RazorDocs Search
API Reference

ForgeTrust.Runnable.Web.Tailwind

ForgeTrust.Runnable.Web.Tailwind

Tailwind CSS integration for Runnable web applications with zero Node.js dependency.

Overview

This package wires the Tailwind standalone CLI into the Runnable web build pipeline so your app can compile generated CSS during builds and run Tailwind in watch mode during development.

Features

  • No Node.js required: Uses the official standalone Tailwind CLI binaries.
  • RID-aware runtime packages: Pulls in the platform-specific runtime package automatically when the package is restored.
  • Build integration: Compiles wwwroot/css/app.css to wwwroot/css/site.gen.css by default.
  • Development watch mode: Starts Tailwind in --watch during development when you register the service.

Usage

Install the package and register Tailwind in your web module:

services.AddTailwind(options =>
{
    options.InputPath = "wwwroot/css/app.css";
    options.OutputPath = "wwwroot/css/site.gen.css";
});

Reference the generated stylesheet from your layout:

<link rel="stylesheet" href="~/css/site.gen.css" asp-append-version="true" />

When OutputPath stays under wwwroot/, the generated file is registered as an ASP.NET Core static web asset on clean builds and publish runs. That means Razor Class Libraries and other package-style consumers can serve the generated CSS without checking site.gen.css into source control first. That registration also stays in place for projects that disable the SDK's default content items and rely on the package to declare the generated web-root asset explicitly.

Keep InputPath and OutputPath pointed at different files. The build target and the development watch service both reject configurations where the two paths resolve to the same file, even if one path uses a normalized relative form such as ./wwwroot/css/../css/app.css.

CI

ForgeTrust.Runnable.Web.Tailwind hooks into the normal dotnet build and dotnet publish pipeline through MSBuild targets, so the default integration does not require a separate npm install or npm run build step in CI.

If you need to suppress the package-driven build temporarily, set TailwindEnabled=false in MSBuild, for example with dotnet build -p:TailwindEnabled=false or a project-level <TailwindEnabled>false</TailwindEnabled> property.

If you want to keep the package-driven build but point it at a different standalone Tailwind executable, set TailwindCliPath to an absolute path or a project-relative file path:

<PropertyGroup>
  <TailwindCliPath>tools/tailwindcss/tailwindcss</TailwindCliPath>
</PropertyGroup>

On Windows, TailwindCliPath can point at the standalone binary directly or at the npm-generated .cmd or .ps1 shim. The package wraps those shims consistently in both build mode and development watch mode, so the same override works in each flow.

Escape hatch (plugin-heavy Tailwind setups)

If your Tailwind configuration depends on npm-only plugins or custom JavaScript tooling, keep your existing Node-based asset pipeline instead of forcing the standalone CLI path.

Disable the package-driven MSBuild integration with TailwindEnabled=false, and either omit services.AddTailwind() or set options.Enabled = false so the development watch service does not start. After that, run your existing npm, pnpm, or yarn Tailwind command as part of your normal frontend build.

If your custom setup still uses the standalone CLI but stores it outside the package runtime layout, prefer TailwindCliPath over editing the imported .targets file directly.

Notes

  • The generated CSS file is intended to be build output and is commonly ignored in source control.
  • Generated CSS outside wwwroot/ still builds locally, but it is not exposed automatically through the static web asset pipeline.
  • The platform-specific ForgeTrust.Runnable.Web.Tailwind.Runtime.* packages are support packages consumed transitively by this package and are not usually installed directly.
  • Tailwind CLI selection follows the current build host, not RuntimeIdentifier, because the standalone CLI runs during the build. Cross-targeted builds still execute the host-compatible binary.
  • Windows Arm64 hosts intentionally use the win-x64 runtime under emulation. There is no ForgeTrust.Runnable.Web.Tailwind.Runtime.win-arm64 package because Tailwind v4.1.18 does not ship a native Windows Arm64 standalone CLI.
Type

TailwindOptions

Configuration options for the Tailwind CSS integration.

Remarks

Use these options with services.AddTailwind(...) to control both build-time compilation and development watch behavior. Defaults:
  • Enabled defaults to true.
  • InputPath defaults to wwwroot/css/app.css.
  • OutputPath defaults to wwwroot/css/site.gen.css.
Paths are resolved relative to the app content root. Common misconfigurations include pointing at a missing input file, using whitespace-only paths, or choosing an output path whose parent directory is not writable.
Property

Enabled

bool Enabled { get; set; }

Gets or sets a value indicating whether Tailwind CSS integration is enabled.

Remarks

Leave this enabled for normal development and build pipelines. Set it to false only when a host intentionally opts out of Tailwind compilation or provides CSS through another mechanism.

Property

InputPath

string InputPath { get; set; }

Gets or sets the path to the input CSS file.

Remarks

Defaults to wwwroot/css/app.css. The value should be a non-empty relative path to a readable .css file under the application content root.

Property

OutputPath

string OutputPath { get; set; }

Gets or sets the path to the output CSS file.

Remarks

Defaults to wwwroot/css/site.gen.css. The value should be a non-empty relative path whose parent directory exists and is writable. Keep the output under wwwroot/ when the generated stylesheet needs to participate in ASP.NET Core static web asset discovery for build and publish output. Avoid pointing this at the same file as InputPath.

Type

TailwindExtensions

Provides extension methods for registering Tailwind CSS services.

Method

AddTailwind

2 overloads
IServiceCollection AddTailwind(this IServiceCollection services)

Adds Tailwind CSS services to the service collection.

Parameters

  • servicesThe service collection.

