ForgeTailwind

Tailwind CSS binary wrapper for Forge Kernel. Provides a lightweight alternative to npm-based Tailwind setup with automatic binary download, platform support, and HMR capabilities.

Overview

ForgeTailwind is a CLI-only module that provides a PHP wrapper around the Tailwind CSS standalone binary. It allows you to use Tailwind CSS without npm, node_modules, or Node.js dependencies, making it a lightweight alternative for those who prefer to avoid the npm ecosystem.

Key Features

No npm/node_modules required
Automatic binary download and setup
Multiple platform support
CLI-only module (no runtime dependencies)
Build and watch commands
HMR (Hot Module Replacement) support
Minification support
Lightweight alternative to npm setup

What ForgeTailwind Provides

  • Tailwind CSS Binary Wrapper: PHP CLI wrapper around the standalone Tailwind CSS binary
  • Automatic Binary Management: Downloads and sets up the Tailwind binary automatically
  • Build Command: Build Tailwind CSS from source files with minification
  • Watch Command: Watch for file changes and automatically rebuild
  • Platform Support: Supports macOS, Windows, and Linux (multiple architectures)
  • HMR Support: Hot Module Replacement for development workflow
  • No Dependencies: No npm, node_modules, or Node.js required

Optional Alternative: ForgeTailwind is an optional alternative to the standard npm-based Tailwind setup. You can still use Tailwind CSS the normal way with npm and Node.js if you prefer. This module is provided as a personal preference for those who want to avoid npm/node_modules baggage.

CLI-Only Module: ForgeTailwind is a CLI-only module (isCli: true, order: 99), providing Tailwind CSS build capabilities without any runtime dependencies. It's a generic module that can be installed as needed.

Architecture & Design Philosophy

ForgeTailwind uses a standalone binary approach, wrapping the official Tailwind CSS standalone binary in PHP CLI commands. This eliminates the need for npm, node_modules, or Node.js while still providing full Tailwind CSS functionality.

Standalone Binary Approach

Instead of using npm to install Tailwind CSS, ForgeTailwind uses the official Tailwind CSS standalone binary:

  • Single binary file (no dependencies)
  • Downloaded from GitHub releases
  • Stored in storage/bin/
  • Platform-specific binaries
  • Automatic download and setup

CLI Wrapper

PHP CLI commands wrap the Tailwind binary:

  • Build command: Compiles Tailwind CSS from source
  • Watch command: Watches for changes and rebuilds automatically
  • Automatic binary management
  • Platform detection and binary selection

Configuration File Support

The Tailwind CSS binary reads tailwind.config.js just like the npm version:

  • Full Configuration Support: All Tailwind configuration options are supported
  • Plugin Support: Plugins defined in tailwind.config.js are fully supported
  • Content Paths: Content paths in config are respected
  • Theme Customization: Theme extensions and overrides work as expected
  • Same as npm: The binary behaves identically to npm-based Tailwind CSS

Example tailwind.config.js:

module.exports = {
    content: [
        '/app/resources/views/**/*.php',
        '/modules/**/src/resources/views/**/*.php',
    ],
    theme: {
        extend: {},
    },
    plugins: [
        require("@tailwindcss/forms"),
        require("@tailwindcss/typography")
    ],
};

Note: The standalone binary reads and processes tailwind.config.js exactly like the npm version. All plugins, theme customizations, and configuration options work identically.

HMR Integration

JavaScript-based Hot Module Replacement:

  • Automatic CSS reloading on file changes
  • Form state preservation
  • Development-only feature
  • Localhost-only for security

Installation

ForgeTailwind can be installed via ForgePackageManager. It's a CLI-only module with no runtime dependencies.

Install via ForgePackageManager

php forge.php module:package-install --module=forge-tailwind

No Dependencies Required

ForgeTailwind requires:

  • PHP 8.3+ (for CLI commands)
  • curl (for binary download)
  • No npm, Node.js, or node_modules required

Binary Download

The Tailwind CSS binary is automatically downloaded on first use. No manual setup is required.

Why ForgeTailwind?

ForgeTailwind was created as a personal preference to avoid npm and node_modules baggage. It's an optional alternative that provides the same Tailwind CSS functionality without requiring Node.js or npm.

