| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent dc78091 commit 3c1636d
13 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1079,6 +1079,18 @@ passing a second `parentURL` argument for contextual resolution. | |||
| 1079 | 1079 | ||
| 1080 | 1080 | Previously gated the entire `import.meta.resolve` feature. | |
| 1081 | 1081 | ||
| 1082 | + ### `--experimental-import-text` | ||
| 1083 | + | ||
| 1084 | + <!-- YAML | ||
| 1085 | + added: | ||
| 1086 | + - REPLACEME | ||
| 1087 | + --> | ||
| 1088 | + | ||
| 1089 | + > Stability: 1.0 - Early development | ||
| 1090 | + | ||
| 1091 | + Enable experimental support for importing modules with | ||
| 1092 | + `with { type: 'text' }`. | ||
| 1093 | + | ||
| 1082 | 1094 | ### `--experimental-inspector-network-resource` | |
| 1083 | 1095 | ||
| 1084 | 1096 | <!-- YAML | |
@@ -3529,6 +3541,7 @@ one is included in the list below. | |||
| 3529 | 3541 | * `--experimental-detect-module` | |
| 3530 | 3542 | * `--experimental-eventsource` | |
| 3531 | 3543 | * `--experimental-import-meta-resolve` | |
| 3544 | + * `--experimental-import-text` | ||
| 3532 | 3545 | * `--experimental-json-modules` | |
| 3533 | 3546 | * `--experimental-loader` | |
| 3534 | 3547 | * `--experimental-modules` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -294,8 +294,10 @@ Node.js only supports the `type` attribute, for which it supports the following | |||
| 294 | 294 | | Attribute `type` | Needed for | | |
| 295 | 295 | | ---------------- | ---------------- | | |
| 296 | 296 | | `'json'` | [JSON modules][] | | |
| 297 | + | `'text'` | [Text modules][] | | ||
| 297 | 298 | ||
| 298 | 299 | The `type: 'json'` attribute is mandatory when importing JSON modules. | |
| 300 | + The `type: 'text'` attribute is mandatory when importing text modules. | ||
| 299 | 301 | ||
| 300 | 302 | ## Built-in modules | |
| 301 | 303 | ||
@@ -702,6 +704,23 @@ exports. A cache entry is created in the CommonJS cache to avoid duplication. | |||
| 702 | 704 | The same object is returned in CommonJS if the JSON module has already been | |
| 703 | 705 | imported from the same path. | |
| 704 | 706 | ||
| 707 | + ## Text modules | ||
| 708 | + | ||
| 709 | + > Stability: 1.0 - Early development | ||
| 710 | + | ||
| 711 | + Text modules are available behind the `--experimental-import-text` flag. | ||
| 712 | + | ||
| 713 | + Text files can be referenced by `import`: | ||
| 714 | + | ||
| 715 | + ```js | ||
| 716 | + import message from './message.txt' with { type: 'text' }; | ||
| 717 | + ``` | ||
| 718 | + | ||
| 719 | + The `with { type: 'text' }` syntax is mandatory; see [Import Attributes][]. | ||
| 720 | + | ||
| 721 | + The imported text only exposes a `default` export whose value is the module | ||
| 722 | + source as a string. | ||
| 723 | + | ||
| 705 | 724 | <i id="esm_experimental_wasm_modules"></i> | |
| 706 | 725 | ||
| 707 | 726 | ## Wasm modules | |
@@ -1295,6 +1314,7 @@ resolution for ESM specifiers is [commonjs-extension-resolution-loader][]. | |||
| 1295 | 1314 | [Node.js Module Resolution And Loading Algorithm]: #resolution-algorithm-specification | |
| 1296 | 1315 | [Source Phase Imports]: https://github.com/tc39/proposal-source-phase-imports | |
| 1297 | 1316 | [Terminology]: #terminology | |
| 1317 | + [Text modules]: #text-modules | ||
| 1298 | 1318 | [URL]: https://url.spec.whatwg.org/ | |
| 1299 | 1319 | [WebAssembly JS String Builtins Proposal]: https://github.com/WebAssembly/js-string-builtins | |
| 1300 | 1320 | [`"exports"`]: packages.md#exports | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,7 @@ const { | |||
| 8 | 8 | ObjectValues, | |
| 9 | 9 | } = primordials; | |
| 10 | 10 | const { validateString } = require('internal/validators'); | |
| 11 | + const { getOptionValue } = require('internal/options'); | ||
| 11 | 12 | ||
| 12 | 13 | const { | |
| 13 | 14 | ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE, | |
@@ -29,8 +30,13 @@ const formatTypeMap = { | |||
| 29 | 30 | 'commonjs': kImplicitTypeAttribute, | |
| 30 | 31 | 'json': 'json', | |
| 31 | 32 | 'module': kImplicitTypeAttribute, | |
| 33 | + 'text': 'text', | ||
| 32 | 34 | 'wasm': kImplicitTypeAttribute, // It's unclear whether the HTML spec will require an type attribute or not for Wasm; see https://github.com/WebAssembly/esm-integration/issues/42 | |
| 33 | 35 | }; | |
| 36 | + // NOTE: Don't add bytes support yet as it requires Uint8Arrays backed by immutable ArrayBuffers, | ||
| 37 | + // which V8 does not support yet. | ||
| 38 | + // see: https://github.com/nodejs/node/pull/62300#issuecomment-4079163816 | ||
| 39 | + | ||
| 34 | 40 | ||
| 35 | 41 | /** | |
| 36 | 42 | * The HTML spec disallows the default type to be explicitly specified | |
@@ -42,7 +48,6 @@ const supportedTypeAttributes = ArrayPrototypeFilter( | |||
| 42 | 48 | ObjectValues(formatTypeMap), | |
| 43 | 49 | (type) => type !== kImplicitTypeAttribute); | |
| 44 | 50 | ||
| 45 | - | ||
| 46 | 51 | /** | |
| 47 | 52 | * Test a module's import attributes. | |
| 48 | 53 | * @param {string} url The URL of the imported module, for error reporting. | |
@@ -62,6 +67,12 @@ function validateAttributes(url, format, | |||
| 62 | 67 | } | |
| 63 | 68 | const validType = formatTypeMap[format]; | |
| 64 | 69 | ||
| 70 | + if (validType !== undefined && | ||
| 71 | + importAttributes.type === 'text' && | ||
| 72 | + !getOptionValue('--experimental-import-text')) { | ||
| 73 | + throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', importAttributes.type, url); | ||
| 74 | + } | ||
| 75 | + | ||
| 65 | 76 | switch (validType) { | |
| 66 | 77 | case undefined: | |
| 67 | 78 | // Ignore attributes for module formats we don't recognize, to allow new | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -47,6 +47,13 @@ function mimeToFormat(mime) { | |||
| 47 | 47 | ) { return 'module'; } | |
| 48 | 48 | if (mime === 'application/json') { return 'json'; } | |
| 49 | 49 | if (mime === 'application/wasm') { return 'wasm'; } | |
| 50 | + if ( | ||
| 51 | + getOptionValue('--experimental-import-text') && | ||
| 52 | + RegExpPrototypeExec( | ||
| 53 | + /^\s*text\/plain\s*(;\s*charset=utf-?8\s*)?$/i, | ||
| 54 | + mime, | ||
| 55 | + ) !== null | ||
| 56 | + ) { return 'text'; } | ||
| 50 | 57 | return null; | |
| 51 | 58 | } | |
| 52 | 59 | ||
@@ -236,12 +243,22 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE | |||
| 236 | 243 | throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath); | |
| 237 | 244 | } | |
| 238 | 245 | ||
| 246 | + // If the caller explicitly requests text format via import attributes, honor it regardless of file extension. | ||
| 247 | + function isExperimentalTextImport(importAttributes) { | ||
| 248 | + return getOptionValue('--experimental-import-text') && | ||
| 249 | + importAttributes?.type === 'text'; | ||
| 250 | + } | ||
| 251 | + | ||
| 239 | 252 | /** | |
| 240 | 253 | * @param {URL} url | |
| 241 | - * @param {{parentURL: string}} context | ||
| 254 | + * @param {{parentURL: string, importAttributes?: Record<string, string>}} context | ||
| 242 | 255 | * @returns {Promise<string> | string | undefined} only works when enabled | |
| 243 | 256 | */ | |
| 244 | 257 | function defaultGetFormatWithoutErrors(url, context) { | |
| 258 | + if (isExperimentalTextImport(context?.importAttributes)) { | ||
| 259 | + return 'text'; | ||
| 260 | + } | ||
| 261 | + | ||
| 245 | 262 | const protocol = url.protocol; | |
| 246 | 263 | if (!ObjectPrototypeHasOwnProperty(protocolHandlers, protocol)) { | |
| 247 | 264 | return null; | |
@@ -251,10 +268,14 @@ function defaultGetFormatWithoutErrors(url, context) { | |||
| 251 | 268 | ||
| 252 | 269 | /** | |
| 253 | 270 | * @param {URL} url | |
| 254 | - * @param {{parentURL: string}} context | ||
| 271 | + * @param {{parentURL: string, importAttributes?: Record<string, string>}} context | ||
| 255 | 272 | * @returns {Promise<string> | string | undefined} only works when enabled | |
| 256 | 273 | */ | |
| 257 | 274 | function defaultGetFormat(url, context) { | |
| 275 | + if (isExperimentalTextImport(context?.importAttributes)) { | ||
| 276 | + return 'text'; | ||
| 277 | + } | ||
| 278 | + | ||
| 258 | 279 | const protocol = url.protocol; | |
| 259 | 280 | if (!ObjectPrototypeHasOwnProperty(protocolHandlers, protocol)) { | |
| 260 | 281 | return null; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -95,7 +95,7 @@ const { defaultLoadSync, throwUnknownModuleFormat } = require('internal/modules/ | |||
| 95 | 95 | */ | |
| 96 | 96 | ||
| 97 | 97 | /** | |
| 98 | - * @typedef {'builtin'|'commonjs'|'json'|'module'|'wasm'} ModuleFormat | ||
| 98 | + * @typedef {'builtin'|'commonjs'|'json'|'module'|'text'|'wasm'} ModuleFormat | ||
| 99 | 99 | */ | |
| 100 | 100 | ||
| 101 | 101 | /** | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -680,3 +680,14 @@ translators.set('module-typescript', function(url, translateContext, parentURL) | |||
| 680 | 680 | translateContext.source = stripTypeScriptModuleTypes(stringify(source), url); | |
| 681 | 681 | return FunctionPrototypeCall(translators.get('module'), this, url, translateContext, parentURL); | |
| 682 | 682 | }); | |
| 683 | + | ||
| 684 | + // Strategy for loading source as text. | ||
| 685 | + translators.set('text', function textStrategy(url, translateContext) { | ||
| 686 | + emitExperimentalWarning('Text import'); | ||
| 687 | + let { source } = translateContext; | ||
| 688 | + assertBufferSource(source, true, 'load'); | ||
| 689 | + source = stringify(source); | ||
| 690 | + return new ModuleWrap(url, undefined, ['default'], function() { | ||
| 691 | + this.setExport('default', source); | ||
| 692 | + }); | ||
| 693 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -614,6 +614,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | |||
| 614 | 614 | AddAlias("--loader", "--experimental-loader"); | |
| 615 | 615 | AddOption("--experimental-modules", "", NoOp{}, kAllowedInEnvvar); | |
| 616 | 616 | AddOption("--experimental-wasm-modules", "", NoOp{}, kAllowedInEnvvar); | |
| 617 | + AddOption("--experimental-import-text", | ||
| 618 | + "experimental support for importing source as text with import " | ||
| 619 | + "attributes", | ||
| 620 | + &EnvironmentOptions::experimental_import_text, | ||
| 621 | + kAllowedInEnvvar); | ||
| 617 | 622 | AddOption("--experimental-import-meta-resolve", | |
| 618 | 623 | "experimental ES Module import.meta.resolve() parentURL support", | |
| 619 | 624 | &EnvironmentOptions::experimental_import_meta_resolve, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -137,6 +137,7 @@ class EnvironmentOptions : public Options { | |||
| 137 | 137 | std::string localstorage_file; | |
| 138 | 138 | bool experimental_global_navigator = true; | |
| 139 | 139 | bool experimental_global_web_crypto = true; | |
| 140 | + bool experimental_import_text = EXPERIMENTALS_DEFAULT_VALUE; | ||
| 140 | 141 | bool experimental_import_meta_resolve = EXPERIMENTALS_DEFAULT_VALUE; | |
| 141 | 142 | std::string input_type; // Value of --input-type | |
| 142 | 143 | bool entry_is_url = false; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,6 +26,11 @@ async function test() { | |||
| 26 | 26 | { code: 'ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE' } | |
| 27 | 27 | ); | |
| 28 | 28 | ||
| 29 | + await assert.rejects( | ||
| 30 | + import(jsModuleDataUrl, { with: { type: 'text' } }), | ||
| 31 | + { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | ||
| 32 | + ); | ||
| 33 | + | ||
| 29 | 34 | await assert.rejects( | |
| 30 | 35 | import(jsModuleDataUrl, { with: { type: 'json', other: 'unsupported' } }), | |
| 31 | 36 | { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,6 +21,11 @@ await assert.rejects( | |||
| 21 | 21 | { code: 'ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE' } | |
| 22 | 22 | ); | |
| 23 | 23 | ||
| 24 | + await assert.rejects( | ||
| 25 | + import(jsModuleDataUrl, { with: { type: 'text' } }), | ||
| 26 | + { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | ||
| 27 | + ); | ||
| 28 | + | ||
| 24 | 29 | await assert.rejects( | |
| 25 | 30 | import(jsModuleDataUrl, { with: { type: 'json', other: 'unsupported' } }), | |
| 26 | 31 | { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments