name: Release on: release: types: [published] workflow_dispatch: permissions: contents: read env: APP_NAME: tailwindcss-oxide NODE_VERSION: 20 OXIDE_LOCATION: ./crates/node jobs: build: strategy: matrix: include: # Windows - os: windows-latest target: x86_64-pc-windows-msvc - os: windows-latest target: aarch64-pc-windows-msvc # macOS - os: macos-latest target: x86_64-apple-darwin strip: strip -x # Must use -x on macOS. This produces larger results on linux. - os: macos-latest target: aarch64-apple-darwin page-size: 14 strip: strip -x # Must use -x on macOS. This produces larger results on linux. # Android - os: ubuntu-latest target: aarch64-linux-android strip: ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - os: ubuntu-latest target: armv7-linux-androideabi strip: ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip # Linux - os: ubuntu-latest target: x86_64-unknown-linux-gnu strip: strip container: image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - os: ubuntu-latest target: aarch64-unknown-linux-gnu strip: llvm-strip container: image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - os: ubuntu-latest target: armv7-unknown-linux-gnueabihf strip: llvm-strip container: image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig - os: ubuntu-latest target: aarch64-unknown-linux-musl strip: aarch64-linux-musl-strip download: true container: image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine - os: ubuntu-latest target: x86_64-unknown-linux-musl strip: strip download: true container: image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine name: Build ${{ matrix.target }} (oxide) runs-on: ${{ matrix.os }} container: ${{ matrix.container }} timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'pnpm' - name: Install gcc-arm-linux-gnueabihf if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }} run: | sudo apt-get update sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y # Cargo already skips downloading dependencies if they already exist - name: Cache cargo uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} # Cache the `oxide` Rust build - name: Cache oxide build uses: actions/cache@v4 with: path: | ./crates/node/*.node ./crates/node/*.wasm ./crates/node/index.d.ts ./crates/node/index.js ./crates/node/browser.js ./crates/node/tailwindcss-oxide.wasi-browser.js ./crates/node/tailwindcss-oxide.wasi.cjs ./crates/node/wasi-worker-browser.mjs ./crates/node/wasi-worker.mjs key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./crates/**/*') }} - name: Install Node.JS uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Install Rust (Stable) if: ${{ matrix.download }} run: | rustup default stable - name: Setup rust target run: rustup target add ${{ matrix.target }} - name: Install dependencies run: pnpm install --ignore-scripts --filter=!./playgrounds/* - name: Build release run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }} env: RUST_TARGET: ${{ matrix.target }} JEMALLOC_SYS_WITH_LG_PAGE: ${{ matrix.page-size }} - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034 if: ${{ matrix.strip }} run: ${{ matrix.strip }} ${{ env.OXIDE_LOCATION }}/*.node - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: bindings-${{ matrix.target }} path: ${{ env.OXIDE_LOCATION }}/*.node build-freebsd: name: Build x86_64-unknown-freebsd (OXIDE) runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - name: Build FreeBSD uses: cross-platform-actions/action@v0.25.0 env: DEBUG: napi:* RUSTUP_HOME: /usr/local/rustup CARGO_HOME: /usr/local/cargo RUSTUP_IO_THREADS: 1 RUST_TARGET: x86_64-unknown-freebsd with: operating_system: freebsd version: '14.0' memory: 13G cpu_count: 3 environment_variables: 'DEBUG RUSTUP_IO_THREADS' shell: bash run: | sudo pkg install -y -f curl node libnghttp2 npm sudo npm install -g pnpm@9.6.0 --unsafe-perm=true curl -sSf https://static.rust-lang.org/rustup/archive/1.27.1/x86_64-unknown-freebsd/rustup-init --output rustup-init chmod +x rustup-init ./rustup-init -y --profile minimal source "$HOME/.cargo/env" echo "~~~~ rustc --version ~~~~" rustc --version echo "~~~~ node -v ~~~~" node -v echo "~~~~ pnpm --version ~~~~" pnpm --version pnpm install --ignore-scripts --filter=!./playgrounds/* || true pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform strip -x ${{ env.OXIDE_LOCATION }}/*.node ls -la ${{ env.OXIDE_LOCATION }} - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: bindings-x86_64-unknown-freebsd path: ${{ env.OXIDE_LOCATION }}/*.node release: runs-on: macos-14 timeout-minutes: 15 name: Build and release Tailwind CSS permissions: contents: write # for softprops/action-gh-release to create GitHub release # https://docs.npmjs.com/generating-provenance-statements#publishing-packages-with-provenance-via-github-actions id-token: write needs: - build - build-freebsd steps: - uses: actions/checkout@v4 with: fetch-depth: 20 - uses: pnpm/action-setup@v4 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'pnpm' registry-url: 'https://registry.npmjs.org' # Cargo already skips downloading dependencies if they already exist - name: Cache cargo uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} # Cache the `oxide` Rust build - name: Cache oxide build uses: actions/cache@v4 with: path: | ./crates/node/*.node ./crates/node/*.wasm ./crates/node/index.d.ts ./crates/node/index.js ./crates/node/browser.js ./crates/node/tailwindcss-oxide.wasi-browser.js ./crates/node/tailwindcss-oxide.wasi.cjs ./crates/node/wasi-worker-browser.mjs ./crates/node/wasi-worker.mjs key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./crates/**/*') }} - name: Setup WASM target run: rustup target add wasm32-wasip1-threads - name: Install dependencies run: pnpm --filter=!./playgrounds/* install - name: Download artifacts uses: actions/download-artifact@v4 with: path: ${{ env.OXIDE_LOCATION }} - name: Move artifacts run: | cd ${{ env.OXIDE_LOCATION }} cp bindings-x86_64-pc-windows-msvc/* ./npm/win32-x64-msvc/ cp bindings-aarch64-pc-windows-msvc/* ./npm/win32-arm64-msvc/ cp bindings-x86_64-apple-darwin/* ./npm/darwin-x64/ cp bindings-aarch64-apple-darwin/* ./npm/darwin-arm64/ cp bindings-aarch64-linux-android/* ./npm/android-arm64/ cp bindings-armv7-linux-androideabi/* ./npm/android-arm-eabi/ cp bindings-aarch64-unknown-linux-gnu/* ./npm/linux-arm64-gnu/ cp bindings-aarch64-unknown-linux-musl/* ./npm/linux-arm64-musl/ cp bindings-armv7-unknown-linux-gnueabihf/* ./npm/linux-arm-gnueabihf/ cp bindings-x86_64-unknown-linux-gnu/* ./npm/linux-x64-gnu/ cp bindings-x86_64-unknown-linux-musl/* ./npm/linux-x64-musl/ cp bindings-x86_64-unknown-freebsd/* ./npm/freebsd-x64/ - name: Build Tailwind CSS run: pnpm run build env: FEATURES_ENV: stable - name: Run pre-publish optimizations scripts run: node ./scripts/pre-publish-optimizations.mjs - name: Lock pre-release versions run: node ./scripts/lock-pre-release-versions.mjs - name: Calculate environment variables run: | echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV echo "TAILWINDCSS_VERSION=$(node -e 'console.log(require(`./packages/tailwindcss/package.json`).version);')" >> $GITHUB_ENV - name: Publish run: | pnpm --recursive --filter="!@tailwindcss/oxide-wasm32-wasi" publish --tag ${{ env.RELEASE_CHANNEL }} --no-git-checks # The wasm package needs a special npm config that isn't read when pnpm --recursive is used pushd crates/node/npm/wasm32-wasi; pnpm publish --tag ${{ env.RELEASE_CHANNEL }} --no-git-checks; popd; env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Trigger Tailwind Play update if: env.RELEASE_CHANNEL == 'latest' uses: actions/github-script@v7 with: github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} script: | await github.rest.actions.createWorkflowDispatch({ owner: 'tailwindlabs', repo: 'play.tailwindcss.com', ref: 'master', workflow_id: 'upgrade-tailwindcss.yml' })