Returns

The service collection for chaining.

IServiceCollection AddTailwind(this IServiceCollection services, Action<TailwindOptions> configureOptions)

Adds Tailwind CSS services with custom configuration to the service collection.

Parameters

  • servicesThe service collection.
  • configureOptionsAn action to configure the TailwindOptions.

Returns

The service collection for chaining.

Type

TailwindWatchService

A background service that runs the Tailwind CLI in watch mode during development.

Method

ExecuteTailwindProcessAsync

Task<CommandResult> ExecuteTailwindProcessAsync(string fileName, IReadOnlyList<string> args, string workingDirectory, CancellationToken cancellationToken)

Executes the Tailwind CLI process.

Parameters

  • fileNameThe path to the executable.
  • argsThe arguments.
  • workingDirectoryThe working directory.
  • cancellationTokenThe cancellation token.

Returns

The command result returned by the Tailwind CLI process.

Remarks

Internal virtual to allow mocking in unit tests.

Method

GetPathComparison

StringComparison GetPathComparison()

Resolves the path-comparison behavior used when validating Tailwind input/output paths.

Returns

The string-comparison behavior used when evaluating Tailwind input and output paths.

Remarks

The default implementation only assumes case-insensitive paths on Windows so development hosts on case-sensitive volumes are not rejected by a false positive same-file check. Override HostPathsAreCaseInsensitive in tests or specialized hosts that know they should compare paths case-insensitively on another platform.

Method

HostPathsAreCaseInsensitive

bool HostPathsAreCaseInsensitive()

Determines whether the current host should treat filesystem paths as case-insensitive for Tailwind path validation.

Returns

true when the host should conservatively compare input and output paths case-insensitively; otherwise false.

Remarks

The default behavior treats only Windows as case-insensitive. Hosts that run on a known case-insensitive non-Windows volume can override this method to opt into StringComparison.OrdinalIgnoreCase.

Type

TailwindCliManager

Manages the location and execution of the Tailwind CLI binary.

Method

GetTailwindPath

string GetTailwindPath()

Gets the path to the Tailwind CLI binary.

Returns

The absolute path to the tailwindcss executable.

Exceptions

  • FileNotFoundExceptionThrown if the binary cannot be found in runtimes, local directory, or PATH.

Remarks

Resolution proceeds in this order:
  1. RID-specific runtime assets under AppContext.BaseDirectory.
  2. A flat binary next to the application under AppContext.BaseDirectory.
  3. RID-specific runtime assets relative to this assembly, including local development runtime build outputs when running inside this repository.
  4. The system PATH as an escape hatch for custom or Node-managed Tailwind setups, including Windows shell shims such as .cmd and .ps1.
If none of these locations contain a compatible binary, the method throws FileNotFoundException.
Method

BuildInvocation

TailwindCliInvocation BuildInvocation(string tailwindPath, IReadOnlyList<string> tailwindArgs)

Builds the process invocation needed to execute a resolved Tailwind CLI path.

Parameters

  • tailwindPathThe resolved Tailwind CLI path returned by GetTailwindPath.
  • tailwindArgsThe Tailwind CLI arguments to forward to the process.

Returns

A TailwindCliInvocation describing the executable to launch and the full ordered argument list.

Remarks

Windows PATH resolution can return Node-managed shell shims such as .cmd or .ps1. These files cannot be launched reliably with System.Diagnostics.ProcessStartInfo.UseShellExecute disabled, so they are wrapped with cmd.exe or powershell.exe as appropriate.

Method

GetCurrentRid

string GetCurrentRid()

Gets the Runtime Identifier (RID) for the current platform.

Returns

The RID string (e.g., "win-x64", "linux-arm64").

Remarks

Must be kept in sync with the RID logic in the runtime package projects and build/ForgeTrust.Runnable.Web.Tailwind.targets. Unsupported operating systems or architectures return "unknown". Windows Arm64 intentionally maps to win-x64 because Tailwind v4.1.18 does not ship a native Windows Arm64 standalone binary.

Method

ResolveRid

string ResolveRid(OSPlatform osPlatform, Architecture architecture)

Resolves the Tailwind runtime identifier for a specific platform and process architecture.

Parameters

  • osPlatformThe operating system platform to evaluate.
  • architectureThe process architecture to map.

Returns

The Tailwind runtime identifier for the supplied platform/architecture pair.

Remarks

Must be kept in sync with the RID logic in the runtime package projects and build/ForgeTrust.Runnable.Web.Tailwind.targets.

Property

BaseDirectoryOverride

string? BaseDirectoryOverride { get; set; }

Gets or sets a directory to override AppContext.BaseDirectory for testing.

Property

AssemblyDirectoryOverride

string? AssemblyDirectoryOverride { get; set; }

Gets or sets a directory to override the resolved assembly directory for testing isolated fallback lookup.

Property

RidOverride

string? RidOverride { get; set; }

Gets or sets a runtime identifier override for tests that need to exercise non-host RID resolution paths.

Property

IsOSPlatformOverride

Func<OSPlatform, bool>? IsOSPlatformOverride { get; set; }

Gets or sets an operating-system detector override for tests that need deterministic platform simulation.

Property

ProcessArchitectureOverride

Func<Architecture>? ProcessArchitectureOverride { get; set; }

Gets or sets a process-architecture override for tests that need deterministic RID resolution.

Type

TailwindCliInvocation

Represents the concrete process invocation required to launch the resolved Tailwind CLI.

Parameters

  • FileNameThe executable or launcher to start.
  • ArgumentsThe complete ordered argument list to pass to FileName.