Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/mean_bean_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ jobs:
ASSET="$BIN-$TAG-${{ matrix.target }}.tar.gz"
cp "$BIN.tar.gz" "$ASSET"
gh release upload "$TAG" "$ASSET"
dprint-plugin:
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Setup Rust toolchain
run: rustup toolchain install stable --profile minimal --target wasm32-unknown-unknown

# the smoke test runs in tests.yml instead, so this job with write access
# never executes the npm and dprint plugin downloads it needs
- name: Build the wasm plugin
run: cargo build -p dprint-plugin-rustywind --release --target wasm32-unknown-unknown

- name: Create release and upload asset
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
# sibling jobs race to create the release, so tolerate losing
gh release view "$TAG" > /dev/null 2>&1 \
|| gh release create "$TAG" --title "$TAG" --notes "" \
|| gh release view "$TAG" > /dev/null
# dprint loads plugins from a url ending in .wasm, so keep the name stable across releases
cp target/wasm32-unknown-unknown/release/dprint_plugin_rustywind.wasm dprint-plugin-rustywind.wasm
gh release upload "$TAG" dprint-plugin-rustywind.wasm
docker:
needs: linux
runs-on: ubuntu-24.04
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,18 @@ jobs:

- name: Test all packages in the workspace
run: cargo test --workspace

dprint-plugin:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Setup Rust toolchain
run: rustup toolchain install stable --profile minimal --target wasm32-unknown-unknown

- name: Format smoke fixtures with the wasm plugin
run: bash ci/dprint_smoke.bash
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## [Unreleased]

### Added

- Add a [dprint](https://dprint.dev) Wasm plugin, published as
`dprint-plugin-rustywind.wasm` on each GitHub release. It sorts classes in
addition to the plugin that formats each file,
[#48](https://github.com/avencera/rustywind/issues/48)

## [0.28.0] - 2026-08-25

### Added
Expand Down
75 changes: 66 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["rustywind-cli", "rustywind-core", "rustywind-vite", "xtask"]
members = ["rustywind-cli", "rustywind-core", "rustywind-dprint", "rustywind-vite", "xtask"]
default-members = ["rustywind-cli"]
resolver = "2"

Expand Down
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,58 @@ Options:
Print version
```

## dprint plugin

RustyWind is also available as a [dprint](https://dprint.dev) Wasm plugin. Each GitHub release
includes `dprint-plugin-rustywind.wasm`; add it to the `plugins` in your `dprint.json`:

```json
{
"rustywind": {},
"plugins": [
"https://plugins.dprint.dev/typescript-0.95.13.wasm",
"https://github.com/avencera/rustywind/releases/download/v0.29.0/dprint-plugin-rustywind.wasm"
]
}
```

The plugin sorts classes in addition to whichever plugin formats the file, so `.tsx` files can be
formatted by the TypeScript plugin and then have their classes sorted. Plugins run in the order
they are listed, so list RustyWind last. This requires dprint 0.58.0 or later; older versions treat
it as a regular plugin that competes with other plugins for the same files.

`dprint config update` does not update this plugin, so change the release tag in the URL to
upgrade.

Files that contain a `dprint-ignore`, `dprint-ignore-file`, or `dprint-ignore-start` comment are
left unchanged. The plugin can't tell which part of the file such a comment excludes, so it skips
the whole file.

The plugin sorts files with these extensions: `astro`, `blade`, `django`, `djhtml`, `ejs`, `erb`,
`handlebars`, `hbs`, `htm`, `html`, `j2`, `jinja`, `jinja2`, `jsx`, `liquid`, `lit`, `php`,
`phtml`, `rb`, `svelte`, `tsx`, and `twig`. The template language is inferred from the file name
the same way as the CLI. Add `associations` to sort other files, such as `"associations":
["**/*.{js,vue}"]`.

All options are optional:

```json
{
"rustywind": {
"allowDuplicates": false,
"preserveWhitespace": false,
"tailwindPrefix": "tw-",
"customRegex": "classes\\(([^)]*)\\)",
"classWrapping": "comma-single-quotes",
"sortOrder": ["flex", "p-4"]
}
}
```

These match the CLI's `--allow-duplicates`, `--preserve-whitespace`, `--tailwind-prefix`,
`--custom-regex`, `--class-wrapping`, and the `sortOrder` of `--config-file`. The plugin cannot
read files or make network requests, so `--output-css-file` and `--vite-css` are not available.

## What

Inspired by [Ryan Heybourn's](https://github.com/heybourn) [headwind](https://github.com/heybourn/headwind)
Expand Down
7 changes: 4 additions & 3 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ tag=v$version
## Checklist

1. Update versions and changelogs.
- Bump `rustywind-cli/Cargo.toml`.
- Bump `rustywind-cli/Cargo.toml` and `rustywind-dprint/Cargo.toml` to the same version.
- Bump `rustywind-core/Cargo.toml` and `rustywind-vite/Cargo.toml` only when those crates change.
- Keep path dependency versions in sync.
- Update `CHANGELOG.md`.
Expand All @@ -27,13 +27,14 @@ cargo xtask npm update-version "$version"
just fmt
just clippy
cargo test -p xtask
just dprint-plugin
```

3. Commit the release prep.

```sh
git status --short
git add CHANGELOG.md Cargo.lock rustywind-cli/Cargo.toml rustywind-core/Cargo.toml rustywind-core/CHANGELOG.md rustywind-vite/Cargo.toml npm/packages
git add CHANGELOG.md Cargo.lock rustywind-cli/Cargo.toml rustywind-dprint/Cargo.toml rustywind-core/Cargo.toml rustywind-core/CHANGELOG.md rustywind-vite/Cargo.toml npm/packages
git commit -m "Release $tag"
git push
```
Expand All @@ -59,7 +60,7 @@ git tag "$tag"
git push origin "$tag"
```

Pushing the tag starts `.github/workflows/mean_bean_deploy.yml`, which creates the GitHub release, uploads binaries, builds Docker images, and publishes npm packages.
Pushing the tag starts `.github/workflows/mean_bean_deploy.yml`, which creates the GitHub release, uploads binaries and the dprint plugin, builds Docker images, and publishes npm packages.

6. Watch the GitHub release workflow.

Expand Down
29 changes: 29 additions & 0 deletions ci/dprint_smoke.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Builds the dprint plugin for wasm and formats the smoke fixtures with the real dprint CLI,
# which checks the wasm exports and additive file matching that native tests can't reach.
# The TypeScript plugin claims card.tsx, so its expected output needs both plugins to run
set -euo pipefail

DPRINT_VERSION=0.63.0
# the checksum makes dprint reject a plugin that changed upstream
TYPESCRIPT_PLUGIN=https://plugins.dprint.dev/typescript-0.95.13.wasm@d353247b160c1e81eb043930de6f940adcd3d713651221d3a0284d4c30ea43c4
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SMOKE="$ROOT/rustywind-dprint/tests/smoke"

cargo build -p dprint-plugin-rustywind --release --target wasm32-unknown-unknown

# cargo puts the wasm under the workspace target dir, which CARGO_TARGET_DIR can move
TARGET_DIR="$(cargo metadata --format-version 1 --no-deps | sed -n 's/.*"target_directory":"\([^"]*\)".*/\1/p')"
PLUGIN="$TARGET_DIR/wasm32-unknown-unknown/release/dprint_plugin_rustywind.wasm"

WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
cp -R "$SMOKE/input/." "$WORK"

cd "$WORK"
npx --yes "dprint@$DPRINT_VERSION" fmt --plugins "$TYPESCRIPT_PLUGIN" "$PLUGIN"
diff -r "$SMOKE/expected" "$WORK"

# a second pass must be a no-op, or dprint would keep reformatting the file
npx --yes "dprint@$DPRINT_VERSION" check --plugins "$TYPESCRIPT_PLUGIN" "$PLUGIN"
echo "dprint plugin smoke test passed"
5 changes: 5 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ fmt:

clippy:
cargo clippy -- -D warnings
cargo clippy -p dprint-plugin-rustywind --all-targets -- -D warnings
cargo clippy -p dprint-plugin-rustywind --target wasm32-unknown-unknown -- -D warnings

compare-tailwind *args:
cargo xtask compare run {{ args }}
Expand All @@ -17,3 +19,6 @@ update:

npm-publish:
cargo xtask npm publish

dprint-plugin:
bash ci/dprint_smoke.bash
Loading
Loading