| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 937e9bb commit d302cb3
21 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -49,7 +49,10 @@ Otherwise, the file is loaded using the CommonJS module loader. See | |||
| 49 | 49 | When loading, the [ES module loader][Modules loaders] loads the program | |
| 50 | 50 | entry point, the `node` command will accept as input only files with `.js`, | |
| 51 | 51 | `.mjs`, `.cjs` or `.wasm` extensions; and with no extension when | |
| 52 | - [`--experimental-default-type=module`][] is passed. | ||
| 52 | + [`--experimental-default-type=module`][] is passed. With the following flags, | ||
| 53 | + additional file extensions are enabled: | ||
| 54 | + | ||
| 55 | + * [`--experimental-addon-modules`][] for files with `.node` extension. | ||
| 53 | 56 | ||
| 54 | 57 | ## Options | |
| 55 | 58 | ||
@@ -895,6 +898,16 @@ and `"` are usable. | |||
| 895 | 898 | It is possible to run code containing inline types unless the | |
| 896 | 899 | [`--no-experimental-strip-types`][] flag is provided. | |
| 897 | 900 | ||
| 901 | + ### `--experimental-addon-modules` | ||
| 902 | + | ||
| 903 | + <!-- YAML | ||
| 904 | + added: REPLACEME | ||
| 905 | + --> | ||
| 906 | + | ||
| 907 | + > Stability: 1.0 - Early development | ||
| 908 | + | ||
| 909 | + Enable experimental import support for `.node` addons. | ||
| 910 | + | ||
| 898 | 911 | ### `--experimental-async-context-frame` | |
| 899 | 912 | ||
| 900 | 913 | <!-- YAML | |
@@ -3330,6 +3343,7 @@ one is included in the list below. | |||
| 3330 | 3343 | * `--enable-source-maps` | |
| 3331 | 3344 | * `--entry-url` | |
| 3332 | 3345 | * `--experimental-abortcontroller` | |
| 3346 | + * `--experimental-addon-modules` | ||
| 3333 | 3347 | * `--experimental-async-context-frame` | |
| 3334 | 3348 | * `--experimental-default-type` | |
| 3335 | 3349 | * `--experimental-detect-module` | |
@@ -3926,6 +3940,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 | |||
| 3926 | 3940 | [`--disable-sigusr1`]: #--disable-sigusr1 | |
| 3927 | 3941 | [`--env-file-if-exists`]: #--env-file-if-existsfile | |
| 3928 | 3942 | [`--env-file`]: #--env-filefile | |
| 3943 | + [`--experimental-addon-modules`]: #--experimental-addon-modules | ||
| 3929 | 3944 | [`--experimental-default-type=module`]: #--experimental-default-typetype | |
| 3930 | 3945 | [`--experimental-sea-config`]: single-executable-applications.md#generating-single-executable-preparation-blobs | |
| 3931 | 3946 | [`--heap-prof-dir`]: #--heap-prof-dir | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1129,18 +1129,21 @@ _isImports_, _conditions_) | |||
| 1129 | 1129 | > 5. If _url_ ends in | |
| 1130 | 1130 | > _".wasm"_, then | |
| 1131 | 1131 | > 1. Return _"wasm"_. | |
| 1132 | - > 6. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_url_). | ||
| 1133 | - > 7. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_). | ||
| 1134 | - > 8. Let _packageType_ be **null**. | ||
| 1135 | - > 9. If _pjson?.type_ is _"module"_ or _"commonjs"_, then | ||
| 1136 | - > 1. Set _packageType_ to _pjson.type_. | ||
| 1137 | - > 10. If _url_ ends in _".js"_, then | ||
| 1132 | + > 6. If `--experimental-addon-modules` is enabled and _url_ ends in | ||
| 1133 | + > _".node"_, then | ||
| 1134 | + > 1. Return _"addon"_. | ||
| 1135 | + > 7. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_url_). | ||
| 1136 | + > 8. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_). | ||
| 1137 | + > 9. Let _packageType_ be **null**. | ||
| 1138 | + > 10. If _pjson?.type_ is _"module"_ or _"commonjs"_, then | ||
| 1139 | + > 1. Set _packageType_ to _pjson.type_. | ||
| 1140 | + > 11. If _url_ ends in _".js"_, then | ||
| 1138 | 1141 | > 1. If _packageType_ is not **null**, then | |
| 1139 | 1142 | > 1. Return _packageType_. | |
| 1140 | 1143 | > 2. If the result of **DETECT\_MODULE\_SYNTAX**(_source_) is true, then | |
| 1141 | 1144 | > 1. Return _"module"_. | |
| 1142 | 1145 | > 3. Return _"commonjs"_. | |
| 1143 | - > 11. If _url_ does not have any extension, then | ||
| 1146 | + > 12. If _url_ does not have any extension, then | ||
| 1144 | 1147 | > 1. If _packageType_ is _"module"_ and the file at _url_ contains the | |
| 1145 | 1148 | > header for a WebAssembly module, then | |
| 1146 | 1149 | > 1. Return _"wasm"_. | |
@@ -1149,7 +1152,7 @@ _isImports_, _conditions_) | |||
| 1149 | 1152 | > 3. If the result of **DETECT\_MODULE\_SYNTAX**(_source_) is true, then | |
| 1150 | 1153 | > 1. Return _"module"_. | |
| 1151 | 1154 | > 4. Return _"commonjs"_. | |
| 1152 | - > 12. Return **undefined** (will throw during load phase). | ||
| 1155 | + > 13. Return **undefined** (will throw during load phase). | ||
| 1153 | 1156 | ||
| 1154 | 1157 | **LOOKUP\_PACKAGE\_SCOPE**(_url_) | |
| 1155 | 1158 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1326,6 +1326,7 @@ The final value of `format` must be one of the following: | |||
| 1326 | 1326 | ||
| 1327 | 1327 | | `format` | Description | Acceptable types for `source` returned by `load` | | |
| 1328 | 1328 | | ----------------------- | ----------------------------------------------------- | -------------------------------------------------- | | |
| 1329 | + | `'addon'` | Load a Node.js addon | {null} | | ||
| 1329 | 1330 | | `'builtin'` | Load a Node.js builtin module | {null} | | |
| 1330 | 1331 | | `'commonjs-typescript'` | Load a Node.js CommonJS module with TypeScript syntax | {string\|ArrayBuffer\|TypedArray\|null\|undefined} | | |
| 1331 | 1332 | | `'commonjs'` | Load a Node.js CommonJS module | {string\|ArrayBuffer\|TypedArray\|null\|undefined} | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -121,6 +121,9 @@ | |||
| 121 | 121 | "entry-url": { | |
| 122 | 122 | "type": "boolean" | |
| 123 | 123 | }, | |
| 124 | + "experimental-addon-modules": { | ||
| 125 | + "type": "boolean" | ||
| 126 | + }, | ||
| 124 | 127 | "experimental-async-context-frame": { | |
| 125 | 128 | "type": "boolean" | |
| 126 | 129 | }, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -163,6 +163,9 @@ Enable Source Map V3 support for stack traces. | |||
| 163 | 163 | .It Fl -entry-url | |
| 164 | 164 | Interpret the entry point as a URL. | |
| 165 | 165 | . | |
| 166 | + .It Fl -experimental-addon-modules | ||
| 167 | + Enable experimental addon module support. | ||
| 168 | + . | ||
| 166 | 169 | .It Fl -experimental-default-type Ns = Ns Ar type | |
| 167 | 170 | Interpret as either ES modules or CommonJS modules input via --eval or STDIN, when --input-type is unspecified; | |
| 168 | 171 | .js or extensionless files with no sibling or parent package.json; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,6 +18,9 @@ const extensionFormatMap = { | |||
| 18 | 18 | '.wasm': 'wasm', | |
| 19 | 19 | }; | |
| 20 | 20 | ||
| 21 | + if (getOptionValue('--experimental-addon-modules')) { | ||
| 22 | + extensionFormatMap['.node'] = 'addon'; | ||
| 23 | + } | ||
| 21 | 24 | if (getOptionValue('--experimental-strip-types')) { | |
| 22 | 25 | extensionFormatMap['.ts'] = 'module-typescript'; | |
| 23 | 26 | extensionFormatMap['.mts'] = 'module-typescript'; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -84,6 +84,9 @@ function defaultLoad(url, context = kEmptyObject) { | |||
| 84 | 84 | if (urlInstance.protocol === 'node:') { | |
| 85 | 85 | source = null; | |
| 86 | 86 | format ??= 'builtin'; | |
| 87 | + } else if (format === 'addon') { | ||
| 88 | + // Skip loading addon file content. It must be loaded with dlopen from file system. | ||
| 89 | + source = null; | ||
| 87 | 90 | } else if (format !== 'commonjs' || defaultType === 'module') { | |
| 88 | 91 | if (source == null) { | |
| 89 | 92 | ({ responseURL, source } = getSourceSync(urlInstance, context)); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,7 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | 3 | const { | |
| 4 | 4 | ArrayPrototypePush, | |
| 5 | - Boolean, | ||
| 6 | 5 | FunctionPrototypeCall, | |
| 7 | 6 | JSONParse, | |
| 8 | 7 | ObjectAssign, | |
@@ -52,6 +51,7 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { | |||
| 52 | 51 | }); | |
| 53 | 52 | const { emitExperimentalWarning, kEmptyObject, setOwnProperty, isWindows } = require('internal/util'); | |
| 54 | 53 | const { | |
| 54 | + ERR_INVALID_RETURN_PROPERTY_VALUE, | ||
| 55 | 55 | ERR_UNKNOWN_BUILTIN_MODULE, | |
| 56 | 56 | } = require('internal/errors').codes; | |
| 57 | 57 | const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache'); | |
@@ -186,7 +186,7 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul | |||
| 186 | 186 | // In case the source was not provided by the `load` step, we need fetch it now. | |
| 187 | 187 | source = stringify(source ?? getSource(new URL(url)).source); | |
| 188 | 188 | ||
| 189 | - const { exportNames, module } = cjsPreparseModuleExports(filename, source, isMain, format); | ||
| 189 | + const { exportNames, module } = cjsPreparseModuleExports(filename, source, format); | ||
| 190 | 190 | cjsCache.set(url, module); | |
| 191 | 191 | const namesWithDefault = exportNames.has('default') ? | |
| 192 | 192 | [...exportNames] : ['default', ...exportNames]; | |
@@ -227,6 +227,47 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul | |||
| 227 | 227 | }, module); | |
| 228 | 228 | } | |
| 229 | 229 | ||
| 230 | + /** | ||
| 231 | + * Creates a ModuleWrap object for a CommonJS module without source texts. | ||
| 232 | + * @param {string} url - The URL of the module. | ||
| 233 | + * @param {boolean} isMain - Whether the module is the main module. | ||
| 234 | + * @returns {ModuleWrap} The ModuleWrap object for the CommonJS module. | ||
| 235 | + */ | ||
| 236 | + function createCJSNoSourceModuleWrap(url, isMain) { | ||
| 237 | + debug(`Translating CJSModule without source ${url}`); | ||
| 238 | + | ||
| 239 | + const filename = urlToFilename(url); | ||
| 240 | + | ||
| 241 | + const module = cjsEmplaceModuleCacheEntry(filename); | ||
| 242 | + cjsCache.set(url, module); | ||
| 243 | + | ||
| 244 | + if (isMain) { | ||
| 245 | + setOwnProperty(process, 'mainModule', module); | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + // Addon export names are not known until the addon is loaded. | ||
| 249 | + const exportNames = ['default', 'module.exports']; | ||
| 250 | + return new ModuleWrap(url, undefined, exportNames, function evaluationCallback() { | ||
| 251 | + debug(`Loading CJSModule ${url}`); | ||
| 252 | + | ||
| 253 | + if (!module.loaded) { | ||
| 254 | + wrapModuleLoad(filename, null, isMain); | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + /** @type {import('./loader').ModuleExports} */ | ||
| 258 | + let exports; | ||
| 259 | + if (module[kModuleExport] !== undefined) { | ||
| 260 | + exports = module[kModuleExport]; | ||
| 261 | + module[kModuleExport] = undefined; | ||
| 262 | + } else { | ||
| 263 | + ({ exports } = module); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + this.setExport('default', exports); | ||
| 267 | + this.setExport('module.exports', exports); | ||
| 268 | + }, module); | ||
| 269 | + } | ||
| 270 | + | ||
| 230 | 271 | translators.set('commonjs-sync', function requireCommonJS(url, source, isMain) { | |
| 231 | 272 | initCJSParseSync(); | |
| 232 | 273 | ||
@@ -277,26 +318,38 @@ translators.set('commonjs', function commonjsStrategy(url, source, isMain) { | |||
| 277 | 318 | return createCJSModuleWrap(url, source, isMain, 'commonjs', cjsLoader); | |
| 278 | 319 | }); | |
| 279 | 320 | ||
| 321 | + /** | ||
| 322 | + * Get or create an entry in the CJS module cache for the given filename. | ||
| 323 | + * @param {string} filename CJS module filename | ||
| 324 | + * @returns {CJSModule} the cached CJS module entry | ||
| 325 | + */ | ||
| 326 | + function cjsEmplaceModuleCacheEntry(filename, exportNames) { | ||
| 327 | + // TODO: Do we want to keep hitting the user mutable CJS loader here? | ||
| 328 | + let cjsMod = CJSModule._cache[filename]; | ||
| 329 | + if (cjsMod) { | ||
| 330 | + return cjsMod; | ||
| 331 | + } | ||
| 332 | + | ||
| 333 | + cjsMod = new CJSModule(filename); | ||
| 334 | + cjsMod.filename = filename; | ||
| 335 | + cjsMod.paths = CJSModule._nodeModulePaths(cjsMod.path); | ||
| 336 | + cjsMod[kIsCachedByESMLoader] = true; | ||
| 337 | + CJSModule._cache[filename] = cjsMod; | ||
| 338 | + | ||
| 339 | + return cjsMod; | ||
| 340 | + } | ||
| 341 | + | ||
| 280 | 342 | /** | |
| 281 | 343 | * Pre-parses a CommonJS module's exports and re-exports. | |
| 282 | 344 | * @param {string} filename - The filename of the module. | |
| 283 | 345 | * @param {string} [source] - The source code of the module. | |
| 284 | - * @param {boolean} isMain - Whether it is pre-parsing for the entry point. | ||
| 285 | - * @param {string} format | ||
| 346 | + * @param {string} [format] | ||
| 286 | 347 | */ | |
| 287 | - function cjsPreparseModuleExports(filename, source, isMain, format) { | ||
| 288 | - let module = CJSModule._cache[filename]; | ||
| 289 | - if (module && module[kModuleExportNames] !== undefined) { | ||
| 348 | + function cjsPreparseModuleExports(filename, source, format) { | ||
| 349 | + const module = cjsEmplaceModuleCacheEntry(filename); | ||
| 350 | + if (module[kModuleExportNames] !== undefined) { | ||
| 290 | 351 | return { module, exportNames: module[kModuleExportNames] }; | |
| 291 | 352 | } | |
| 292 | - const loaded = Boolean(module); | ||
| 293 | - if (!loaded) { | ||
| 294 | - module = new CJSModule(filename); | ||
| 295 | - module.filename = filename; | ||
| 296 | - module.paths = CJSModule._nodeModulePaths(module.path); | ||
| 297 | - module[kIsCachedByESMLoader] = true; | ||
| 298 | - CJSModule._cache[filename] = module; | ||
| 299 | - } | ||
| 300 | 353 | ||
| 301 | 354 | if (source === undefined) { | |
| 302 | 355 | ({ source } = loadSourceForCJSWithHooks(module, filename, format)); | |
@@ -337,7 +390,7 @@ function cjsPreparseModuleExports(filename, source, isMain, format) { | |||
| 337 | 390 | ||
| 338 | 391 | if (format === 'commonjs' || | |
| 339 | 392 | (!BuiltinModule.normalizeRequirableId(resolved) && findLongestRegisteredExtension(resolved) === '.js')) { | |
| 340 | - const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, false, format); | ||
| 393 | + const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, format); | ||
| 341 | 394 | for (const name of reexportNames) { | |
| 342 | 395 | exportNames.add(name); | |
| 343 | 396 | } | |
@@ -519,6 +572,25 @@ translators.set('wasm', function(url, source) { | |||
| 519 | 572 | return module; | |
| 520 | 573 | }); | |
| 521 | 574 | ||
| 575 | + // Strategy for loading a addon | ||
| 576 | + translators.set('addon', function translateAddon(url, source, isMain) { | ||
| 577 | + emitExperimentalWarning('Importing addons'); | ||
| 578 | + | ||
| 579 | + // The addon must be loaded from file system with dlopen. Assert | ||
| 580 | + // the source is null. | ||
| 581 | + if (source !== null) { | ||
| 582 | + throw new ERR_INVALID_RETURN_PROPERTY_VALUE( | ||
| 583 | + 'null', | ||
| 584 | + 'load', | ||
| 585 | + 'source', | ||
| 586 | + source); | ||
| 587 | + } | ||
| 588 | + | ||
| 589 | + debug(`Translating addon ${url}`); | ||
| 590 | + | ||
| 591 | + return createCJSNoSourceModuleWrap(url, isMain); | ||
| 592 | + }); | ||
| 593 | + | ||
| 522 | 594 | // Strategy for loading a commonjs TypeScript module | |
| 523 | 595 | translators.set('commonjs-typescript', function(url, source, isMain) { | |
| 524 | 596 | assertBufferSource(source, true, 'load'); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -424,6 +424,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | |||
| 424 | 424 | "Treat the entrypoint as a URL", | |
| 425 | 425 | &EnvironmentOptions::entry_is_url, | |
| 426 | 426 | kAllowedInEnvvar); | |
| 427 | + AddOption("--experimental-addon-modules", | ||
| 428 | + "experimental import support for addons", | ||
| 429 | + &EnvironmentOptions::experimental_addon_modules, | ||
| 430 | + kAllowedInEnvvar); | ||
| 427 | 431 | AddOption("--experimental-abortcontroller", "", NoOp{}, kAllowedInEnvvar); | |
| 428 | 432 | AddOption("--experimental-eventsource", | |
| 429 | 433 | "experimental EventSource API", | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -121,6 +121,7 @@ class EnvironmentOptions : public Options { | |||
| 121 | 121 | bool require_module = true; | |
| 122 | 122 | std::string dns_result_order; | |
| 123 | 123 | bool enable_source_maps = false; | |
| 124 | + bool experimental_addon_modules = false; | ||
| 124 | 125 | bool experimental_eventsource = false; | |
| 125 | 126 | bool experimental_fetch = true; | |
| 126 | 127 | bool experimental_websocket = true; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments