Skip to content

feat: update @vercel/webpack-asset-relocator-loader to 1.10.3 - #1342

Merged
styfle merged 3 commits into
mainfrom
bump-webpack-asset-relocator-dependency
Aug 13, 2026
Merged

feat: update @vercel/webpack-asset-relocator-loader to 1.10.3#1342
styfle merged 3 commits into
mainfrom
bump-webpack-asset-relocator-dependency

Conversation

@styfle

@styfle styfle commented Aug 10, 2026

Copy link
Copy Markdown
Member

Bumps @vercel/webpack-asset-relocator-loader from 1.7.3 to 1.10.3 (latest).

What's in the bump

Version Change
1.7.4 Use a computed node-gyp-build path (#185)
1.7.5 Fix __nccwpck_require__ is not defined regression (#195)
1.8.0 Support node:path as an alias of path (#197)
1.9.0 Load native addons from the prebuilds directory (#198)
1.9.1 Support the packaging format of sharp v0.34.x (#199)
1.10.0 Ship the loader as source instead of a prebuilt bundle (#200)
1.10.2 Packaging/CI fixes
1.10.3 Percent-decode the ESM asset base (#220)

Because 1.10.0 publishes src/ rather than an ncc-built dist/, the loader's previously bundled dependencies are now real transitive dependencies — that accounts for the lockfile growth. The relocate-loader build emits no new assets, and dist/ncc/loaders/relocate-loader.js.cache.js actually shrinks slightly (499.37KB → 492.13KB).

Why the unit fixtures change

The loader now registers the asset base through a webpack RuntimeModule instead of the deprecated mainTemplate.hooks.requireExtensions. Two consequences show up in test/unit/*/output*.js:

  1. The block is labelled /* webpack/runtime/asset-relocator-loader */ instead of /* webpack/runtime/compat */, and is emitted earlier in the runtime.
  2. Bundles that never reference __nccwpck_require__ no longer carry the dead if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = ... assignment — the runtime module is only added when RuntimeGlobals.require is actually in the tree. The guard was always false in those bundles, so this is dead-code removal, not a behaviour change.

I specifically checked that the second point is not a regression. __nccwpck_require__.ab is still emitted wherever it is referenced, verified by hand for CJS, ESM, and concatenated-TypeScript builds that relocate an asset, and by the asset-heavy integration tests (sharp, canvas, ffmpeg, oracledb, leveldown, binary-require), which all pass.

The Windows fix now comes from upstream

The first push was green on Linux and macOS but failed on all three Windows jobs:

Cannot find module 'C:/Users/RUNNER%7E1/AppData/Local/Temp/.../runtime.json'

The relocator derives the ESM asset base from new URL('.', import.meta.url).pathname, which is percent-encoded. The Windows runner's temp dir is an 8.3 short name (RUNNER~1), so ~ became %7E. This is not platform-specific — paths containing spaces break identically everywhere:

$ ncc build input.mjs -o '/tmp/out dir'
Cannot find module '/tmp/out%20dir/runtime.json'

That expression is byte-identical in 1.7.3 and 1.10.2, so the bug is pre-existing. It was simply unreachable for this fixture before: 1.7.3 had no node: specifier support, so import { resolve } from "node:path" was not statically analyzable and runtime.json was never relocated. 1.8.0 added node:path as an alias of path, so the reference is now resolved, emitted as an asset, and rewritten to __nccwpck_require__.ab + ... — which is where the latent bug surfaces.

This PR originally carried the one-line fix (wrap the pathname in decodeURIComponent) as a patchedDependencies entry. That patch has now shipped upstream in 1.10.3, so this PR bumps to 1.10.3 and deletes:

  • patches/@vercel__webpack-asset-relocator-loader@1.10.2.patch
  • the matching patchedDependencies entry in pnpm-workspace.yaml (that file is now identical to main again)

1.10.3 is 1.10.2 plus exactly that change — diffing the two published tarballs shows only the version field and the one requireBase line (plus an explanatory comment). Confirmed empirically: update-fixtures.sh regenerates every test/unit/*/output*.js with zero drift against the patched-1.10.2 fixtures already in this PR.

Also fixed

update-fixtures.sh invoked node node_modules/.bin/jest for the coverage pass. Under pnpm that path is a shell shim rather than a JS entry point, so the step crashed with SyntaxError: missing ) after argument list and never regenerated any output-coverage.js. Switched both invocations to node_modules/jest/bin/jest.js, matching the test script in package.json.

That broken step is why two output-coverage.js fixtures had drifted on main before this PR (import-meta-cjs and ts-json-resolve). Their regenerated output here therefore contains one small change each that is unrelated to the relocator. The drift went unnoticed because test/integration.test.js calls process.exit(0) in afterAll under coverage, so pnpm test-coverage exits 0 even when test/unit.test.js fails.

Testing

Re-run on Linux / Node 22.22.2 after the bump to 1.10.3:

  • pnpm test121 passed, 1 failed. The only failure is binary-require.js (Cannot find module './hello.node'), because pnpm build-test-binary needs a C++ toolchain that the machine used for this re-run does not have, so test/integration/hello.node was never produced. CI installs node-gyp and builds it, and this test passed on the previous push.
  • jest --coverage --globals '{"coverage":true}' test/unit28 passed
  • bash update-fixtures.sh — regenerates all fixtures, git status clean afterwards
  • pnpm install --frozen-lockfile — succeeds with no config override

The %20/%7E case is now covered end-to-end rather than by hand: running the create-require-runtime integration test with TMPDIR="/tmp/tmp dir~short" reproduces the Windows failure mode on Linux. It passes on 1.10.3, and to confirm the check is actually sensitive I reverted decodeURIComponent in the built loader and watched it fail with exactly the CI error:

Cannot find module '/tmp/tmp%20dir%7Eshort/<hash>/runtime.json'

Two pre-existing quirks I ran into and confirmed also reproduce on main, so they are not introduced here and are left alone:

  • Under --runInBand, if test/watcher.test.js runs before test/unit.test.js in the same process, a unit test fails with TypeError: Cannot read properties of undefined (reading 'then') inside webpack's FileSystemInfo. Reproduced at 1.7.3.
  • The stale coverage fixtures described above.

One thing to flag

1.10.3 was published a few minutes before this update was pushed, and pnpm-workspace.yaml sets minimumReleaseAge: 2880 (48h), so a fresh resolution of this version is blocked today. I generated the lockfile with a one-off --config.minimumReleaseAge=0 and deliberately did not add a minimumReleaseAgeExclude entry, so the repo's supply-chain policy is unchanged. CI is unaffected: both install steps in ci.yml use pnpm install --frozen-lockfile, which skips resolution and installs 1.10.3 from the lockfile (verified locally — it succeeds with no override). Once 1.10.3 is 48h old the constraint stops mattering entirely — hold this PR until then if you'd rather the policy not be bypassed at all.

Related

  • Fixes TypeError with BigInt data types #1307

    Confirmed this bump does address it. That TypeError: Cannot mix BigInt and other types originates in the relocator's static evaluator (relocate-loader.js.cache.js), whose BinaryExpression handler is unguarded in 1.7.3. 1.10.x wraps it in a try, with a comment naming that exact error, and adds the matching guard for the UnaryExpression BigInt case.

Bumps the asset relocator loader from 1.7.3 to 1.10.2, picking up:

- 1.7.4 — use a computed node-gyp-build path (#185)
- 1.7.5 — fix `__nccwpck_require__ is not defined` regression (#195)
- 1.8.0 — support `node:path` as an alias of `path` (#197)
- 1.9.0 — load native addons from the `prebuilds` directory (#198)
- 1.9.1 — support the packaging format of sharp v0.34.x (#199)
- 1.10.0 — ship the loader as source instead of a prebuilt bundle (#200)

Since 1.10.0 publishes `src/` rather than an ncc-built `dist/`, the
loader's former bundled dependencies are now real transitive deps, which
is why the lockfile grows. The relocate-loader build emits no new assets.

Unit fixtures are regenerated because the loader now registers its asset
base via a webpack RuntimeModule instead of the deprecated
`mainTemplate.hooks.requireExtensions`:

- the block is labelled `/* webpack/runtime/asset-relocator-loader */`
  instead of `/* webpack/runtime/compat */`, and is emitted earlier
- bundles that never reference `__nccwpck_require__` no longer carry a
  dead `if (typeof __nccwpck_require__ !== 'undefined')` assignment

Verified that `__nccwpck_require__.ab` is still emitted wherever it is
referenced, for CJS, ESM and concatenated TypeScript builds, and that the
asset-heavy integration tests (sharp, canvas, ffmpeg, oracledb, leveldown,
binary-require) still pass.

Also fixes the coverage step of update-fixtures.sh, which invoked
`node node_modules/.bin/jest` — a shell shim under pnpm, not a JS entry
point — so it crashed with a SyntaxError before regenerating any
output-coverage.js fixtures.

Co-Authored-By: Steven <229881+styfle@users.noreply.github.com>
@socket-security

socket-security Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​vercel/​webpack-asset-relocator-loader@​1.10.39810010092100

View full report

The Windows CI jobs failed on `ncc run create-require-runtime.mjs` with:

  Cannot find module 'C:/Users/RUNNER%7E1/AppData/Local/Temp/.../runtime.json'

The relocator derives the ESM asset base from
`new URL('.', import.meta.url).pathname`, which is percent-encoded, so any
output directory containing a character that needs escaping produces a
broken path. The Windows runner's temp dir is an 8.3 short name
(`RUNNER~1`), so `~` became `%7E`. Paths containing spaces break the same
way on every platform:

  $ ncc build input.mjs -o '/tmp/out dir'
  Cannot find module '/tmp/out%20dir/runtime.json'

This expression is byte-identical in 1.7.3 and 1.10.2, so the bug is not
new. It was previously unreachable for this fixture because 1.7.3 had no
`node:` specifier support: `import { resolve } from "node:path"` was not
statically analyzable, so `runtime.json` was never relocated. 1.8.0 added
`node:path` as an alias of `path`, so the reference is now resolved,
emitted as an asset, and rewritten to `__nccwpck_require__.ab + ...` —
which is where the latent bug surfaces.

Patch the loader to wrap the pathname in `decodeURIComponent`. Slicing
still happens after decoding, and it only trims a leading `/` on Windows
drive paths and the trailing `/`, neither of which decoding can alter.
The CJS branch uses `__dirname` and is untouched.

This uses pnpm's patchedDependencies, as the repo already does for
unfetch. It should be dropped once the fix is released upstream in
vercel/webpack-asset-relocator-loader.

Co-Authored-By: Steven <229881+styfle@users.noreply.github.com>
@styfle
styfle requested a review from mischnic August 13, 2026 01:05
styfle added a commit to vercel/webpack-asset-relocator-loader that referenced this pull request Aug 13, 2026
ESM builds derive `__webpack_require__.ab` from
`new URL('.', import.meta.url).pathname`, which is percent-encoded. Any
output directory whose name contains an escaped character therefore
produced an asset base that does not exist on disk:

    $ ncc build input.mjs -o '/tmp/out dir'
    Cannot find module '/tmp/out%20dir/runtime.json'

Spaces (`%20`), tildes (`%7E`) and non-ASCII characters (`%C3%A4`) all
hit this. It is not platform-specific, but Windows runs into it without
trying, because the GitHub Actions temp directory is an 8.3 short name
(`RUNNER~1` -> `RUNNER%7E1`).

Fixed by decoding the pathname before slicing. Slicing still happens
after decoding, and it only trims a leading `/` on Windows drive paths
and the trailing `/`, neither of which decoding can alter. The CJS
branch uses `__dirname` and is untouched.

vercel/ncc#1342 currently carries this exact change as a
`patchedDependencies` entry; it can be dropped once this ships.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Co-Authored-By: Steven <229881+styfle@users.noreply.github.com>
styfle added a commit to vercel/webpack-asset-relocator-loader that referenced this pull request Aug 13, 2026
## Why ncc needs a `.patch` today

[vercel/ncc#1342](vercel/ncc#1342) bumps this
loader to 1.10.2 and has to carry
`patches/@vercel__webpack-asset-relocator-loader@1.10.2.patch` because
of a latent bug here. This PR is that fix, upstreamed with a test, so
the patch can be dropped.

### The bug

ESM builds derive `__webpack_require__.ab` from `new URL('.',
import.meta.url).pathname`
([`src/asset-relocator.js#L345`](https://github.com/vercel/webpack-asset-relocator-loader/blob/main/src/asset-relocator.js#L345)),
and that pathname is **percent-encoded**. Any output directory whose
name contains an escaped character yields an asset base that does not
exist on disk:

```console
$ ncc build input.mjs -o '/tmp/out dir'
$ node '/tmp/out dir/index.js'
Error: ENOENT: no such file or directory, open '/tmp/out%20dir/runtime.json'
```

Spaces (`%20`), tildes (`%7E`) and non-ASCII characters (`%C3%A4`) all
trigger it. It is **not** platform-specific, but Windows hits it without
trying: the GitHub Actions temp directory is an 8.3 short name, so
`RUNNER~1` becomes `RUNNER%7E1`. That is exactly how ncc#1342 found it —
green on Linux and macOS, red on all three Windows jobs.

### Why it only surfaced now

The expression is byte-identical in 1.7.3 and 1.10.2, so the bug is
pre-existing — ncc's fixture just could not reach it. 1.7.3 had no
`node:` specifier support, so `import { resolve } from "node:path"` was
not statically analyzable and the asset was never relocated.
[#197](#197)
added `node:path` as an alias of `path` in 1.8.0, so the reference now
resolves, gets emitted as an asset, and is rewritten to
`__nccwpck_require__.ab + ...` — which is where the latent bug shows up.

## The fix

```diff
-new URL('.', import.meta.url).pathname.slice(...)
+decodeURIComponent(new URL('.', import.meta.url).pathname).slice(...)
```

Slicing still happens after decoding, and it only trims a leading `/` on
Windows drive paths and the trailing `/`, neither of which decoding can
alter. The CJS branch uses `__dirname` and is untouched.

This is **byte-identical** to the replacement line in ncc#1342's patch
file, so that PR can delete `patches/` and the `patchedDependencies`
entry with no other change once this ships.

## Tests

New `test/esm-asset-base.test.js` builds an ESM bundle that reads an
asset relative to `__dirname`, writes it to a real temp directory, and
**executes the output with `node`** — so it asserts the asset actually
loads, not just that the emitted string looks right. Three output
directories, one per escape class:

| Directory | Encodes to | Before | After |
| --- | --- | --- | --- |
| `plain` | — | ✅ pass | ✅ pass |
| `out ~dir` | `out%20%7Edir` | ❌ `ENOENT .../out%20%7Edir/asset.txt` |
✅ pass |
| `ütf8` | `%C3%BCtf8` | ❌ `ENOENT .../%C3%BCtf8/asset.txt` | ✅ pass |

The `plain` case is the control: it passes either way, showing the
decode does not regress ordinary paths.

`test/unit/esm-dirname/output{,-coverage}.js` are regenerated for the
one changed runtime line.

### One extra commit-adjacent change

Adding a third test file perturbs jest's suite ordering, which exposed a
**pre-existing** cwd leak: `test/project.test.js` calls
`process.chdir()` and never restores it, and `test/index.test.js`
resolves `filterAssetBase: path.resolve('test')` against the cwd.
Whenever the two share a process with `project` first, 69 unit tests
fail. Reproducible on stock `main`:

```console
$ jest --runInBand --testSequencer ./seq.js   # forces project.test.js first
PASS test/project.test.js
FAIL test/index.test.js
Tests: 69 failed, 16 passed, 85 total
```

Rather than let my new file take the blame for a flaky run,
`test/project.test.js` now restores the cwd in `afterAll`, making the
suite order-independent. My own test uses `__dirname`-absolute paths
throughout and is unaffected either way.

### Results

Green on all six CI jobs — Node 22/24 × ubuntu / macOS / **windows** —
at **88 passed, 3 suites** (baseline on `main` is 85).

Windows matters here: it is the platform that surfaced the bug in
ncc#1342, and the two Windows jobs now exercise all three cases against
a real 8.3 short-name temp path.

Locally on Node 22.22.2 / Linux, also green in every run mode, including
with jest's ordering forced against it:

- `yarn test` — 88 passed
- `yarn test --runInBand`, both natural and forced `project`-first order
— 88 passed
- `yarn test-coverage` — 88 passed, thresholds met

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Steven <229881+styfle@users.noreply.github.com>
1.10.3 ships the percent-decoding fix for the ESM asset base upstream
(vercel/webpack-asset-relocator-loader#220), so the local patch added in
the previous commit is no longer needed and is removed here.

1.10.3 is otherwise byte-identical to 1.10.2 plus that one-line change,
so no test fixtures move: `update-fixtures.sh` regenerates every
`test/unit/*/output*.js` with no drift.

Co-Authored-By: Steven <229881+styfle@users.noreply.github.com>
@styfle styfle changed the title feat: update @vercel/webpack-asset-relocator-loader to 1.10.2 feat: update @vercel/webpack-asset-relocator-loader to 1.10.3 Aug 13, 2026
@styfle
styfle enabled auto-merge (squash) August 13, 2026 02:37
@styfle
styfle merged commit cb1f1f0 into main Aug 13, 2026
22 of 23 checks passed
@styfle
styfle deleted the bump-webpack-asset-relocator-dependency branch August 13, 2026 03:13
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.45.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeError with BigInt data types

2 participants