Make Rspack output independent of the checkout path

What does this MR do and why?

Makes the production Rspack build give the same output wherever the checkout is. Today, building the same tree in two directories gives different Rspack file names and contents. The build is not reproducible, and the Nix build of the assets in !262215 can't match the file names of build-assets-image.

Two causes, one commit each:

  1. Keep checkout paths out of Vue 3 lane imports. config/vue3migration/plugins/rspack_loader.js rewrote each ?vue3 import to the target's absolute path. Rspack sizes a module by the loader's output, and splitChunks places modules by size (minSize: 150000), so a longer checkout path moved modules between chunks. The loader now writes the path relative to the importing file. It resolves to the same file and query, so all importers still share one ?vue3 module. A new spec, spec/frontend/config/vue3migration/plugins/rspack_loader_spec.mjs, checks both.
  2. Mangle Rspack output without char frequency. Rspack minifies the runtime while its chunk table still holds provisional hashes; the real content hashes replace them afterwards. SWC picks short variable names by how often each character appears, and it counts those hashes too. With source maps on, the provisional hashes depend on the absolute source paths, so the runtime's variable names, and with them its file name, change with the directory (https://github.com/web-infra-dev/rspack/issues/14089). mangle.disableCharFreq makes SWC pick names in a fixed order. The minimizer list is otherwise Rspack's default (SwcJsMinimizerRspackPlugin, LightningCssMinimizerRspackPlugin).

webpack is unchanged. The Rspack output changes once, to the path-independent layout.

Size, Rspack JS of tree 3c50039f built in /builds/gitlab-org/gitlab without source maps, gzip level 9:

Build Raw (B) Gzip (B) Gzip vs before
Before 156,361,111 42,145,298
Commit 1 156,533,988 42,196,325 +0.12%
Commits 1 and 2 156,534,008 42,299,520 +0.37%

Commit 1's change comes from the new chunk layout; commit 2's from the fixed name order.

References

How to set up and validate locally

  1. Run the loader spec: yarn vitest:vue3migration --run. Steps 2 to 5 check the whole build.
  2. Install and build the islands once: NODE_ENV=production yarn install --frozen-lockfile, then scripts/build_frontend_islands.
  3. Build in the checkout and keep the output:
    NODE_ENV=production FE_SOURCEMAPS=true SKIP_FRONTEND_ISLANDS_BUILD=true yarn run rspack-prod
    mv public/assets/webpack /tmp/rspack-a
  4. Copy the checkout, node_modules included, to a path of a different length (cp -a), run the same build there, and move its public/assets/webpack to /tmp/rspack-b.
  5. diff -rq /tmp/rspack-a /tmp/rspack-b prints nothing. On master the names differ: 1079 of 5568 top-level files for a 57- vs a 107-character path with source maps.
Validation so far
  • This MR's CI: pipeline 2954747770 passed, including test-vue3migration-tooling (the new spec), the four compile-production-assets jobs, Jest for Vue 2 and Vue 3, predictive RSpec and e2e:test-on-cng. bundle-size-review (allowed to fail) failed on a webpack chunk-name conflict that master has had since ee4b06d1dc; webpack doesn't use this loader.
  • Nix comparison: pipeline 2952009663 of !262215 carries the same loader and Rspack config. Its Nix build, in a random /nix/var/nix/builds/... directory, has the same 1696 Rspack file names and 940 entrypoints as a fresh compile-production-assets-rspack compile in /builds/gitlab-org/gitlab (both runtime.fa5b7cab.bundle.js). Before these commits, 234 names differed (2950755954).
  • Linux (node:22.23.1-bookworm, arm64), tree 3c50039f with both commits: byte-identical output in /builds/gitlab-org/gitlab, /build/source and /nix/var/nix/builds/nix-12015-2632109856/source, with source maps (10,531 files) and without (7,859 files).
  • Before the change, the same container reproduces the mismatch name for name. In /builds/gitlab-org/gitlab it gives the 1692 Rspack names of gitlab-assets-ee:3c50039ff30f7a59985013e317bb78559e45740f (compile-production-assets-rspack), and in the Nix build directory the 1692 names of gitlab-assets-ee-nix:3c50039ff30f7a59985013e317bb78559e45740f. 237 names differ between them.
  • Same module graph: 10,293 module identifiers before and after commit 1, 1705 of them ?vue3 modules.
  • macOS arm64: byte-identical output at two paths (57 and 107 characters).
  • Spec: the 15 tests of rspack_loader_spec.mjs pass, and 11 of them fail against master's loader. yarn vitest:vue3migration: 193 tests pass. ESLint and Prettier are clean.
  • Not validated yet: loading a Vue 3 page from the Rspack build in a browser. The module graph is unchanged, but the chunks that carry it are not. e2e:test-on-cng serves the webpack build, because rspack_production_assets is off by default.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Alessio Caiazza

Merge request reports

Loading
Loading