Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcad46af

Browse files
joyeecheungmarco-ippolito
authored andcommitted
module: support require()ing synchronous ESM graphs
This patch adds `require()` support for synchronous ESM graphs underthe flag `--experimental-require-module`This is based on the the following design aspect of ESM:- The resolution can be synchronous (up to the host)- The evaluation of a synchronous graph (without top-level await) is also synchronous, and, by the time the module graph is instantiated (before evaluation starts), this is is already known.If `--experimental-require-module` is enabled, and the ECMAScriptmodule being loaded by `require()` meets the following requirements:- Explicitly marked as an ES module with a `"type": "module"` field in the closest package.json or a `.mjs` extension.- Fully synchronous (contains no top-level `await`).`require()` will load the requested module as an ES Module, and returnthe module name space object. In this case it is similar to dynamic`import()` but is run synchronously and returns the name space objectdirectly.```mjs// point.mjsexport function distance(a, b) { return (b.x - a.x) ** 2 + (b.y - a.y) ** 2;}class Point { constructor(x, y) { this.x = x; this.y = y; }}export default Point;``````cjsconst required = require('./point.mjs');// [Module: null prototype] {// default: [class Point],// distance: [Function: distance]// }console.log(required);(async () => { const imported = await import('./point.mjs'); console.log(imported === required); // true})();```If the module being `require()`'d contains top-level `await`, or themodule graph it `import`s contains top-level `await`,[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, usersshould load the asynchronous module using `import()`.If `--experimental-print-required-tla` is enabled, instead of throwing`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate themodule, try to locate the top-level awaits, and print their location tohelp users fix them.PR-URL:#51977Backport-PR-URL:#53500Reviewed-By: Chengzhong Wu <legendecas@gmail.com>Reviewed-By: Matteo Collina <matteo.collina@gmail.com>Reviewed-By: Guy Bedford <guybedford@gmail.com>Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
1 parent30b859f commitcad46af

File tree

63 files changed

+1170
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1170
-79
lines changed

‎doc/api/cli.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,18 @@ added: v11.8.0
974974
975975
Use the specified file as a security policy.
976976

977+
###`--experimental-require-module`
978+
979+
<!-- YAML
980+
added: REPLACEME
981+
-->
982+
983+
>Stability: 1.1 - Active Developement
984+
985+
Supports loading a synchronous ES module graph in`require()`.
986+
987+
See[Loading ECMAScript modules using`require()`][].
988+
977989
###`--experimental-sea-config`
978990

979991
<!-- YAML
@@ -1695,6 +1707,18 @@ changes:
16951707

16961708
Identical to`-e` but prints the result.
16971709

1710+
###`--experimental-print-required-tla`
1711+
1712+
<!-- YAML
1713+
added: REPLACEME
1714+
-->
1715+
1716+
This flag is only useful when`--experimental-require-module` is enabled.
1717+
1718+
If the ES module being`require()`'d contains top-level await, this flag
1719+
allows Node.js to evaluate the module, try to locate the
1720+
top-level awaits, and print their location to help users find them.
1721+
16981722
###`--prof`
16991723

17001724
<!-- YAML
@@ -2642,6 +2666,8 @@ one is included in the list below.
26422666
*`--experimental-network-imports`
26432667
*`--experimental-permission`
26442668
*`--experimental-policy`
2669+
*`--experimental-print-required-tla`
2670+
*`--experimental-require-module`
26452671
*`--experimental-shadow-realm`
26462672
*`--experimental-specifier-resolution`
26472673
*`--experimental-top-level-await`
@@ -3111,6 +3137,7 @@ done
31113137
[ExperimentalWarning: `vm.measureMemory` is an experimental feature]:vm.md#vmmeasurememoryoptions
31123138
[Fetch API]:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
31133139
[File System Permissions]:permissions.md#file-system-permissions
3140+
[Loading ECMAScript modules using `require()`]:modules.md#loading-ecmascript-modules-using-require
31143141
[Module customization hooks]:module.md#customization-hooks
31153142
[Module customization hooks: enabling]:module.md#enabling
31163143
[Modules loaders]:packages.md#modules-loaders

‎doc/api/errors.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,6 +2521,19 @@ Accessing `Object.prototype.__proto__` has been forbidden using
25212521
[`Object.setPrototypeOf`][] should be used to get and set the prototype of an
25222522
object.
25232523

2524+
<aid="ERR_REQUIRE_ASYNC_MODULE"></a>
2525+
2526+
###`ERR_REQUIRE_ASYNC_MODULE`
2527+
2528+
>Stability: 1 - Experimental
2529+
2530+
When trying to`require()` a[ES Module][] under`--experimental-require-module`,
2531+
the module turns out to be asynchronous. That is, it contains top-level await.
2532+
2533+
To see where the top-level await is, use
2534+
`--experimental-print-required-tla` (this would execute the modules
2535+
before looking for the top-level awaits).
2536+
25242537
<aid="ERR_REQUIRE_ESM"></a>
25252538

25262539
###`ERR_REQUIRE_ESM`
@@ -2529,6 +2542,9 @@ object.
25292542
25302543
An attempt was made to`require()` an[ES Module][].
25312544

2545+
To enable`require()` for synchronous module graphs (without
2546+
top-level`await`), use`--experimental-require-module`.
2547+
25322548
<aid="ERR_SCRIPT_EXECUTION_INTERRUPTED"></a>
25332549

25342550
###`ERR_SCRIPT_EXECUTION_INTERRUPTED`

‎doc/api/esm.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,11 +449,10 @@ compatibility.
449449
450450
###`require`
451451
452-
The CommonJS module`require` always treats the files it references as CommonJS.
452+
The CommonJS module`require` currently only supports loading synchronous ES
453+
modules when`--experimental-require-module` is enabled.
453454
454-
Using`require` to load an ES module is not supported because ES modules have
455-
asynchronous execution. Instead, use [`import()`][] to load an ES module
456-
from a CommonJS module.
455+
See [Loading ECMAScript modules using`require()`][] for details.
457456
458457
### CommonJS Namespaces
459458
@@ -1132,6 +1131,7 @@ resolution for ESM specifiers is [commonjs-extension-resolution-loader][].
11321131
[Import Attributes]: #import-attributes
11331132
[Import Attributes proposal]: https://github.com/tc39/proposal-import-attributes
11341133
[JSON modules]: #json-modules
1134+
[Loading ECMAScript modules using`require()`]: modules.md#loading-ecmascript-modules-using-require
11351135
[Module customization hooks]: module.md#customization-hooks
11361136
[Node.js Module Resolution And Loading Algorithm]: #resolution-algorithm-specification
11371137
[Terminology]: #terminology

‎doc/api/modules.md

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,16 +168,60 @@ variable. Since the module lookups using `node_modules` folders are all
168168
relative, and based on the real path of the files making the calls to
169169
`require()`, the packages themselves can be anywhere.
170170

171-
##The`.mjs` extension
171+
##Loading ECMAScript modules using`require()`
172172

173-
Due to the synchronous nature of`require()`, it is not possible to use it to
174-
load ECMAScript module files. Attempting to do so will throw a
175-
[`ERR_REQUIRE_ESM`][] error. Use[`import()`][] instead.
176-
177-
The`.mjs` extension is reserved for[ECMAScript Modules][] which cannot be
178-
loaded via`require()`. See[Determining module system][] section for more info
173+
The`.mjs` extension is reserved for[ECMAScript Modules][].
174+
Currently, if the flag`--experimental-require-module` is not used, loading
175+
an ECMAScript module using`require()` will throw a[`ERR_REQUIRE_ESM`][]
176+
error, and users need to use[`import()`][] instead. See
177+
[Determining module system][] section for more info
179178
regarding which files are parsed as ECMAScript modules.
180179

180+
If`--experimental-require-module` is enabled, and the ECMAScript module being
181+
loaded by`require()` meets the following requirements:
182+
183+
* Explicitly marked as an ES module with a`"type": "module"` field in
184+
the closest package.json or a`.mjs` extension.
185+
* Fully synchronous (contains no top-level`await`).
186+
187+
`require()` will load the requested module as an ES Module, and return
188+
the module name space object. In this case it is similar to dynamic
189+
`import()` but is run synchronously and returns the name space object
190+
directly.
191+
192+
```mjs
193+
// point.mjs
194+
exportfunctiondistance(a,b) {return (b.x-a.x)**2+ (b.y-a.y)**2; }
195+
classPoint {
196+
constructor(x,y) {this.x= x;this.y= y; }
197+
}
198+
exportdefaultPoint;
199+
```
200+
201+
```cjs
202+
constrequired=require('./point.mjs');
203+
// [Module: null prototype] {
204+
// default: [class Point],
205+
// distance: [Function: distance]
206+
// }
207+
console.log(required);
208+
209+
(async ()=> {
210+
constimported=awaitimport('./point.mjs');
211+
console.log(imported=== required);// true
212+
})();
213+
```
214+
215+
If the module being`require()`'d contains top-level`await`, or the module
216+
graph it`import`s contains top-level`await`,
217+
[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users should
218+
load the asynchronous module using`import()`.
219+
220+
If`--experimental-print-required-tla` is enabled, instead of throwing
221+
`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the
222+
module, try to locate the top-level awaits, and print their location to
223+
help users fix them.
224+
181225
##All together
182226

183227
<!-- type=misc-->
@@ -207,12 +251,24 @@ require(X) from module at path Y
207251

208252
LOAD_AS_FILE(X)
209253
1. If X is a file, load X as its file extension format. STOP
210-
2. If X.js is a file, load X.js as JavaScript text. STOP
211-
3. If X.json is a file, parse X.json to a JavaScript Object. STOP
254+
2. If X.js is a file,
255+
a. Find the closest package scope SCOPE to X.
256+
b. If no scope was found, load X.js as a CommonJS module. STOP.
257+
c. If the SCOPE/package.json contains "type" field,
258+
1. If the "type" field is "module", load X.js as an ECMAScript module. STOP.
259+
2. Else, load X.js as an CommonJS module. STOP.
260+
3. If X.json is a file, load X.json to a JavaScript Object. STOP
212261
4. If X.node is a file, load X.node as binary addon. STOP
262+
5. If X.mjs is a file, and `--experimental-require-module` is enabled,
263+
load X.mjs as an ECMAScript module. STOP
213264

214265
LOAD_INDEX(X)
215-
1. If X/index.js is a file, load X/index.js as JavaScript text. STOP
266+
1. If X/index.js is a file
267+
a. Find the closest package scope SCOPE to X.
268+
b. If no scope was found, load X/index.js as a CommonJS module. STOP.
269+
c. If the SCOPE/package.json contains "type" field,
270+
1. If the "type" field is "module", load X/index.js as an ECMAScript module. STOP.
271+
2. Else, load X/index.js as an CommonJS module. STOP.
216272
2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
217273
3. If X/index.node is a file, load X/index.node as binary addon. STOP
218274

@@ -1097,6 +1153,7 @@ This section was moved to
10971153
[GLOBAL_FOLDERS]:#loading-from-the-global-folders
10981154
[`"main"`]:packages.md#main
10991155
[`"type"`]:packages.md#type
1156+
[`ERR_REQUIRE_ASYNC_MODULE`]:errors.md#err_require_async_module
11001157
[`ERR_REQUIRE_ESM`]:errors.md#err_require_esm
11011158
[`ERR_UNSUPPORTED_DIR_IMPORT`]:errors.md#err_unsupported_dir_import
11021159
[`MODULE_NOT_FOUND`]:errors.md#module_not_found

‎doc/api/packages.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,15 @@ There is the CommonJS module loader:
133133
`process.dlopen()`.
134134
* It treats all files that lack`.json` or`.node` extensions as JavaScript
135135
text files.
136-
* It cannot be used to load ECMAScript modules (although it is possible to
137-
[load ECMASCript modules from CommonJS modules][]). When used to load a
138-
JavaScript text file that is not an ECMAScript module, it loads it as a
139-
CommonJS module.
136+
* It can only be used to[load ECMASCript modules from CommonJS modules][] if
137+
the module graph is synchronous (that contains no top-level`await`) when
138+
`--experimental-require-module` is enabled.
139+
When used to load a JavaScript text file that is not an ECMAScript module,
140+
the file will be loaded as a CommonJS module.
140141

141142
There is the ECMAScript module loader:
142143

143-
* It is asynchronous.
144+
* It is asynchronous, unless it's being used to load modules for`require()`.
144145
* It is responsible for handling`import` statements and`import()` expressions.
145146
* It is not monkey patchable, can be customized using[loader hooks][].
146147
* It does not support folders as modules, directory indexes (e.g.
@@ -623,9 +624,9 @@ specific to least specific as conditions should be defined:
623624
*`"require"` - matches when the package is loaded via`require()`. The
624625
referenced file should be loadable with`require()` although the condition
625626
matches regardless of the module format of the target file. Expected
626-
formats include CommonJS, JSON,andnative addons but notES modules as
627-
`require()` doesn't support them._Always mutually exclusive with
628-
`"import"`._
627+
formats include CommonJS, JSON, native addons, andES modules
628+
if`--experimental-require-module` is enabled._Always mutually
629+
exclusive with`"import"`._
629630
*`"default"` - the generic fallback that always matches. Can be a CommonJS
630631
or ES module file._This condition should always come last._
631632

@@ -1371,7 +1372,7 @@ This field defines [subpath imports][] for the current package.
13711372
[entry points]:#package-entry-points
13721373
[folders as modules]:modules.md#folders-as-modules
13731374
[import maps]:https://github.com/WICG/import-maps
1374-
[load ECMASCript modules from CommonJS modules]:modules.md#the-mjs-extension
1375+
[load ECMASCript modules from CommonJS modules]:modules.md#loading-ecmascript-modules-using-require
13751376
[loader hooks]:esm.md#loaders
13761377
[packages folder mapping]:https://github.com/WICG/import-maps#packages-via-trailing-slashes
13771378
[self-reference]:#self-referencing-a-package-using-its-name

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp