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
52 changes: 36 additions & 16 deletions .github/actions/build-upstream/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ inputs:
description: 'Print the output after the build'
required: false
default: 'false'
skip-native:
description: >-
Skip the NAPI binding cache and all native cargo/napi build steps; the
native binaries must already be in place (e.g. downloaded from the
windows-cli-binaries artifact produced by the build-windows-cli job).
required: false
default: 'false'

runs:
using: 'composite'
Expand All @@ -18,14 +25,17 @@ runs:
target: ${{ inputs.target }}
upload: 'false'

# Compute cache key once before any builds modify files
# (packages/cli/package.json is modified by syncTestPackageExports during build-ts)
# Include env vars (RELEASE_BUILD, DEBUG, VERSION) to ensure cache miss on release builds
# Compute the shared input hash before builds modify files
# (packages/cli/package.json is modified by syncTestPackageExports during build-ts).
- uses: ./.github/actions/compute-native-cache-input-hash
id: native-cache-inputs

# Include env vars (RELEASE_BUILD, DEBUG, VERSION) to ensure cache miss on release builds.
- name: Compute NAPI binding cache key
id: cache-key
shell: bash
run: |
echo "key=napi-binding-v3-${INPUTS_TARGET}-${RELEASE_BUILD}-${DEBUG}-${VERSION}-${NPM_TAG}-${{ hashFiles('packages/tools/.upstream-versions.json', 'rust-toolchain.toml', 'Cargo.lock', 'crates/**/*.rs', 'crates/*/Cargo.toml', 'packages/cli/binding/**/*.rs', 'packages/cli/binding/Cargo.toml', 'Cargo.toml', '.cargo/config.toml', 'packages/cli/package.json', 'packages/cli/build.ts', 'packages/cli/tsdown.config.ts') }}" >> $GITHUB_OUTPUT
echo "key=napi-binding-v3-${INPUTS_TARGET}-${RELEASE_BUILD}-${DEBUG}-${VERSION}-${NPM_TAG}-${{ steps.native-cache-inputs.outputs.hash }}" >> "$GITHUB_OUTPUT"
env:
INPUTS_TARGET: ${{ inputs.target }}

Expand All @@ -38,6 +48,7 @@ runs:
# Cache NAPI bindings and Rust CLI binary (the slow parts, especially on Windows)
- name: Restore NAPI binding cache
id: cache-restore
if: inputs.skip-native != 'true'
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
Expand All @@ -52,6 +63,15 @@ runs:
${{ steps.rust-target.outputs.dir }}/${{ inputs.target }}/release/vp-setup.exe
key: ${{ steps.cache-key.outputs.key }}

# Single source of truth for "build the native binaries in this job":
# false when the caller supplied prebuilt ones (skip-native) or the cache
# already has them. Every native build step (and the cache save) gates on
# this one flag instead of repeating the two-part condition.
- name: Decide native build
id: native
shell: bash
run: echo "build=${{ inputs.skip-native != 'true' && steps.cache-restore.outputs.cache-hit != 'true' }}" >> "$GITHUB_OUTPUT"

# Apply Vite+ branding patches to vite source (CI checks out
# upstream vite which doesn't have branding patches)
- name: Brand vite
Expand All @@ -69,14 +89,14 @@ runs:

# Install zig + cargo-zigbuild for musl cross-compilation (napi-cross only supports gnu)
- name: Add musl Rust target
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'musl')
shell: bash
run: rustup target add ${INPUTS_TARGET}
env:
INPUTS_TARGET: ${{ inputs.target }}

- name: Setup zig (musl)
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'musl')
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
with:
version: 0.15.2
Expand All @@ -87,15 +107,15 @@ runs:
# the pinned git commit. TODO: revert to taiki-e/install-action once
# cargo-zigbuild > 0.22.3 is released.
- name: Install cargo-zigbuild (musl)
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'musl')
shell: bash
run: cargo install --locked --git https://github.com/rust-cross/cargo-zigbuild --rev 7e791b4be71b9870e0abccedf7885486803cd923 cargo-zigbuild

# NAPI builds - only run on cache miss (slow, especially on Windows)
# Must run before vite-plus TypeScript builds which depend on the bindings
- name: Build NAPI bindings (Linux gnu)
shell: bash
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'linux') && !contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'linux') && !contains(inputs.target, 'musl')
run: |
pnpm --filter=vite-plus build-native --target ${INPUTS_TARGET} --use-napi-cross
env:
Expand All @@ -106,7 +126,7 @@ runs:

- name: Build NAPI bindings (Linux musl)
shell: bash
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'musl')
run: |
pnpm --filter=vite-plus build-native --target ${INPUTS_TARGET} -x
env:
Expand All @@ -117,15 +137,15 @@ runs:

