@@ -168,16 +168,60 @@ variable. Since the module lookups using `node_modules` folders are all |
168 | 168 | relative, and based on the real path of the files making the calls to |
169 | 169 | `require()`, the packages themselves can be anywhere. |
170 | 170 |
|
171 | | -## The `.mjs` extension |
| 171 | +## Loading ECMAScript modules using `require()` |
172 | 172 |
|
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 |
179 | 178 | regarding which files are parsed as ECMAScript modules. |
180 | 179 |
|
| 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 | +export function distance(a, b) { return (b.x - a.x) ** 2 + (b.y - a.y) ** 2; } |
| 195 | +class Point { |
| 196 | + constructor(x, y) { this.x = x; this.y = y; } |
| 197 | +} |
| 198 | +export default Point; |
| 199 | +``` |
| 200 | + |
| 201 | +```cjs |
| 202 | +const required = require('./point.mjs'); |
| 203 | +// [Module: null prototype] { |
| 204 | +// default: [class Point], |
| 205 | +// distance: [Function: distance] |
| 206 | +// } |
| 207 | +console.log(required); |
| 208 | + |
| 209 | +(async () => { |
| 210 | + const imported = await import('./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 | + |
181 | 225 | ## All together |
182 | 226 |
|
183 | 227 | <!-- type=misc --> |
@@ -207,12 +251,24 @@ require(X) from module at path Y |
207 | 251 |
|
208 | 252 | LOAD_AS_FILE(X) |
209 | 253 | 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 |
212 | 261 | 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 |
213 | 264 |
|
214 | 265 | 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. |
216 | 272 | 2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP |
217 | 273 | 3. If X/index.node is a file, load X/index.node as binary addon. STOP |
218 | 274 |
|
@@ -1097,6 +1153,7 @@ This section was moved to |
1097 | 1153 | [GLOBAL_FOLDERS]: #loading-from-the-global-folders |
1098 | 1154 | [`"main"`]: packages.md#main |
1099 | 1155 | [`"type"`]: packages.md#type |
| 1156 | +[`ERR_REQUIRE_ASYNC_MODULE`]: errors.md#err_require_async_module |
1100 | 1157 | [`ERR_REQUIRE_ESM`]: errors.md#err_require_esm |
1101 | 1158 | [`ERR_UNSUPPORTED_DIR_IMPORT`]: errors.md#err_unsupported_dir_import |
1102 | 1159 | [`MODULE_NOT_FOUND`]: errors.md#module_not_found |
|