You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Node loads `data:` modules directly from their URL payload. Supported ESM media types include `text/javascript`, `application/json`, and `application/wasm` ([Node ESM documentation](https://github.com/nodejs/node/blob/v22.9.0/doc/api/esm.md#L219-L241)).
4
+
5
+
## Query and fragment handling
6
+
7
+
Before Node 22.9.0, the ESM loader parsed a data module from `url.pathname`, so URL query and fragment metadata were outside the module body ([v20.20.2 loader](https://github.com/nodejs/node/blob/v20.20.2/lib/internal/modules/esm/load.js#L31-L73)). Node 22.9.0 adopted the Fetch-standard data-URL processor ([backport](https://github.com/nodejs/node/commit/40ba89e4524b6593badbdfa9e716c0523a0fa234)); it serializes the URL with only the fragment excluded, then decodes the remaining body ([v22.9.0 processor](https://github.com/nodejs/node/blob/v22.9.0/lib/internal/data_url.js#L35-L96)).
8
+
9
+
Appending a query to a base64 data URL therefore changes its encoded body on Node 22.9.0 and newer. For example, `data:text/javascript;base64,Y29uc29sZS5sb2coMSk=?namespace=private` is not valid base64. A fragment leaves the payload unchanged because the processor excludes it.
10
+
11
+
## Loader implication
12
+
13
+
Loader metadata that must survive into imports from a `data:` module belongs in its fragment, not a query parameter. A `data:` module can import absolute URLs, so preserving the metadata is necessary for a hook to continue handling a TypeScript child module. Relative imports remain unsupported because `data:` is not a special URL scheme.
Dependency classification must inspect `new URL(parentURL).pathname`, not a substring of the serialized URL ([ESM resolver](../../src/esm/hook/resolve.ts)). URL queries and fragments are not filesystem location. A local parent URL containing `?source=/node_modules/` must retain local tsconfig path behavior, while a real dependency pathname must not receive the consumer's aliases.
55
55
56
+
## Namespaced URLs
57
+
58
+
`tsImport()` isolates each registration with a namespace. File URLs carry that namespace in their query, while `data:` URLs carry it in a trailing fragment parameter so Node does not include the metadata in the data payload. Data URLs bypass file-oriented resolver logic because their payload can contain query and directory-like text. The trailing marker is removed only when it matches the active registration, leaving user fragments opaque. It lets absolute TypeScript imports from a `data:` module retain the registration namespace ([Node contract](../node/data-url-modules.md), [resolver](../../src/esm/hook/resolve.ts), [lookup](../../src/esm/hook/utils.ts)).
59
+
56
60
## Required test matrix
57
61
58
62
Before changing resolver code, cover each policy row through every execution boundary:
@@ -65,6 +69,7 @@ Before changing resolver code, cover each policy row through every execution bou
65
69
6. Parent URL classification with no query, a `/node_modules/` query, and a real `node_modules` pathname.
66
70
7. Dependency subpaths with conditional root exports, package imports, scoped nested mains, an exact main before extension fallbacks, a missing main that falls through to index, a main directory, and an all-miss native-error comparison.
67
71
8. A relative dependency directory beneath root exports, so the package-subpath boundary cannot block ordinary index fallback.
72
+
9. A namespaced `tsImport()` graph containing base64 and raw `data:` modules, an opaque user fragment, and an absolute TypeScript child across async and sync hooks.
0 commit comments