Latest Results
Fix deterministic content hashes when source maps contain build-local paths
Rspack’s code generation hash currently hashes each generated `Source` structurally. For
`SourceMapSource`, that structural hash includes the full source map, including path-like fields
such as `sources`, `sourceRoot`, and `file`. In sandboxed or remote-execution CI environments,
those fields can contain absolute worker paths like `/mnt/engflow/worker/work/N/exec/...`, where
`N` varies between otherwise identical builds.
Those path differences do not affect emitted JavaScript bytes, but they feed into per-module
codegen hashes. The tainted module hashes then feed chunk content hashes, causing unstable asset
filenames and reducing cross-build asset reuse.
This change makes codegen hashing deterministic for that case by:
- sorting codegen `SourceType` entries before hashing, avoiding hash-map iteration-order instability
- hashing only content-relevant source-map fields for `SourceMapSource`;
- deliberately excluding path-like source-map metadata from the source hash while preserving it in
emitted source maps;
- adding a regression test proving identical emitted code with different sandbox source-map paths
produces the same source hash.
This keeps debug/source-map output unchanged, while ensuring content hashes reflect emitted content
and stable source-map content rather than ephemeral build-machine paths.cellison-figma:ce/deterministic-sourcemap-codegen-hash fix(core): harden the beforeLoaders round-trip
Three problems in the JS conversion layer, all found by review:
- An entry a tap rebuilt from scratch (`{ ...loaders[0], options }`) drops
the non-enumerable snapshot but keeps its `ident`, so the guard against
reusing a configured ident did not fire and the rule's shared options
object was overwritten for every other module it matched. The set of
configured idents is now collected before the taps run and checked
against that, instead of against the entry's own snapshot.
- `JsLoaderItem::from(&Arc<dyn Loader>)` derives its fields by splitting
the loader identifier on `'|'`, which drops the loader type entirely for
JS loaders and truncates the path of any identifier containing a `'|'`.
The hook now passes a `JsBeforeLoadersLoaderItem` built from
`Loader::r#type()` and the module's loader options instead, so `type` is
accurate and nothing is parsed out of the identifier.
- `Rule.use[].cache` and `Rule.use[].parallel` were silently dropped from
any loader a tap rewrote; both are carried over from the snapshot now.
A generated ident no longer contains a `'|'` either, since module
identifiers embed one and `module.loaders` still goes through the splitting
conversion.
The test gains the rebuilt-entry case, which reproduced the first problem,
a `finishModules` assertion that the rule's options object survived, and a
`.cjs` loader that reports `type: "commonjs"`.
Documents that a tap should replace `options` rather than mutate it in
place: the object is shared with every module the rule matched, and a
mutation is invisible to the cache key the loader was resolved with.kakiuwang-ui:feat/normal-module-before-loaders Latest Branches
0%
cellison-figma:ce/deterministic-sourcemap-codegen-hash 0%
codex/erase-js-tap-execution-types +3%
seal/swc-next-side-effects-declarations © 2026 CodSpeed Technology