fix(ext/node): align node:module behavior with Node#33482
Conversation
- process.config.variables.node_module_version: expose the ABI version (mirrors process.versions.modules) so consumers reading process.config can detect the supported native-addon ABI. Matches Node's lib/internal/process/per_thread.js. - 01_require.js getExportsForCircularRequire: skip the prototype-swap when module.exports is a Proxy. Matches the !isProxy(...) guard in Node's lib/internal/modules/cjs/loader.js so user-defined getPrototypeOf traps are not invoked during circular require warnings or cleanup. - 01_require.js Module constructor: define `this.exports` via ObjectDefineProperty (mirrors Node's setOwnProperty) so user-installed Object.prototype.exports setters are not triggered during module construction. - 01_require.js makeRequireFunction: define `require.main` via ObjectDefineProperty for the same reason. - 01_require.js createRequire: throw ERR_INVALID_ARG_VALUE (with the standard "must be a file URL object, file URL string, or absolute path string" reason) instead of a plain Error, matching Node's lib/internal/modules/cjs/loader.js. Enables four tests in the node_compat suite: - parallel/test-module-circular-dependency-warning.js - parallel/test-module-create-require.js - parallel/test-module-prototype-mutation.js - parallel/test-module-version.js
nathanwhitbot
left a comment
There was a problem hiding this comment.
Faithful port of Node:
!isProxy(module.exports)guard matcheslib/internal/modules/cjs/loader.js:1022and L1370.ObjectDefinePropertyforModule.exportsandrequire.mainmirrorssetOwnProperty()inlib/internal/util.js(called from L341 andhelpers.js:235).createRequireErrorstring matches Node verbatim;ERR_INVALID_ARG_VALUEis correct error class.process.config.variables.node_module_versionexposed as integer ABI version — passestest-module-version.jsassertions (Number.isInteger+ > 0).
LGTM.
nathanwhitbot
left a comment
There was a problem hiding this comment.
Reviewed against Node source. Each change matches:
process.config.variables.node_module_version(process.ts): Node exposes this fromconfig.gypi(build-time int fromconfigure.py→process.config). MirroringNumber(versions.modules)is correct —versions.modulesis the same NODE_MODULE_VERSION string.getExportsForCircularRequireproxy guard (01_require.js): exact match to Nodelib/internal/modules/cjs/loader.js:1021-1023—module.exports && !isProxy(module.exports) && ObjectGetPrototypeOf(...) === ObjectPrototype.core.isProxyis the right primitive (internal V8-level check, no trap invocation).Module._loadcleanup proxy guard: matches Nodelib/internal/modules/cjs/loader.js:1370-1372(!isProxy(module.exports) && ObjectGetPrototypeOf(module.exports) === CircularRequirePrototypeWarningProxy).ModuleconstructorObjectDefineProperty(this, "exports", ...): byte-for-byte equivalent to Node'ssetOwnProperty(this, 'exports', {})(lib/internal/util.js:754-762) —{ __proto__: null, configurable: true, enumerable: true, writable: true, value }is exactly whatsetOwnPropertyexpands to.makeRequireFunctionObjectDefineProperty(require, "main", ...): matches Nodelib/internal/modules/helpers.js:235(setOwnProperty(require, 'main', process.mainModule)). LocalmainModulehere is kept in sync withprocess.mainModuleat L769-770.createRequireERR_INVALID_ARG_VALUE: matches Nodelib/internal/modules/cjs/loader.js:2046-2051. NotecreateRequireErrorhere duplicates thekCreateRequireErrorconstant introduced by #33449 (now on main) — when this branch picks up main, those will collide; a quick rename should resolve.
Tests enabled (circular-dependency-warning, create-require, prototype-mutation, version) are alphabetically placed correctly.
LGTM modulo the createRequire/#33449 collision once main is merged in.
nathanwhitbot
left a comment
There was a problem hiding this comment.
Merge from main only. No PR-specific changes.
fibibot
left a comment
There was a problem hiding this comment.
LGTM. Five small alignment fixes, each mapped to a concrete Node behaviour:
!core.isProxy(module.exports)guard added to bothgetExportsForCircularRequireand theModule._loadcleanup branch — mirrors Node's!isProxy(...)guard inlib/internal/modules/cjs/loader.js. Prevents user-installedgetPrototypeOftraps from firing during the circular-require warning path.Moduleconstructor now usesObjectDefineProperty(this, "exports", { configurable, enumerable, value, writable, __proto__: null })instead ofthis.exports = {}. MirrorssetOwnProperty()inlib/internal/util.jsand is whatparallel/test-module-prototype-mutation.jsrequires (it installs anObject.prototype.exportssetter thatmustNotCall).- Same treatment for
require.maininmakeRequireFunction. Same test, same reasoning —Object.prototype.mainsetter must not fire. process.config.variables.node_module_version: Number(versions.modules)produces the integer ABI version (108from_process/process.ts:193).parallel/test-module-version.jsassertsObject.hasOwn(...),Number.isInteger(...), and> 0— all satisfied.
All test node_compat jobs (linux/macos/windows × x86_64/aarch64 × debug/release) are green, so the four enabled tests (test-module-circular-dependency-warning, test-module-create-require, test-module-prototype-mutation, test-module-version) really do pass. The two failing CI jobs (wpt release linux-x86_64, ci status) are the pre-existing CA-cert-expired infrastructure issue (certificate expired: ... not valid after 1717209917) hitting WebSocket tests across recent PRs — not introduced here.
nathanwhitbot
left a comment
There was a problem hiding this comment.
Merge from main only. No PR-specific changes.
nathanwhitbot
left a comment
There was a problem hiding this comment.
build debug windows-x86_64 failed at Upload artifact debug-windows-x86_64-denort step — cargo build succeeded, artifact upload aborted. Infra flake. Rerun needed. cc @nathanwhit
|
|
Head branch was pushed to by a user without write access
nathanwhitbot
left a comment
There was a problem hiding this comment.
Merge from main only. No PR-specific changes.
nathanwhitbot
left a comment
There was a problem hiding this comment.
Same regression as flagged on #33411 — test-webstream-structured-clone-no-leftovers.mjs (newly enabled in #33412) now fails after #33465 made structuredClone stricter. Affects linux-aarch64 and macos-aarch64 here. Unrelated to this PR's content. cc @nathanwhit
|
|
Same regression flagged on denoland#33411: test fails on aarch64 after denoland#33465 made structuredClone stricter for non-serializable Web types. Mark flaky on this branch too so the merge doesn't block CI.
Head branch was pushed to by a user without write access
…nd#33465 Flaky marker didn't help — DataCloneError fires deterministically on every retry after denoland#33465 made structuredClone stricter for non-serializable Web types. Ignore until the polyfill divergence is resolved.
fibibot
left a comment
There was a problem hiding this comment.
Still LGTM after 4e491520 + ab905061. The merge from main brought in #33428 and #33412 cleanly — the original 01_require.js / process.ts / config.jsonc hunks from the module-alignment work all survive against base. The two new commits just promote parallel/test-webstream-structured-clone-no-leftovers.mjs from flaky: true → { ignore: true, reason: ... }, citing the regression introduced by #33465. I confirmed the regression is real — the if (value[kNotSerializable]) throw check at ext/web/13_message_port.js runs unconditionally before the transfer-list path, so structuredClone(stream, { transfer: [stream] }) now throws even though stream is being transferred, not cloned. The ignore-with-reason is the right workaround for this PR; the fix belongs in a separate change to #33465's check.
| "parallel/test-webstorage-without-sqlite.js": {}, | ||
| "parallel/test-webstream-string-tag.js": {}, | ||
| "parallel/test-webstream-structured-clone-no-leftovers.mjs": {}, | ||
| "parallel/test-webstream-structured-clone-no-leftovers.mjs": { |
…denoland#33465" Reverts both the flaky and ignore workarounds per bartlomieju's request. The test entry returns to the default {} state.
|
Reverted per @bartlomieju's request — |
nathanwhitbot
left a comment
There was a problem hiding this comment.
test unit debug macos-aarch64 failed at "Run dsherret/rust-toolchain-file" step (23s) — rustup setup infra flake. Rerun needed. cc @nathanwhit
Several small alignment fixes in
ext/node/polyfills/01_require.jsandprocess.tsto match Node'slib/internal/modules/cjs/loader.js,lib/internal/modules/helpers.js, andlib/internal/process/per_thread.js.Changes
process.config.variables.node_module_version: expose the ABI version (mirrorsprocess.versions.modules) so consumers readingprocess.configcan detect the supported native-addon ABI.getExportsForCircularRequire/ Module._load cleanup: skip the prototype-swap whenmodule.exportsis a Proxy. Matches the!isProxy(...)guard in Node, so user-definedgetPrototypeOftraps are not invoked during circular-require warnings or cleanup.Moduleconstructor: definethis.exportsviaObjectDefineProperty(mirrorssetOwnProperty()in Node) so user-installedObject.prototype.exportssetters are not triggered during module construction.makeRequireFunction: definerequire.mainviaObjectDefinePropertyfor the same reason.createRequire: throwERR_INVALID_ARG_VALUEwith the standard"must be a file URL object, file URL string, or absolute path string"reason, instead of a plainError.Tests enabled
parallel/test-module-circular-dependency-warning.jsparallel/test-module-create-require.jsparallel/test-module-prototype-mutation.jsparallel/test-module-version.jsVerified no regressions across the configured
test-require-*andtest-module-*tests.