- name: Build NAPI bindings (non-Linux targets)
shell: bash
if: steps.cache-restore.outputs.cache-hit != 'true' && !contains(inputs.target, 'linux')
if: steps.native.outputs.build == 'true' && !contains(inputs.target, 'linux')
run: |
pnpm --filter=vite-plus build-native --target ${INPUTS_TARGET}
env:
DEBUG: napi:*
INPUTS_TARGET: ${{ inputs.target }}

- name: Build Rust CLI binary (Linux gnu)
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'linux') && !contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'linux') && !contains(inputs.target, 'musl')
shell: bash
run: |
pnpm exec napi build --use-napi-cross --target ${INPUTS_TARGET} --release -p vite_global_cli
Expand All @@ -136,7 +156,7 @@ runs:
INPUTS_TARGET: ${{ inputs.target }}

- name: Build Rust CLI binary (Linux musl)
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'musl')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'musl')
shell: bash
run: |
pnpm exec napi build -x --target ${INPUTS_TARGET} --release -p vite_global_cli
Expand All @@ -147,28 +167,28 @@ runs:
INPUTS_TARGET: ${{ inputs.target }}

- name: Build Rust CLI binary (non-Linux targets)
if: steps.cache-restore.outputs.cache-hit != 'true' && !contains(inputs.target, 'linux')
if: steps.native.outputs.build == 'true' && !contains(inputs.target, 'linux')
shell: bash
run: cargo build --release --target ${INPUTS_TARGET} -p vite_global_cli
env:
INPUTS_TARGET: ${{ inputs.target }}

- name: Build trampoline shim binary (Windows only)
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'windows')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'windows')
shell: bash
run: cargo build --release --target ${INPUTS_TARGET} -p vite_trampoline
env:
INPUTS_TARGET: ${{ inputs.target }}

- name: Build installer binary (Windows only)
if: steps.cache-restore.outputs.cache-hit != 'true' && contains(inputs.target, 'windows')
if: steps.native.outputs.build == 'true' && contains(inputs.target, 'windows')
shell: bash
run: cargo build --release --target ${INPUTS_TARGET} -p vite_installer
env:
INPUTS_TARGET: ${{ inputs.target }}

- name: Save NAPI binding cache
if: steps.cache-restore.outputs.cache-hit != 'true'
if: steps.native.outputs.build == 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
Expand Down
104 changes: 104 additions & 0 deletions .github/actions/build-windows-cli/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: 'Build Windows CLI binaries'
description: >-
Cross-compile the Windows release NAPI binding and vp/vp-shim/vp-setup
binaries on Linux with cargo-xwin, cache them by source hash, and upload
them as an artifact for Windows jobs to consume (with build-upstream's
skip-native input). Run on a Linux runner after checkout + clone.

inputs:
save-cache:
description: "Whether setup-xwin's setup-rust should save its cache (usually only on main)."
required: false
default: 'false'
artifact-name:
description: 'Name for the uploaded binaries artifact.'
required: false
default: 'windows-cli-binaries'

runs:
using: 'composite'
steps:
# The shared action is the single source of truth for inputs that affect
# the native binaries and generated bindings.
- uses: ./.github/actions/compute-native-cache-input-hash
id: native-cache-inputs

# Use a distinct prefix: this cache stores Linux-relative paths and must
# never mix with the caches build-upstream saves on other runners. Sharing
# this one key across ci.yml and e2e-test.yml lets whichever workflow builds
# first serve the other.
- name: Compute binaries cache key
id: cache-key
shell: bash
run: |
echo "key=windows-cli-xwin-v1-${{ steps.native-cache-inputs.outputs.hash }}" >> "$GITHUB_OUTPUT"

- name: Define binary paths
id: binary-paths
shell: bash
run: |
{
echo 'paths<<EOF'
echo 'packages/cli/binding/*.node'
echo 'target/x86_64-pc-windows-msvc/release/vp.exe'
echo 'target/x86_64-pc-windows-msvc/release/vp-shim.exe'
echo 'target/x86_64-pc-windows-msvc/release/vp-setup.exe'
echo 'EOF'
} >> "$GITHUB_OUTPUT"

- name: Restore binaries cache
id: binaries-cache
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ steps.binary-paths.outputs.paths }}
key: ${{ steps.cache-key.outputs.key }}

- uses: ./.github/actions/setup-xwin
if: steps.binaries-cache.outputs.cache-hit != 'true'
with:
save-cache: ${{ inputs.save-cache }}
cache-key: windows-cli-cross

- uses: oxc-project/setup-node@4c588e9266bd930b6ddc34307df0659ed511d187 # v1.3.1
if: steps.binaries-cache.outputs.cache-hit != 'true'

# --skip-format: formatting the generated index.cjs/index.d.cts needs the
# repo vite config, which imports the not-yet-built vite-plus dist; this
# action skips the TS builds on purpose.
- name: Build NAPI binding
if: steps.binaries-cache.outputs.cache-hit != 'true'
shell: bash
run: pnpm --filter=vite-plus build-native --target x86_64-pc-windows-msvc -x --skip-format
env:
DEBUG: 'napi:*'
XWIN_ACCEPT_LICENSE: '1'
# See setup-xwin / build-windows-tests for why this Detours escape
# hatch is needed.
CXXFLAGS: -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH

- name: Build Rust CLI binaries
if: steps.binaries-cache.outputs.cache-hit != 'true'
shell: bash
run: cargo xwin build --release --target x86_64-pc-windows-msvc -p vite_global_cli -p vite_trampoline -p vite_installer
env:
XWIN_ACCEPT_LICENSE: '1'
CXXFLAGS: -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.artifact-name }}
# Both path roots are workspace-relative, so the artifact preserves the
# repo layout and a plain download into the workspace places every file
# where tool install-global-cli expects it. The generated binding JS
# (index.cjs etc.) is NOT included: those files are committed, and the
# unformatted copies this action produces (--skip-format) must not
# overwrite them in consumer checkouts (vp check would flag them).
path: ${{ steps.binary-paths.outputs.paths }}
if-no-files-found: error
retention-days: 7

- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
if: steps.binaries-cache.outputs.cache-hit != 'true'
with:
path: ${{ steps.binary-paths.outputs.paths }}
key: ${{ steps.cache-key.outputs.key }}
43 changes: 43 additions & 0 deletions .github/actions/compute-native-cache-input-hash/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: 'Compute native cache input hash'
description: 'Hash every input that can affect the native CLI binaries and generated bindings.'

outputs:
hash:
description: 'Combined hash of the native build inputs.'
value: ${{ steps.compute.outputs.hash }}

runs:
using: 'composite'
steps:
- name: Compute native cache input hash
id: compute
shell: bash
run: |
echo "hash=$NATIVE_CACHE_INPUT_HASH" >> "$GITHUB_OUTPUT"
env:
NATIVE_CACHE_INPUT_HASH: >-
${{
hashFiles(
'packages/tools/.upstream-versions.json',
'rust-toolchain.toml',
'Cargo.lock',
'Cargo.toml',
'.cargo/config.toml',
'crates/**',
'packages/cli/binding/src/**',
'packages/cli/binding/build.rs',
'packages/cli/binding/Cargo.toml',
'packages/cli/binding/index.*',
'packages/cli/src/vite-config-entry-basenames.json',
'package.json',
'pnpm-lock.yaml',
'pnpm-workspace.yaml',
'packages/cli/package.json',
'packages/cli/build.ts',
'packages/cli/tsdown.config.ts',
'.github/actions/build-upstream/action.yml',
'.github/actions/build-windows-cli/action.yml',
'.github/actions/compute-native-cache-input-hash/action.yml',
'.github/actions/setup-xwin/action.yml'
)
}}
48 changes: 48 additions & 0 deletions .github/actions/setup-xwin/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: 'Setup cargo-xwin'
description: >-
Install the Rust toolchain and cargo-xwin for cross-compiling to
x86_64-pc-windows-msvc on Linux, with the MSVC CRT / Windows SDK cached.

inputs:
cache-key:
description: 'setup-rust cache-key prefix; pass a distinct value per caller.'
required: true
save-cache:
description: 'Whether setup-rust should save its cache (usually only on main).'
required: false
default: 'false'
tools:
description: >-
Extra comma-separated taiki-e/install-action tools to install alongside
cargo-xwin (e.g. "cargo-nextest").
required: false
default: ''

runs:
using: 'composite'
steps:
# llvm-tools provides llvm-ar in the toolchain's rustlib bin dir; cargo-xwin
# symlinks the MSVC-style llvm-lib/llvm-dlltool (used by cc-rs to archive
# C/C++ deps) and lld-link from there when the runner image has no matching
# system LLVM.
- uses: oxc-project/setup-rust@68c3199c5339f965e6e163924c3c450773eba42b # main (pending v1.0.17 — Swatinem/rust-cache v2.9.1 for node24)
with:
save-cache: ${{ inputs.save-cache }}
cache-key: ${{ inputs.cache-key }}
components: llvm-tools

- run: rustup target add x86_64-pc-windows-msvc
shell: bash

- uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
with:
tool: ${{ inputs.tools != '' && format('{0},cargo-xwin', inputs.tools) || 'cargo-xwin' }}

# Downloading and unpacking the MSVC CRT/Windows SDK dominates cold wall
# time (~10 minutes); the unpacked result is immutable for a given manifest
# version, so cache it (combined restore + post-job save). Bump the key when
# bumping cargo-xwin.
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/cargo-xwin
key: cargo-xwin-msvc-17
Loading
Loading