Personal Preference

This module was created to avoid:

  • npm dependency management
  • node_modules directory bloat
  • Node.js installation requirements
  • package.json and package-lock.json files

Lightweight Alternative

ForgeTailwind provides:

  • Single binary file (no dependencies)
  • No npm/node_modules required
  • No Node.js required
  • Pure PHP CLI wrapper
  • Minimal setup overhead

Optional Usage

Important points:

  • Not Required: You can still use npm-based Tailwind setup
  • Optional Alternative: Use ForgeTailwind if you prefer a lightweight approach
  • Inspiration: For those who want a similar approach
  • Standard Way: npm-based setup is still the standard and recommended approach

Note: This module is provided as a personal preference. Users are free to use Tailwind CSS the normal way with npm and Node.js. ForgeTailwind is just an alternative option for those who want to avoid npm dependencies.

CLI Commands

ForgeTailwind provides two CLI commands for building and watching Tailwind CSS.

tailwind:build

Builds Tailwind CSS from source files:

php forge.php tailwind:build [--input=CSS_PATH] [--output=CSS_PATH]

Options

  • --input: Input CSS file path (default: app/resources/assets/css/tailwind.css)
  • --output: Output CSS file path (default: public/assets/css/app.css)

Features

  • Automatic binary download if missing
  • Minification support (--minify flag)
  • Custom input/output paths
  • Error handling and reporting

Examples

# Build with default paths
php forge.php tailwind:build

# Build with custom paths
php forge.php tailwind:build --input=app/resources/css/tailwind.css --output=public/assets/css/app.css

tailwind:watch

Watches for file changes and automatically rebuilds Tailwind CSS:

php forge.php tailwind:watch [--input=CSS_PATH] [--output=CSS_PATH] [--platform=PLATFORM]

Options

  • --input: Input CSS file path (default: app/resources/assets/css/tailwind.css)
  • --output: Output CSS file path (default: public/assets/css/app.css)
  • --platform: Tailwind binary platform (default: macos-arm64)

Supported Platforms

  • macos-arm64 (default)
  • macos-x64
  • windows-x64
  • linux-arm64
  • linux-arm64-musl
  • linux-x64
  • linux-x64-musl

Examples

# Watch with default settings
php forge.php tailwind:watch

# Watch with custom paths
php forge.php tailwind:watch --input=app/resources/css/tailwind.css --output=public/assets/css/app.css

# Watch with specific platform
php forge.php tailwind:watch --platform=linux-x64

Note: The watch command runs continuously until stopped (Ctrl-C). It automatically rebuilds Tailwind CSS whenever source files change.

Binary Management

ForgeTailwind automatically manages the Tailwind CSS binary, downloading it from GitHub releases when needed.

Automatic Download

The binary is automatically downloaded on first use:

  1. Check if binary exists in storage/bin/
  2. If missing, download from GitHub releases
  3. Set executable permissions (Unix systems)
  4. Store binary for future use

Binary Storage

Binaries are stored in:

storage/bin/tailwindcss        # Unix systems
storage/bin/tailwindcss.exe    # Windows

Download Source

Binaries are downloaded from official Tailwind CSS GitHub releases:

// Example download URL
https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-arm64

Binary Caching

The binary is cached after first download:

  • Only downloads if binary doesn't exist
  • Reuses existing binary for subsequent builds
  • Platform-specific binaries are stored separately

Executable Permissions

On Unix systems, the binary is automatically made executable:

exec("chmod +x " . escapeshellarg($tempBin), $out, $ret);

Platform Support

ForgeTailwind supports multiple platforms with platform-specific binaries.

Supported Platforms

Platform Binary Name
macOS ARM64 tailwindcss-macos-arm64
macOS x64 tailwindcss-macos-x64
Windows x64 tailwindcss-windows-x64.exe
Linux ARM64 tailwindcss-linux-arm64
Linux ARM64 (musl) tailwindcss-linux-arm64-musl
Linux x64 tailwindcss-linux-x64
Linux x64 (musl) tailwindcss-linux-x64-musl

Platform Selection

The platform is selected via the --platform argument in the watch command:

php forge.php tailwind:watch --platform=linux-x64

Default Platform

The default platform is macos-arm64. For the build command, it automatically detects the platform based on the system.

HMR (Hot Module Replacement)

ForgeTailwind includes JavaScript-based Hot Module Replacement for automatic CSS reloading during development.

What is HMR?

Hot Module Replacement automatically reloads CSS when Tailwind files are rebuilt, without requiring a full page refresh. This improves the development workflow by preserving form state and scroll position.

Features

  • Automatic CSS Reloading: Detects when CSS file changes and reloads it
  • Form State Preservation: Preserves form input values during CSS reload
  • No Page Refresh: Only CSS is reloaded, not the entire page
  • Development Only: Only active in development environments
  • Localhost Only: Only works on localhost/127.0.0.1 for security

Enabling HMR

HMR is enabled via the APP_HMR environment variable:

# .env
APP_HMR=true

Using HMR in Views

Use the forgetailwind() helper function in your views:

<?php echo forgetailwind(); ?>

This will output the HMR script tag if HMR is enabled and conditions are met.

HMR Conditions

HMR script is only included when:

  • APP_HMR is true
  • Environment is not production or staging
  • Host is localhost or 127.0.0.1

How HMR Works

The HMR JavaScript:

  1. Polls the CSS file for changes (every 1.3 seconds)
  2. Detects file modification time or hash changes
  3. Preserves form state before reload
  4. Reloads the CSS file with a cache-busting query parameter
  5. Restores form state after reload

Security: HMR only works on localhost/127.0.0.1 to prevent potential security issues in production environments.

Helper Functions

ForgeTailwind provides a helper function for HMR integration.

forgetailwind()

Returns the HMR script tag if HMR is enabled and conditions are met:

function forgetailwind(): string
{
    $isHmrEnabled = env("APP_HMR", false);
    $env = env("APP_ENV");
    $host = request_host();

    if (!$isHmrEnabled) {
        return "";
    }

    if (in_array($env, ["production", "staging"], true)) {
        return "";
    }

    if (
        !str_starts_with($host, "localhost") &&
        !str_starts_with($host, "127.0.0.1")
    ) {
        return "";
    }

    return '<script defer src="/assets/modules/forge-tailwind/js/forge-tailwind-hmr.js"></script>';
}

Usage in Views

<!DOCTYPE html>
<html>
<head>
    <title>My Page</title>
    <link rel="stylesheet" href="/assets/css/app.css">
    <?php echo forgetailwind(); ?>
</head>
<body>
    <!-- Your content -->
</body>
</html>

Return Value

Returns:

  • HMR script tag if all conditions are met
  • Empty string if HMR is disabled or conditions are not met

Configuration

ForgeTailwind uses the standard tailwind.config.js file, which is read by the Tailwind binary just like with npm.

Configuration File

Create a tailwind.config.js file in your project root:

module.exports = {
    content: [
        '/app/resources/views/**/*.php',
        '/app/resources/assets/**/*.js',
        '/modules/**/src/resources/views/**/*.php',
    ],
    theme: {
        extend: {},
    },
    plugins: [
        require("@tailwindcss/forms"),
        require("@tailwindcss/typography")
    ],
};

Plugin Support

Plugins are fully supported. The binary reads and processes plugins from tailwind.config.js:

  • Plugins must be installed via npm (for the require() to work)
  • The binary processes plugins the same way as npm-based Tailwind
  • All official Tailwind plugins work
  • Custom plugins are supported

Note: While ForgeTailwind avoids npm for the Tailwind binary itself, you may still need npm to install plugin packages if you use plugins. The binary reads the config file and processes plugins, but the plugin packages themselves need to be available via require().

Content Paths

Define which files Tailwind should scan for classes:

content: [
    '/app/resources/views/**/*.php',
    '/app/resources/assets/**/*.js',
    '/modules/**/src/resources/views/**/*.php',
]

Theme Customization

Customize the Tailwind theme just like with npm:

theme: {
    extend: {
        colors: {
            'brand': '#1da1f2',
        },
    },
}

Default File Paths

ForgeTailwind uses default file paths that can be customized via command arguments.

Default Input Path

app/resources/assets/css/tailwind.css

This is your source Tailwind CSS file with @tailwind directives.

