Skip to content

feat(oxide): add OpenHarmony (aarch64-unknown-linux-ohos) prebuilt binary support#20276

Open
social4hyq wants to merge 4 commits into
tailwindlabs:mainfrom
social4hyq:feat/ohos-support
Open

feat(oxide): add OpenHarmony (aarch64-unknown-linux-ohos) prebuilt binary support#20276
social4hyq wants to merge 4 commits into
tailwindlabs:mainfrom
social4hyq:feat/ohos-support

Conversation

@social4hyq

@social4hyq social4hyq commented Jun 25, 2026

Copy link
Copy Markdown

Add aarch64-unknown-linux-ohos as a build target so @tailwindcss/oxide
loads natively on OpenHarmony/HarmonyOS devices without falling back to WASM.

Changes

  • crates/node/package.json — add aarch64-unknown-linux-ohos to napi.targets; add @tailwindcss/oxide-openharmony-arm64 to optionalDependencies
  • crates/node/npm/openharmony-arm64/package.json — new platform subpackage ("os": ["openharmony"], "cpu": ["arm64"])
  • pnpm-lock.yaml — updated for new workspace package
  • .github/workflows/release.yml — new build-ohos job + wire into release job needs and Move artifacts step

Why no index.js changes

@napi-rs/cli@3.7.0 (already used by this project) natively maps aarch64-unknown-linux-ohosprocess.platform === 'openharmony' with package suffix openharmony-arm64. The generated index.js will contain the correct branch automatically — no manual edits needed.

CI design decisions

  • Separate build-ohos job (not added to the main matrix) — the existing build matrix entries use --use-napi-cross (zig) which doesn't support the OHOS sysroot; OHOS needs its own linker setup
  • Boshen/setup-ohos-sdk@v1.0.0 — same action used by rolldown and lightningcss for their OHOS builds; downloads only the native sysroot instead of the full 2.3 GB SDK
  • Shell wrapper linker — configured via CARGO_TARGET_*_LINKER env var; no .cargo/config.toml changes
  • rustflags: -C link-arg=-fuse-ld=lld -C link-arg=-lm — required for OHOS targets (lld is the only supported linker; -lm resolves missing math symbols)

Verification

Built and runtime-tested on HarmonyOS HongMeng Kernel 1.12.0 (aarch64) with LLVM 21.1.8:

cargo build --lib -p tailwind-oxide --release --target aarch64-unknown-linux-ohos  #

Runtime verified via opencode (which embeds @tailwindcss/oxide) on-device ✓

CI: social4hyq/tailwindcss — Test OHOS build — run #28161581738all steps passed, artifact tailwindcss-oxide.openharmony-arm64.node (2.6 MB) produced ✓

- Add aarch64-unknown-linux-ohos to napi targets in crates/node/package.json
- Add @tailwindcss/oxide-openharmony-arm64 optional dependency
- Add crates/node/npm/openharmony-arm64/package.json platform subpackage
- Add build-ohos CI job using Boshen/setup-ohos-sdk
- Wire build-ohos into release job needs + Move artifacts step

NAPI-RS 3.7.0 natively maps aarch64-unknown-linux-ohos to process.platform
'openharmony' with package suffix 'openharmony-arm64', so index.js is
generated correctly without manual edits.

Verified: built and runtime-tested on HarmonyOS HongMeng Kernel 1.12.0 (aarch64).
@social4hyq social4hyq requested a review from a team as a code owner June 25, 2026 09:38
@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge after adding --ignore-scripts to the OHOS install step; the rest of the changes follow established patterns.

The OHOS build job omits --ignore-scripts from its pnpm install call, while every other build job includes it. This can cause native-module lifecycle scripts to execute on the Ubuntu host runner before any cross-compiled binary exists, potentially breaking the install step.

.github/workflows/release.yml — the Install dependencies step inside build-ohos needs --ignore-scripts added.

Reviews (5): Last reviewed commit: "fix: address PR review feedback" | Re-trigger Greptile

