diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 42645aa49..63f79fa10 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -50,7 +50,7 @@ If you open a pull request for a new feature, we're likely to close it not becau
## Coding standards
-Our code formatting rules are defined in the `"prettier"` section of [package.json](https://github.com/tailwindcss/tailwindcss/blob/main/package.json). You can check your code against these standards by running:
+Our code formatting rules are defined in the `"prettier"` section of [package.json](https://github.com/tailwindlabs/tailwindcss/blob/main/package.json). You can check your code against these standards by running:
```sh
pnpm run lint
@@ -76,7 +76,7 @@ To run the integration tests, use:
pnpm build && pnpm test:integrations
```
-Additionally, some features require testing in browsers (i.e to ensure CSS variable resolution works as expected). These can be run via:
+Additionally, some features require testing in browsers (i.e. to ensure CSS variable resolution works as expected). These can be run via:
```sh
pnpm build && pnpm test:ui
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index ee9d3f9ab..aa0793aa3 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -8,7 +8,7 @@ It's never a fun experience to have your pull request declined after investing a
For more info, check out the contributing guide:
-https://github.com/tailwindcss/tailwindcss/blob/main/.github/CONTRIBUTING.md
+https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md
-->
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b0c8f483e..5ae59e80f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,12 +8,18 @@ on:
permissions:
contents: read
+env:
+ NODE_VERSION: 24
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
tests:
strategy:
fail-fast: false
matrix:
- node-version: [20]
runner:
- name: Windows
os: windows-latest
@@ -21,12 +27,14 @@ jobs:
- name: Linux
os: namespace-profile-default
+ # Playwright 1.62+ dropped WebKit support for macOS 14, and hangs
+ # instead of failing when launching WebKit on a macos-14 runner.
- name: macOS
- os: macos-14
+ os: macos-15
# Exclude windows and macos from being built on feature branches
run-all:
- - ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.body, '[ci-all]') }}
+ - ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.body, '[ci-all]') || github.event.pull_request.user.login == 'depfu[bot]' }}
exclude:
- run-all: false
runner:
@@ -41,21 +49,21 @@ jobs:
name: ${{ matrix.runner.name }}
steps:
- - uses: actions/checkout@v4
- - uses: pnpm/action-setup@v4
-
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
- node-version: ${{ matrix.node-version }}
- cache: 'pnpm'
+ persist-credentials: false
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+
+ - name: Use Node.js ${{ env.NODE_VERSION }}
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version: ${{ env.NODE_VERSION }}
# Cargo already skips downloading dependencies if they already exist
- name: Cache cargo
- uses: actions/cache@v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
- ~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
@@ -64,7 +72,7 @@ jobs:
# Cache the `oxide` Rust build
- name: Cache oxide build
- uses: actions/cache@v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
./crates/node/*.node
@@ -82,7 +90,7 @@ jobs:
run: rustup target add wasm32-wasip1-threads
- name: Install dependencies
- run: pnpm install
+ run: pnpm install --frozen-lockfile
- name: Build
run: pnpm run build
@@ -104,9 +112,13 @@ jobs:
- name: Run Playwright tests
run: npm run test:ui
+ notify:
+ if: ${{ always() && github.ref == 'refs/heads/main' && needs.tests.result == 'failure' }}
+ needs: tests
+ runs-on: ubuntu-latest
+ steps:
- name: Notify Discord
- if: failure() && github.ref == 'refs/heads/main'
- uses: discord-actions/message@v2
+ uses: discord-actions/message@5c7149c81a83146e5d01f142be1bf87a61831c4d # v2
with:
webhookUrl: ${{ secrets.DISCORD_WEBHOOK_URL }}
- message: 'The [most recent build](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `main` branch has failed.'
+ message: 'The [most recent ${{ github.workflow }} workflow](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `main` branch has failed.'
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 0148dd983..457c38424 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -8,13 +8,18 @@ on:
permissions:
contents: read
+env:
+ NODE_VERSION: 24
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
tests:
strategy:
fail-fast: false
matrix:
- node-version: [20]
-
runner:
- name: Windows
os: windows-latest
@@ -50,21 +55,25 @@ jobs:
name: ${{ matrix.runner.name }} / ${{ matrix.integration }}
steps:
- - uses: actions/checkout@v4
- - uses: pnpm/action-setup@v4
-
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
- node-version: ${{ matrix.node-version }}
- cache: 'pnpm'
+ persist-credentials: false
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+
+ - run: |
+ git config --global user.name "github-actions[bot]"
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
+
+ - name: Use Node.js ${{ env.NODE_VERSION }}
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version: ${{ env.NODE_VERSION }}
# Cargo already skips downloading dependencies if they already exist
- name: Cache cargo
- uses: actions/cache@v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
- ~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
@@ -73,7 +82,7 @@ jobs:
# Cache the `oxide` Rust build
- name: Cache oxide build
- uses: actions/cache@v4
+ uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
./crates/node/*.node
@@ -99,24 +108,18 @@ jobs:
CARGO_PROFILE_RELEASE_LTO: 'off'
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: 'lld-link'
- - name: Test ${{ matrix.integration }} 1/3
- run: pnpm run test:integrations ./integrations/${{ matrix.integration }} --shard 1/3
- env:
- GITHUB_WORKSPACE: ${{ github.workspace }}
-
- - name: Test ${{ matrix.integration }} 2/3
- run: pnpm run test:integrations ./integrations/${{ matrix.integration }} --shard 2/3
- env:
- GITHUB_WORKSPACE: ${{ github.workspace }}
-
- - name: Test ${{ matrix.integration }} 3/3
- run: pnpm run test:integrations ./integrations/${{ matrix.integration }} --shard 3/3
+ - name: Test ${{ matrix.integration }}
+ run: pnpm run test:integrations ./integrations/${{ matrix.integration }}
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
+ notify:
+ if: ${{ always() && github.ref == 'refs/heads/main' && needs.tests.result == 'failure' }}
+ needs: tests
+ runs-on: ubuntu-latest
+ steps:
- name: Notify Discord
- if: failure() && github.ref == 'refs/heads/main'
- uses: discord-actions/message@v2
+ uses: discord-actions/message@5c7149c81a83146e5d01f142be1bf87a61831c4d # v2
with:
webhookUrl: ${{ secrets.DISCORD_WEBHOOK_URL }}
- message: 'The [most recent build](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `main` branch has failed.'
+ message: 'The [most recent ${{ github.workflow }} workflow](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `main` branch has failed.'
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
index be1050b03..24e829afd 100644
--- a/.github/workflows/prepare-release.yml
+++ b/.github/workflows/prepare-release.yml
@@ -2,18 +2,29 @@ name: Prepare Release
on:
workflow_dispatch:
+ inputs:
+ dry_run:
+ description: Skip creating the draft GitHub release
+ required: false
+ default: true
+ type: boolean
push:
tags:
- 'v*'
env:
APP_NAME: tailwindcss-oxide
- NODE_VERSION: 20
+ NODE_VERSION: 24
+ PNPM_VERSION: '11.9.0'
OXIDE_LOCATION: ./crates/node
permissions:
contents: read
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
build:
strategy:
@@ -43,44 +54,40 @@ jobs:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
strip: strip
- container:
- image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
+ build-flags: --use-napi-cross
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
- strip: llvm-strip
- container:
- image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
+ strip: aarch64-linux-gnu-strip
+ build-flags: --use-napi-cross
- os: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
- strip: llvm-strip
- container:
- image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig
+ strip: arm-linux-gnueabihf-strip
+ build-flags: --use-napi-cross
- 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
+ strip-zig: true
+ build-flags: -x
- 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
+ build-flags: -x
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
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ persist-credentials: false
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+ with:
+ version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
- cache: 'pnpm'
+ package-manager-cache: false
- name: Install gcc-arm-linux-gnueabihf
if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
@@ -88,62 +95,56 @@ jobs:
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 }}
+ - name: Install binutils-aarch64-linux-gnu
+ if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
run: |
- rustup default stable
+ sudo apt-get update
+ sudo apt-get install binutils-aarch64-linux-gnu -y
+
+ - uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2
+ if: ${{ contains(matrix.target, 'musl') }}
+ with:
+ version: 0.14.1
+ use-cache: false
+
+ - name: Install cargo-zigbuild
+ uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 # v2
+ if: ${{ contains(matrix.target, 'musl') }}
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ with:
+ tool: cargo-zigbuild
- name: Setup rust target
run: rustup target add ${{ matrix.target }}
- name: Install dependencies
- run: pnpm install --ignore-scripts --filter=!./playgrounds/*
+ run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/*
- name: Build release
- run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }}
+ run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }} ${{ matrix.build-flags }}
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
+ if: ${{ matrix.strip || matrix.strip-zig }}
+ env:
+ STRIP_COMMAND: ${{ matrix.strip }}
+ STRIP_ZIG: ${{ matrix.strip-zig }}
+ run: |
+ if [ "$STRIP_ZIG" = "true" ]; then
+ for file in ${{ env.OXIDE_LOCATION }}/*.node; do
+ zig objcopy --strip-all "$file" "$file.stripped"
+ mv "$file.stripped" "$file"
+ done
+ exit 0
+ fi
+
+ eval "$STRIP_COMMAND ${{ env.OXIDE_LOCATION }}/*.node"
- name: Upload artifacts
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: bindings-${{ matrix.target }}
path: ${{ env.OXIDE_LOCATION }}/*.node
@@ -153,9 +154,11 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ persist-credentials: false
- name: Build FreeBSD
- uses: cross-platform-actions/action@v0.25.0
+ uses: cross-platform-actions/action@cdc9ee69ef84a5f2e59c9058335d9c57bcb4ac86 # v0.25.0
env:
DEBUG: napi:*
RUSTUP_HOME: /usr/local/rustup
@@ -171,12 +174,12 @@ jobs:
shell: bash
run: |
sudo pkg install -y -f curl node libnghttp2 npm
- sudo npm install -g pnpm@9.6.0 --unsafe-perm=true
+ sudo npm install -g pnpm@${{ env.PNPM_VERSION }} --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"
- pnpm install --ignore-scripts --filter=!./playgrounds/* || true
+ pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/* || true
echo "~~~~ rustc --version ~~~~"
rustc --version
echo "~~~~ node -v ~~~~"
@@ -187,7 +190,7 @@ jobs:
strip -x ${{ env.OXIDE_LOCATION }}/*.node
ls -la ${{ env.OXIDE_LOCATION }}
- name: Upload artifacts
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: bindings-x86_64-unknown-freebsd
path: ${{ env.OXIDE_LOCATION }}/*.node
@@ -198,18 +201,17 @@ jobs:
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
+ contents: write # Required for creating releases
needs:
- build
- build-freebsd
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 20
+ persist-credentials: false
- run: git fetch --tags -f
@@ -218,51 +220,25 @@ jobs:
run: |
echo "TAG_NAME=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- - uses: pnpm/action-setup@v4
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+ with:
+ version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
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/**/*') }}
+ package-manager-cache: false
- name: Setup WASM target
run: rustup target add wasm32-wasip1-threads
- name: Install dependencies
- run: pnpm --filter=!./playgrounds/* install
+ run: pnpm --filter=!./playgrounds/* install --frozen-lockfile
- name: Download artifacts
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
path: ${{ env.OXIDE_LOCATION }}
@@ -301,30 +277,31 @@ jobs:
echo "EOF" >> $GITHUB_ENV
- name: Upload standalone artifacts
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: tailwindcss-standalone
path: packages/@tailwindcss-standalone/dist/
- name: Upload npm package tarballs
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: npm-package-tarballs
path: dist/*.tgz
- name: Prepare GitHub Release
- uses: softprops/action-gh-release@v2
- with:
- draft: true
- tag_name: ${{ env.TAG_NAME }}
- body: |
- ${{ env.RELEASE_NOTES }}
- files: |
- packages/@tailwindcss-standalone/dist/sha256sums.txt
- packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64
- packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64-musl
- packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64
- packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64-musl
- packages/@tailwindcss-standalone/dist/tailwindcss-macos-arm64
- packages/@tailwindcss-standalone/dist/tailwindcss-macos-x64
- packages/@tailwindcss-standalone/dist/tailwindcss-windows-x64.exe
+ if: ${{ !inputs.dry_run }}
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh release create "${TAG_NAME}" \
+ --draft \
+ --title "${TAG_NAME}" \
+ --notes "${RELEASE_NOTES}" \
+ packages/@tailwindcss-standalone/dist/sha256sums.txt \
+ packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64 \
+ packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64-musl \
+ packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64 \
+ packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64-musl \
+ packages/@tailwindcss-standalone/dist/tailwindcss-macos-arm64 \
+ packages/@tailwindcss-standalone/dist/tailwindcss-macos-x64 \
+ packages/@tailwindcss-standalone/dist/tailwindcss-windows-x64.exe
diff --git a/.github/workflows/release-insiders.yml b/.github/workflows/release-insiders.yml
deleted file mode 100644
index 53478a227..000000000
--- a/.github/workflows/release-insiders.yml
+++ /dev/null
@@ -1,318 +0,0 @@
-name: Release Insiders
-
-on:
- push:
- branches: [main]
-
-permissions:
- contents: read
-
-env:
- APP_NAME: tailwindcss-oxide
- NODE_VERSION: 20
- OXIDE_LOCATION: ./crates/node
- RELEASE_CHANNEL: insiders
-
-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 insiders
-
- 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
-
- - name: Resolve version
- id: vars
- run: |
- echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
-
- - 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: 'Version based on commit: 0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }}'
- run: pnpm run version-packages 0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }}
-
- - name: Build Tailwind CSS
- run: pnpm run build
-
- - 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: Upload npm package tarballs
- uses: actions/upload-artifact@v4
- with:
- name: npm-package-tarballs
- path: dist/*.tgz
-
- - 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
- uses: actions/github-script@v7
- with:
- github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }}
- script: |
- await github.rest.actions.createWorkflowDispatch({
- owner: 'tailwindlabs',
- repo: 'upgrades',
- ref: 'main',
- workflow_id: 'upgrade-tailwindcss.yml'
- })
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8b27773b3..2c957d3af 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,18 +1,34 @@
name: Release
on:
+ push:
+ branches: [main]
release:
types: [published]
workflow_dispatch:
+ inputs:
+ channel:
+ description: Release channel to publish
+ required: true
+ default: insiders
+ type: choice
+ options:
+ - insiders
+ - release
permissions:
contents: read
env:
APP_NAME: tailwindcss-oxide
- NODE_VERSION: 20
+ NODE_VERSION: 24
+ PNPM_VERSION: '11.9.0'
OXIDE_LOCATION: ./crates/node
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
build:
strategy:
@@ -42,44 +58,40 @@ jobs:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
strip: strip
- container:
- image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
+ build-flags: --use-napi-cross
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
- strip: llvm-strip
- container:
- image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
+ strip: aarch64-linux-gnu-strip
+ build-flags: --use-napi-cross
- os: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
- strip: llvm-strip
- container:
- image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig
+ strip: arm-linux-gnueabihf-strip
+ build-flags: --use-napi-cross
- 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
+ strip-zig: true
+ build-flags: -x
- 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
+ build-flags: -x
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
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ persist-credentials: false
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+ with:
+ version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
- cache: 'pnpm'
+ package-manager-cache: false
- name: Install gcc-arm-linux-gnueabihf
if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
@@ -87,62 +99,56 @@ jobs:
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 }}
+ - name: Install binutils-aarch64-linux-gnu
+ if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
run: |
- rustup default stable
+ sudo apt-get update
+ sudo apt-get install binutils-aarch64-linux-gnu -y
+
+ - uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2
+ if: ${{ contains(matrix.target, 'musl') }}
+ with:
+ version: 0.14.1
+ use-cache: false
+
+ - name: Install cargo-zigbuild
+ uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 # v2
+ if: ${{ contains(matrix.target, 'musl') }}
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ with:
+ tool: cargo-zigbuild
- name: Setup rust target
run: rustup target add ${{ matrix.target }}
- name: Install dependencies
- run: pnpm install --ignore-scripts --filter=!./playgrounds/*
+ run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/*
- name: Build release
- run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }}
+ run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }} ${{ matrix.build-flags }}
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
+ if: ${{ matrix.strip || matrix.strip-zig }}
+ env:
+ STRIP_COMMAND: ${{ matrix.strip }}
+ STRIP_ZIG: ${{ matrix.strip-zig }}
+ run: |
+ if [ "$STRIP_ZIG" = "true" ]; then
+ for file in ${{ env.OXIDE_LOCATION }}/*.node; do
+ zig objcopy --strip-all "$file" "$file.stripped"
+ mv "$file.stripped" "$file"
+ done
+ exit 0
+ fi
+
+ eval "$STRIP_COMMAND ${{ env.OXIDE_LOCATION }}/*.node"
- name: Upload artifacts
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: bindings-${{ matrix.target }}
path: ${{ env.OXIDE_LOCATION }}/*.node
@@ -152,9 +158,11 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ persist-credentials: false
- name: Build FreeBSD
- uses: cross-platform-actions/action@v0.25.0
+ uses: cross-platform-actions/action@cdc9ee69ef84a5f2e59c9058335d9c57bcb4ac86 # v0.25.0
env:
DEBUG: napi:*
RUSTUP_HOME: /usr/local/rustup
@@ -170,7 +178,7 @@ jobs:
shell: bash
run: |
sudo pkg install -y -f curl node libnghttp2 npm
- sudo npm install -g pnpm@9.6.0 --unsafe-perm=true
+ sudo npm install -g pnpm@${{ env.PNPM_VERSION }} --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
@@ -181,12 +189,12 @@ jobs:
node -v
echo "~~~~ pnpm --version ~~~~"
pnpm --version
- pnpm install --ignore-scripts --filter=!./playgrounds/* || true
+ pnpm install --ignore-scripts --frozen-lockfile --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
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: bindings-x86_64-unknown-freebsd
path: ${{ env.OXIDE_LOCATION }}/*.node
@@ -194,10 +202,10 @@ jobs:
release:
runs-on: macos-14
timeout-minutes: 15
- name: Build and release Tailwind CSS
+ name: Build and publish Tailwind CSS
permissions:
- contents: write # for softprops/action-gh-release to create GitHub release
+ contents: read
# https://docs.npmjs.com/generating-provenance-statements#publishing-packages-with-provenance-via-github-actions
id-token: write
@@ -206,55 +214,51 @@ jobs:
- build-freebsd
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 20
+ persist-credentials: false
- - uses: pnpm/action-setup@v4
+ - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+ with:
+ version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
- cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
+ package-manager-cache: false
- # 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') }}
+ # npm trusted publishing validates the caller workflow filename, so all npm publishes live here.
+ # This workflow rebuilds the publish artifacts instead of depending on prepare-release.yml.
+ - name: Resolve release metadata
+ env:
+ INPUT_CHANNEL: ${{ github.event.inputs.channel || '' }}
+ run: |
+ if [[ "${{ github.event_name }}" == "release" || "$INPUT_CHANNEL" == "release" ]]; then
+ release_channel=$(node ./scripts/release-channel.js)
- # 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/**/*') }}
+ echo "RELEASE_KIND=release" >> $GITHUB_ENV
+ echo "RELEASE_CHANNEL=$release_channel" >> $GITHUB_ENV
+ echo "FEATURES_ENV=stable" >> $GITHUB_ENV
+ else
+ sha_short=$(git rev-parse --short HEAD)
+
+ echo "RELEASE_KIND=insiders" >> $GITHUB_ENV
+ echo "RELEASE_CHANNEL=insiders" >> $GITHUB_ENV
+ echo "SHA_SHORT=$sha_short" >> $GITHUB_ENV
+ echo "INSIDERS_VERSION=0.0.0-insiders.$sha_short" >> $GITHUB_ENV
+ fi
- name: Setup WASM target
run: rustup target add wasm32-wasip1-threads
- name: Install dependencies
- run: pnpm --filter=!./playgrounds/* install
+ run: pnpm --filter=!./playgrounds/* install --frozen-lockfile
- name: Download artifacts
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
path: ${{ env.OXIDE_LOCATION }}
@@ -274,10 +278,19 @@ jobs:
cp bindings-x86_64-unknown-linux-musl/* ./npm/linux-x64-musl/
cp bindings-x86_64-unknown-freebsd/* ./npm/freebsd-x64/
+ - name: 'Version based on commit: ${{ env.INSIDERS_VERSION }}'
+ if: env.RELEASE_KIND == 'insiders'
+ run: pnpm run version-packages ${INSIDERS_VERSION}
+
- name: Build Tailwind CSS
+ if: env.RELEASE_KIND == 'insiders'
+ run: pnpm run build
+
+ - name: Build Tailwind CSS
+ if: env.RELEASE_KIND == 'release'
run: pnpm run build
env:
- FEATURES_ENV: stable
+ FEATURES_ENV: ${{ env.FEATURES_ENV }}
- name: Run pre-publish optimizations scripts
run: node ./scripts/pre-publish-optimizations.mjs
@@ -285,22 +298,20 @@ jobs:
- 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: Upload npm package tarballs
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
+ with:
+ name: npm-package-tarballs
+ path: dist/*.tgz
- name: Publish
run: |
- pnpm --recursive --filter="!@tailwindcss/oxide-wasm32-wasi" publish --tag ${{ env.RELEASE_CHANNEL }} --no-git-checks
+ pnpm --recursive --filter="!@tailwindcss/oxide-wasm32-wasi" publish --tag ${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 }}
+ pushd crates/node/npm/wasm32-wasi; pnpm publish --tag ${RELEASE_CHANNEL} --no-git-checks --config.node-linker=hoisted; popd;
- name: Trigger Tailwind Play update
- if: env.RELEASE_CHANNEL == 'latest'
- uses: actions/github-script@v7
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }}
script: |
@@ -310,3 +321,38 @@ jobs:
ref: 'main',
workflow_id: 'upgrade-tailwindcss.yml'
})
+
+ notify:
+ if: ${{ always() && (needs.build.result == 'failure' || needs.build-freebsd.result == 'failure' || needs.release.result == 'failure') }}
+ needs:
+ - build
+ - build-freebsd
+ - release
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+ with:
+ persist-credentials: false
+
+ - name: Resolve release label
+ id: release
+ env:
+ INPUT_CHANNEL: ${{ github.event.inputs.channel || '' }}
+ RELEASE_TAG: ${{ github.event.release.tag_name || '' }}
+ run: |
+ if [[ "${{ github.event_name }}" == "release" ]]; then
+ tag_name="${RELEASE_TAG:-${GITHUB_REF_NAME}}"
+ echo "label=release ${tag_name}" >> $GITHUB_OUTPUT
+ elif [[ "$INPUT_CHANNEL" == "release" ]]; then
+ version=$(node -p "require('./packages/tailwindcss/package.json').version")
+ echo "label=release v${version}" >> $GITHUB_OUTPUT
+ else
+ sha_short=$(git rev-parse --short HEAD)
+ echo "label=insiders release 0.0.0-insiders.${sha_short}" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Notify Discord
+ uses: discord-actions/message@5c7149c81a83146e5d01f142be1bf87a61831c4d # v2
+ with:
+ webhookUrl: ${{ secrets.DISCORD_WEBHOOK_URL }}
+ message: 'The [most recent ${{ github.workflow }} workflow](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) for `${{ steps.release.outputs.label }}` has failed.'
diff --git a/.npmrc b/.npmrc
deleted file mode 100644
index ded82e2f6..000000000
--- a/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-auto-install-peers = true
diff --git a/.prettierignore b/.prettierignore
index 3de4530dd..4f50b932f 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,5 +4,6 @@ pnpm-lock.yaml
target/
crates/node/index.d.ts
crates/node/index.js
+crates/ignore/
.next
.fingerprint
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8c3ce090..e5e6f6f89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,289 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- _Experimental_: Add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901))
+- Add `@tailwindcss/turbopack` package to run Tailwind CSS with Next.js ([20367](https://github.com/tailwindlabs/tailwindcss/pull/20367))
+
+### Fixed
+
+- Ensure watch mode detects changes to symlinked `@source` files whose real paths aren't otherwise scanned ([#20356](https://github.com/tailwindlabs/tailwindcss/pull/20356))
+- Ensure custom variants using `@scope` wrap the generated utilities instead of nesting inside them ([#20369](https://github.com/tailwindlabs/tailwindcss/pull/20369))
+- Fix flattening of `@scope` at-rules ([#20369](https://github.com/tailwindlabs/tailwindcss/pull/20369))
+- Fix standalone declarations in `@scope`, wrap them in `:where(:scope)` ([#20369](https://github.com/tailwindlabs/tailwindcss/pull/20369))
+- Always emit a space for empty fallback values in CSS variables (e.g. `var(--tw-blur,)` → `var(--tw-blur, )`) ([#20373](https://github.com/tailwindlabs/tailwindcss/pull/20373))
+- Canonicalization: convert arbitrary breakpoint and container query variants to named equivalents (e.g. `max-[64rem]` → `max-lg`) ([#20380](https://github.com/tailwindlabs/tailwindcss/pull/20380))
+- Prevent `@tailwindcss/vite` from crashing on every edit under Vite's experimental `bundledDev` mode ([#20379](https://github.com/tailwindlabs/tailwindcss/pull/20379))
+- Ensure `@tailwindcss/oxide` falls back to WASM on platforms without native bindings ([#20383](https://github.com/tailwindlabs/tailwindcss/pull/20383))
+- Detect classes in Ruby percent literals using angle brackets or custom delimiters (e.g. `%w