Default Output Path

public/assets/css/app.css

This is the compiled CSS file that should be included in your HTML.

Customizing Paths

You can customize both paths using command arguments:

php forge.php tailwind:build \
    --input=app/resources/css/custom.css \
    --output=public/css/custom.css

Example Tailwind Source File

/* app/resources/assets/css/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Your custom CSS here */

Usage Examples

Basic Build

# Build Tailwind CSS with default paths
php forge.php tailwind:build

Build with Custom Paths

php forge.php tailwind:build \
    --input=app/resources/css/tailwind.css \
    --output=public/assets/css/app.css

Watch Mode for Development

# Watch for changes and rebuild automatically
php forge.php tailwind:watch

# Watch with custom paths
php forge.php tailwind:watch \
    --input=app/resources/css/tailwind.css \
    --output=public/assets/css/app.css

Watch with Platform Selection

# Watch on Linux
php forge.php tailwind:watch --platform=linux-x64

# Watch on Windows
php forge.php tailwind:watch --platform=windows-x64

HMR Integration

Enable HMR in your .env:

APP_HMR=true
APP_ENV=local

Include HMR script in your layout:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="/assets/css/app.css">
    <?php echo forgetailwind(); ?>
</head>
<body>
    <!-- Your content -->
</body>
</html>

Development Workflow

  1. Start watch mode: php forge.php tailwind:watch
  2. Enable HMR: Set APP_HMR=true in .env
  3. Include HMR script in your layout
  4. Edit your HTML/Templates with Tailwind classes
  5. CSS automatically rebuilds and reloads in browser

Comparison: ForgeTailwind vs npm

ForgeTailwind and npm-based Tailwind setup each have their advantages. Choose the approach that best fits your needs.

Feature ForgeTailwind npm-based
Dependencies Single binary, no npm npm, Node.js, node_modules
Setup Automatic binary download npm install, package.json
File Size Small (single binary) Large (node_modules)
Tailwind Plugins Full support (reads tailwind.config.js) Full plugin ecosystem
Configuration Full (tailwind.config.js, same as npm) Full (tailwind.config.js)
HMR Built-in JavaScript HMR Vite/Webpack HMR
Use Case Lightweight, simple projects Full Tailwind ecosystem

When to Use ForgeTailwind

  • You want to avoid npm/node_modules
  • You prefer a lightweight setup
  • You want a simple, binary-based approach
  • You want full Tailwind configuration and plugins without npm
  • You're building a simple to medium project

When to Use npm-based Setup

  • You're already using npm/Node.js in your project
  • You're using a build tool (Vite, Webpack, etc.)
  • You prefer the standard npm-based approach
  • You need integration with other npm-based tools
  • You're building a complex project with multiple npm dependencies

Recommendation: For most projects, the standard npm-based Tailwind setup is recommended. ForgeTailwind is best suited for those who specifically want to avoid npm dependencies or prefer a lightweight alternative.

Best Practices

Development Workflow

  • Use tailwind:watch during development
  • Enable HMR for automatic CSS reloading
  • Keep watch process running while developing
  • Use build command for production builds

Production Builds

  • Use tailwind:build for production
  • Build is automatically minified
  • Disable HMR in production (it's disabled by default)
  • Include built CSS file in your HTML

Binary Management

  • Binary is automatically downloaded when needed
  • Binary is cached in storage/bin/
  • Delete binary to force re-download if needed
  • Platform-specific binaries are stored separately

HMR Best Practices

  • Only enable HMR in development
  • HMR only works on localhost (security)
  • Use forgetailwind() helper in layouts
  • Disable HMR in production/staging environments

File Organization

  • Keep source Tailwind file in app/resources/assets/css/
  • Output compiled CSS to public/assets/css/
  • Use consistent naming conventions
  • Add compiled CSS to .gitignore if desired

Platform Selection

  • Use appropriate platform for your system
  • Default (macos-arm64) works for most macOS users
  • Specify platform explicitly for Linux/Windows
  • Use musl variants for Alpine Linux

Alternative Approaches

  • Consider npm-based setup for full Tailwind features
  • Use ForgeTailwind for lightweight projects
  • Both approaches can coexist in different projects
  • Choose based on your project needs