Comment thread crates/node/package.json
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "workspace:*",
"@tailwindcss/oxide-openharmony-arm64": "workspace:*",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Frozen Lockfile Install Fails

This adds a new workspace optional dependency, but the PR does not include a matching pnpm-lock.yaml update. The new OHOS workflow runs pnpm install --ignore-scripts --frozen-lockfile, so release builds can stop at install time before the native package is built or published.

Comment thread crates/node/package.json
"targets": [
"armv7-linux-androideabi",
"aarch64-linux-android",
"aarch64-unknown-linux-ohos",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Generated Loader Can Miss OHOS

This relies on the generated loader mapping aarch64-unknown-linux-ohos to the openharmony-arm64 package at publish time, but no checked-in loader change or release-step verification pins that behavior here. If the generator does not emit an openharmony branch for the runtime platform, OpenHarmony installs can receive the new optional package but still try the wrong native package or report that no native binary is available.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fef6ae17-f0fe-42f0-aa65-e3211c89d6be

📥 Commits

Reviewing files that changed from the base of the PR and between 351004e and 7384552.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • .github/workflows/release.yml
  • scripts/version-packages.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/release.yml

Walkthrough

The PR adds an OpenHarmony arm64 npm manifest, adds the aarch64-unknown-linux-ohos target and optional dependency to the node package, includes the package in version syncing, and updates the release workflow to build, strip, upload, and copy OHOS bindings into the npm release layout.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding OpenHarmony prebuilt binary support for oxide.
Description check ✅ Passed The description matches the changeset and explains the new OpenHarmony build target and packaging work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 220-221: The workflow step using dtolnay/rust-toolchain@stable is
not pinned and can drift over time; update the Install Rust step in release.yml
to reference a specific full commit SHA instead of the stable tag. Keep the step
name and action usage the same, but replace the version tag with the locked
commit identifier to match the repo’s supply-chain policy.
- Around line 238-239: The OHOS dependency install step is suppressing lifecycle
scripts, which prevents required setup hooks from running before the build.
Update the Install dependencies step in the release workflow to remove
--ignore-scripts from the pnpm install command while keeping the existing frozen
lockfile and filter behavior, so the build environment is initialized correctly
for build:platform.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2ccccdc5-4a35-4dad-91c0-472f2e6eba44

📥 Commits

Reviewing files that changed from the base of the PR and between d5ca0ae and 52c23df.

📒 Files selected for processing (3)
  • .github/workflows/release.yml
  • crates/node/npm/openharmony-arm64/package.json
  • crates/node/package.json

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
@@ -0,0 +1,27 @@
{
"name": "@tailwindcss/oxide-openharmony-arm64",
"version": "4.3.1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Sync package version
This new native package is picked up by the recursive publish step, but it is not in the hardcoded oxide package list that the release workflow versions before publishing. On the next release or insiders publish, this package can stay at 4.3.1 while @tailwindcss/oxide points at the new release version. The publish can then fail because 4.3.1 already exists, or OpenHarmony users can get a platform package whose version no longer matches the parent optional dependency set. Please add crates/node/npm/openharmony-arm64 to the same version sync list as the other native packages.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/test-ohos-build.yml:
- Around line 19-31: The workflow job uses mutable action tags in the
checkout/setup steps, so update the `actions/checkout`, `pnpm/action-setup`,
`actions/setup-node`, and `dtolnay/rust-toolchain` references to pinned commit
SHAs to match the repo’s pinning policy. Also update the `actions/checkout` step
to disable credential persistence with `persist-credentials: false` since this
job only builds; keep the changes localized to the existing checkout, pnpm
setup, node setup, and Rust toolchain steps.
- Line 49: Remove the --ignore-scripts flag from the pnpm install step in the
test-ohos-build workflow so Bun lifecycle scripts can run during installation;
keep the existing --frozen-lockfile and playgrounds filter arguments in the
install command, and update the workflow step that uses pnpm install
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3c4739fb-b8d8-4c8d-9e7e-cb8978e59003

📥 Commits

Reviewing files that changed from the base of the PR and between 52c23df and 351004e.

📒 Files selected for processing (1)
  • .github/workflows/test-ohos-build.yml

Comment thread .github/workflows/test-ohos-build.yml Outdated
Comment on lines +19 to +31
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}

- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Pin actions to commit SHAs and disable credential persistence.

actions/checkout@v4, pnpm/action-setup@v4, actions/setup-node@v4, and dtolnay/rust-toolchain@stable are referenced by mutable tags, which is inconsistent with the SHA-pinned Boshen/setup-ohos-sdk on line 37 and the repo's pinning policy. Also set persist-credentials: false on the checkout since this job only builds and does not push.

🔒 Proposed fix
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@<commit-sha> # v4
+        with:
+          persist-credentials: false

Apply the same SHA pinning to lines 21, 26, and 31.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 19-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 21-21: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 26-26: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 31-31: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/test-ohos-build.yml around lines 19 - 31, The workflow job
uses mutable action tags in the checkout/setup steps, so update the
`actions/checkout`, `pnpm/action-setup`, `actions/setup-node`, and
`dtolnay/rust-toolchain` references to pinned commit SHAs to match the repo’s
pinning policy. Also update the `actions/checkout` step to disable credential
persistence with `persist-credentials: false` since this job only builds; keep
the changes localized to the existing checkout, pnpm setup, node setup, and Rust
toolchain steps.

Source: Linters/SAST tools

Comment thread .github/workflows/test-ohos-build.yml Outdated
chmod +x /tmp/aarch64-linux-ohos-clang

- name: Install dependencies
run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Remove --ignore-scripts from the install step.

In this repo's setup, Bun relies on lifecycle scripts during installation, so --ignore-scripts breaks the Bun-related setup. Keep --frozen-lockfile (and the playgrounds filter), but drop --ignore-scripts.

🔧 Proposed fix
-        run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/*
+        run: pnpm install --frozen-lockfile --filter=!./playgrounds/*

Based on learnings: do not run pnpm install with --ignore-scripts in this repo's CI/release workflows because Bun relies on lifecycle scripts during installation; the only safe flag to enforce is --frozen-lockfile.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/*
run: pnpm install --frozen-lockfile --filter=!./playgrounds/*
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/test-ohos-build.yml at line 49, Remove the
--ignore-scripts flag from the pnpm install step in the test-ohos-build workflow
so Bun lifecycle scripts can run during installation; keep the existing
--frozen-lockfile and playgrounds filter arguments in the install command, and
update the workflow step that uses pnpm install accordingly.

Source: Learnings

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/
cp bindings-aarch64-unknown-linux-ohos/* ./npm/openharmony-arm64/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Rename OHOS artifact

This copy puts the OHOS build output into npm/openharmony-arm64/ without changing the filename. The package declares tailwindcss-oxide.openharmony-arm64.node as its entry point, while the napi build --platform --target=aarch64-unknown-linux-ohos output is target-derived. If that output keeps the OHOS target name, the published package can contain a .node file that does not match its main, so require('@tailwindcss/oxide-openharmony-arm64') fails with MODULE_NOT_FOUND even though the package installed successfully. Please rename the copied artifact to the filename declared by the platform package, or update the package metadata to match the actual build output.

- Pin dtolnay/rust-toolchain to commit SHA (supply-chain policy)
- Remove --ignore-scripts from build-ohos install step
- Add openharmony-arm64 to version-packages.mjs syncedWorkspaces
  so the platform package version stays in sync on every release
- Remove test-ohos-build.yml (verification artifact, not for upstream)
@social4hyq

Copy link
Copy Markdown
Author

Thanks for the review! Addressing all comments in commit 7384552:

CodeRabbit — dtolnay/rust-toolchain pinning → pinned to commit SHA 67ef31d5b988238dd797d409d6f9574278e20537.

CodeRabbit — --ignore-scripts → removed from the build-ohos install step.

Greptile — version-packages.mjs syncedWorkspaces → real bug, fixed by adding crates/node/npm/openharmony-arm64 to the hardcoded list so it versions in sync with @tailwindcss/oxide on every release.

Greptile — Generated loader may miss OHOS@napi-rs/cli@3.7.0 (already used by this project) natively maps aarch64-unknown-linux-ohos to process.platform === 'openharmony' with package suffix openharmony-arm64, so the generated index.js is correct automatically. Confirmed by CI run: artifact is named tailwindcss-oxide.openharmony-arm64.node.

Greptile — Artifact rename → not needed; napi build --platform derives the filename from the NAPI-RS platform suffix, output is already tailwindcss-oxide.openharmony-arm64.node, matching the platform package main field.

Removed test-ohos-build.yml → temporary verification workflow, not for upstream.

@RobinMalfait

Copy link
Copy Markdown
Member

Hey! I appreciate the PR, but going to skip this for now. We can add support for it if more people need support for this. Right now I'm a bit skeptical, especially becaues of the 3rd party GitHub actions that are being used.

We can revisit this when more people need support for ohos. Thanks!

@SimboDu123

Copy link
Copy Markdown

oh no!
Hope to quickly adapt to OpenHarmony!

@social4hyq

social4hyq commented Jun 29, 2026

Copy link
Copy Markdown
Author

Hi @RobinMalfait, thanks for taking a look at this PR. I'd like to respectfully ask you to reconsider, with some additional context:

1. There is real, measurable demand.

The OpenHarmony platform packages of peer projects are seeing substantial usage:

Package Monthly Downloads
@rollup/rollup-openharmony-arm64 12.6M
@rolldown/binding-openharmony-arm64 5.6M

These are not marginal numbers. OpenHarmony/HarmonyOS has a growing developer ecosystem.

2. Boshen/setup-ohos-sdk is the community standard, not an unknown third-party.

This same GitHub Action is already used by Rolldown (rolldown/rolldown#5258), Rollup (rollup/rollup#6081), OXC (oxc-project/oxc#16105). Boshen is a well-known ecosystem contributor and an oxc core member — this action is production-proven across multiple projects.

3. All peer projects listed above have already merged their OHOS support, and the Tailwind PR is technically sound (reviewed and greenlit by both CodeRabbit and Greptile, CI verified). Without native OHOS binaries, Tailwind CSS users on that platform can only fall back to WASM, which is significantly slower.

Would you be open to revisiting this?

@RobinMalfait RobinMalfait reopened this Jul 9, 2026
Comment on lines +238 to +239
- name: Install dependencies
run: pnpm install --frozen-lockfile --filter=!./playgrounds/*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 All other build jobs (main matrix and FreeBSD) pass --ignore-scripts here. Without it, lifecycle scripts from dependencies can execute on the host runner before the cross-compiled native binary exists, which can break the install step or load a wrong-architecture binary.

Suggested change
- name: Install dependencies
run: pnpm install --frozen-lockfile --filter=!./playgrounds/*
- name: Install dependencies
run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/*

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@RobinMalfait

Copy link
Copy Markdown
Member

@social4hyq I understand that, but the problem is that we get asked to add support for a bunch of different platforms without knowing why this is needed. There are no bug reports saying that Tailwind CSS is currently not working on these platforms, or if it is working that it is slower compared to a native version (and how much slower).

Adding support for every platform that exists is not really possible, because what's actually happening here is that we have to support these platforms forever. When 3rd party tools stop providing support for a platform, then we have to support it ourselves.

Without native OHOS binaries, Tailwind CSS users on that platform can only fall back to WASM, which is significantly slower.

Do you have some data on this? What does "significantly slower" mean on your machine for example?

The OpenHarmony platform packages of peer projects are seeing substantial usage:

I believe those numbers, I just need to understand what's currently broken or how slow things are.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants