Skip to content

ci: cross-compile Windows tests and CLI binaries on Linux with cargo-xwin#1824

Merged
fengmk2 merged 12 commits into
mainfrom
ci/cross-compile-windows-tests
Jul 3, 2026
Merged

ci: cross-compile Windows tests and CLI binaries on Linux with cargo-xwin#1824
fengmk2 merged 12 commits into
mainfrom
ci/cross-compile-windows-tests

Conversation

@fengmk2

@fengmk2 fengmk2 commented Jun 12, 2026

Copy link
Copy Markdown
Member

Summary

Build the Windows test binaries and the CLI/binding once on a Linux runner with cargo-xwin, then just run them on Windows (download-only). Same approach as voidzero-dev/vite-task#443.

Cache-miss comparison

Run Wall time
main (cache miss) 34m45s
this PR (Windows CLI binary-cache miss) 17m09s

Net: 17m36s faster, about 51% less wall time. Both runs include the Socket Firewall Free job. The PR run missed the windows-cli-xwin binary cache after the reviewed cache-key/path refactors; the Windows SDK and package-manager caches were warm.

Latest binary-cache-miss breakdown:

  • build-windows-tests: 2m45s, followed by the download-only Windows test job in 3m05s.
  • build-windows-cli: 7m46s, followed by the slowest download-only Windows consumer tail in 6m52s.
  • All Windows test, CLI E2E, snapshot, SFW, and ecosystem jobs passed using the Linux-built artifacts.

Warm-cache comparison

Run Wall time
Before: main (NAPI binding cache hit) 11m57s
After: this PR (windows-cli-xwin cache hit) 7m13s

Net: 4m44s faster, about 40% less wall time. These are full successful CI executions with the native caches already populated. In the PR run, build-windows-cli restored the exact binary cache, skipped native compilation, re-uploaded the artifact, and completed in 9s.

Why this is faster:

  • Linux is a much faster place to cross-compile the Windows binaries (cargo-xwin + clang-cl/lld-link against the cached MSVC CRT / Windows SDK), instead of every Windows job rebuilding the same ~24-minute release binding + CLI binaries.
  • Before, the run was gated by the single slowest Windows job (~30m, each doing its own full build); after, the native work is performed once on Linux and the Windows jobs only download and execute the resulting artifacts.
  • The Windows jobs (Test, CLI E2E, CLI snap, sfw) now download a prebuilt artifact and skip native compilation, so they need no Rust toolchain or dev drive.
  • test's Windows leg runs from a nextest archive (build-windows-tests) with no toolchain at all.
  • Releases are unaffected and keep building natively on Windows (their cache keys differ via RELEASE_BUILD/VERSION). CI Windows binaries are clang-cl/lld-link-built; the e2e/snap suites still run them on real Windows.
flowchart LR
  subgraph Before["Before: every Windows job rebuilds the workspace"]
    B1["Windows jobs x5"] --> B2["Compile binding + vp on Windows<br/>~24m each"]
    B2 --> B3["Install vp"]
    B3 --> B4["Run e2e / snap / sfw"]
  end

  subgraph After["After: build once on Linux, run on Windows"]
    A1["Linux: build-windows-cli"] --> A2["vp.exe + binding artifact"]
    A2 --> A3["CLI E2E / snap / sfw (Windows)<br/>download + run, no toolchain"]
    A4["Linux: build-windows-tests"] --> A5["nextest archive"]
    A5 --> A6["Test (Windows)<br/>run-only"]
  end
Loading

@fengmk2 fengmk2 self-assigned this Jun 12, 2026
@netlify

netlify Bot commented Jun 12, 2026

Copy link
Copy Markdown

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit d6f692d
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a477962511e2400076a39a0

@fengmk2 fengmk2 force-pushed the ci/cross-compile-windows-tests branch from 76a1e12 to 954004c Compare June 13, 2026 06:39
@fengmk2 fengmk2 added test: e2e Auto run e2e tests test: install-e2e run vite install e2e test test: create-e2e Run `vp create` e2e tests test: sfw labels Jun 13, 2026
fengmk2 added 4 commits June 15, 2026 14:21
…xwin

Windows jobs previously compiled the workspace (test job) and the
release NAPI binding plus vp binaries (cli-e2e-test, 3 cli-snap-test
shards, install-e2e-test-sfw) on slow windows-latest runners, costing
about 24 minutes per job on every NAPI binding cache miss.

Apply the approach from voidzero-dev/vite-task#443:

- build-windows-tests (Linux) cross-compiles workspace tests with
  cargo-xwin into a portable cargo-nextest archive and runs the
  Windows-target cargo check with -D warnings; the run-only
  test-windows job downloads the archive and runs it without a Rust
  toolchain (--test-threads 1 because serial_test in-process locks do
  not span nextest's process-per-test model).
- build-windows-cli (Linux) cross-builds the release binding via
  napi build -x and vp.exe/vp-shim.exe/vp-setup.exe via cargo xwin
  build, published as the windows-cli-binaries artifact; the Windows
  entries of cli-e2e-test, cli-snap-test, and install-e2e-test-sfw
  download it and skip native builds via build-upstream's new
  skip-native input.

Release builds are unaffected and keep building natively on Windows
(reusable-release-build cache keys differ via RELEASE_BUILD/VERSION).
The build-windows-cli job intentionally skips the TS builds, but
build.ts formats the generated index.cjs/index.d.cts with options
imported from the repo vite config, which itself imports the built
vite-plus dist and crashed with ERR_MODULE_NOT_FOUND after a successful
cross compile. Add a --skip-format flag to build.ts and pass it from
the job; formatting the generated bindings is cosmetic there.
The generated binding JS files (index.cjs, index.d.cts, index.js,
index.d.ts) are committed to the repo, and the cross-build job now
regenerates them unformatted (--skip-format). Shipping them in the
artifact overwrote the pristine committed copies in consumer checkouts
and made vp check fail on the Windows e2e job. Consumers only need the
.node binding and the vp/vp-shim/vp-setup executables; the committed
index files are already correct (Linux e2e's unexpected-file-changes
check guards their drift).
- build-upstream: collapse the repeated `skip-native != 'true' &&
  cache-hit != 'true'` condition (12 step guards) into a single
  computed `native.build` output gating each step.
- Add reciprocal 'keep in sync' comments on the two copies of the
  hashFiles cache-key input list (build-upstream vs build-windows-cli)
  so they don't drift and serve a stale cross-built artifact.
- build.ts: extract the custom-flag list and use .includes() instead
  of a growing chain of != comparisons.
@fengmk2 fengmk2 force-pushed the ci/cross-compile-windows-tests branch from fee2372 to 7ef8158 Compare June 15, 2026 06:21
fengmk2 added 4 commits June 15, 2026 14:42
The e2e-test build job's windows-latest entry built the NAPI binding + vp
binaries natively (~24m on cache miss); the e2e-test run job was already
artifact-only. Cross-compile that build on Linux with cargo-xwin the same
way ci.yml does, keeping only the run job on Windows.

Extract the xwin toolchain setup (setup-rust + llvm-tools, rustup target,
cargo-xwin install, MSVC SDK cache) into a shared .github/actions/setup-xwin
composite, now used by build-windows-tests, build-windows-cli, and the
e2e-test build, instead of a third copy. The composite uses the combined
actions/cache (restore + post-save) for the SDK, replacing the split
restore/save pairs.
Moving the whole e2e-test Windows build to Linux is infeasible: in
non-release CI builds @voidzero-dev/vite-plus-core bundles the rolldown
native binding for the *host* platform, so building on Linux ships the
Linux rolldown binding in the Windows tgz and every Windows e2e job
fails at config load (rolldown returns null -> "Cannot convert
undefined or null to object"). ci.yml's Phase 2 avoids this because its
Windows jobs still run core's bundling on Windows; only the vite-plus
.node is cross-built.

Revert the e2e build job to the native Windows build. The setup-xwin
composite and the ci.yml refactor (both green) stay.
Extract the Windows cross-build into a .github/actions/build-windows-cli
composite (compute cache key, restore, setup-xwin, cross-build binding +
vp/vp-shim/vp-setup, upload artifact, save cache) so ci.yml and
e2e-test.yml share one implementation and one content-hash cache key.

e2e-test gains a build-windows-cli job that produces the artifact; its
build job's windows-latest entry downloads it and runs build-upstream
with skip-native, so the ~24m native Rust compile moves to Linux while
core/rolldown bundling still runs on Windows (it is host-platform
specific, which is why the all-Linux approach failed).
@fengmk2

fengmk2 commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: e51ee80388

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fengmk2 fengmk2 marked this pull request as ready for review July 3, 2026 07:11
@fengmk2 fengmk2 requested review from Brooooooklyn and wan9chi July 3, 2026 07:16
@fengmk2 fengmk2 merged commit 53edee8 into main Jul 3, 2026
97 checks passed
@fengmk2 fengmk2 deleted the ci/cross-compile-windows-tests branch July 3, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test: create-e2e Run `vp create` e2e tests test: e2e Auto run e2e tests test: install-e2e run vite install e2e test test: sfw

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants