Skip to content

test(vite-plugin-rails): build determinism + add to JS matrix#4

Draft
andriytyurnikov wants to merge 3 commits intochore/ci-hardening-and-node-bumpfrom
test/build-stability-and-rails-matrix
Draft

test(vite-plugin-rails): build determinism + add to JS matrix#4
andriytyurnikov wants to merge 3 commits intochore/ci-hardening-and-node-bumpfrom
test/build-stability-and-rails-matrix

Conversation

@andriytyurnikov
Copy link
Copy Markdown
Member

Slice 4 of the ElMassimo#607 split. Stacks on #3 (CI hardening + Node 22) — base is set to that branch so the diff stays focused on the test-stability work. When #3 merges to main, retarget this PR's base to main and the diff becomes self-contained.

Drafted in fork — will retarget upstream once locally reviewed.

Why

vite-plugin-rails' tests/build.spec.ts pinned exact 8-char content hashes (e.g. assets/main-Ddvw3iap.js) in both the file-list assertion and the manifest snapshot. Any routine bump of Vite, Rolldown, Vue, or sass that changes a chunk by even a byte forces a manual hash regeneration even though the manifest shape is unchanged.

This brittleness is what made #3's first attempt at adding vite-plugin-rails to the JS matrix fail: Node 22 + 24 produce different chunk bytes than whoever last regenerated the snapshot, so the test failed on hash mismatch even though nothing structural had changed.

This PR fixes the brittleness, then adds vite-plugin-rails to the matrix.

Changes

Test stability — hash normalization

  • vite-plugin-rails/tests/build.spec.ts: introduce stripHash (regex on 8-char content-hash suffixes) and normalize helpers. The file-list assertion now compares hash-stripped names; the snapshot is normalized recursively, replacing integrity SRI values with the literal <integrity> placeholder.
  • vite-plugin-rails/tests/__snapshots__/build.spec.ts.snap regenerated against the new normalize pass.

The test now fails on structural changes (entry → file mapping, imports list, css list, etc.) but absorbs byte-level churn from upstream dependency updates.

Build determinism — pin NODE_ENV=production

  • vite-plugin-rails/example/package.json: npm run build now pins NODE_ENV=production.

vitest sets NODE_ENV=test by default, and build.spec.ts spawns npm run build inheriting that env. Vite respects an externally-set NODE_ENV — it doesn't overwrite it from --mode production — so the test-driven build was producing Vue's development bundle (with Object.freeze, __file injection of absolute paths, prop validators, dev-only warnings). Local npm run build (no vitest in the loop) shipped Vue's production bundle. The two outputs diverged by ~27 KB and produced different chunk hashes — the symptom previously misdiagnosed as cross-platform drift.

Pinning NODE_ENV=production in the build script makes the build match production semantics regardless of how it's invoked, so the test exercises the same code real users ship.

Add vite-plugin-rails to JS matrix

  • .github/workflows/js.yml: package matrix [vite-plugin-ruby, vite-plugin-rails]; fail-fast: false; job name and test step use ${{ matrix.package }}.

Commits

test(vite-plugin-rails): normalize chunk hashes for dep-bump stability
fix(vite-plugin-rails): pin example build to NODE_ENV=production
chore(ci): add vite-plugin-rails to JS test matrix

Test plan

  • CI passes for vite-plugin-rails on Node 22 + 24
  • CI still passes for vite-plugin-ruby on Node 22 + 24
  • Snapshot remains stable across a hypothetical Vite patch bump (verified locally by re-running the build with a different Vite minor and observing the test still passes)

build.spec.ts pinned exact 8-char content hashes (e.g. assets/main-Ddvw3iap.js)
in both the file-list assertion and the snapshot. Any routine bump of Vite,
Rolldown, Vue, or sass that changes a chunk by even a byte forces a manual
hash regeneration even though the manifest shape is unchanged.

Strip the 8-char hash from filenames before asserting, and replace the
sub-resource integrity value with a `<integrity>` placeholder in the
snapshot. The test now fails on structural changes (entry → file mapping,
imports list, css list, etc.) but absorbs byte-level churn from upstream
dependency updates.
vitest sets NODE_ENV=test by default, and build.spec.ts spawns
`npm run build` inheriting that env. Vite respects an externally-set
NODE_ENV — it doesn't overwrite it from --mode production — so the
test-driven build was producing Vue's *development* bundle (Object.freeze,
__file injection with absolute paths, prop validators, dev-only warnings).

Local `npm run build` (no vitest in the loop) shipped Vue's production
bundle. The two outputs diverged by ~27 KB and produced different chunk
hashes — the symptom we previously misdiagnosed as cross-platform drift.

Setting NODE_ENV=production in the build script makes the build match
production semantics regardless of how it's invoked, so the test exercises
the same code real users ship.
Now that the build snapshot strips chunk hashes and the example build
is pinned to NODE_ENV=production, vite-plugin-rails' tests are stable
enough across Node versions and dep bumps to run in CI.

- Matrix: package: [vite-plugin-ruby, vite-plugin-rails].
- name: matrix package, so each job is named for what it tests.
- fail-fast: false, so a failure in one matrix cell doesn't cancel
  siblings.
- Test step uses ${{ matrix.package }}.
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.

1 participant