|
7 | 7 | <!-- YAML |
8 | 8 | added: v8.5.0 |
9 | 9 | changes: |
| 10 | + - version: REPLACEME |
| 11 | + pr-url: https://github.com/nodejs/node/pull/44710 |
| 12 | + description: Loader hooks are executed off the main thread. |
10 | 13 | - version: |
11 | 14 | - v18.6.0 |
12 | 15 | pr-url: https://github.com/nodejs/node/pull/42623 |
@@ -325,6 +328,9 @@ added: |
325 | 328 | - v13.9.0 |
326 | 329 | - v12.16.2 |
327 | 330 | changes: |
| 331 | + - version: REPLACEME |
| 332 | + pr-url: https://github.com/nodejs/node/pull/44710 |
| 333 | + description: This API now returns a string synchronously instead of a Promise. |
328 | 334 | - version: |
329 | 335 | - v16.2.0 |
330 | 336 | - v14.18.0 |
@@ -340,29 +346,26 @@ command flag enabled. |
340 | 346 | * `specifier` {string} The module specifier to resolve relative to `parent`. |
341 | 347 | * `parent` {string|URL} The absolute parent module URL to resolve from. If none |
342 | 348 | is specified, the value of `import.meta.url` is used as the default. |
343 | | -* Returns: {Promise} |
| 349 | +* Returns: {string} |
344 | 350 |
|
345 | 351 | Provides a module-relative resolution function scoped to each module, returning |
346 | | -the URL string. |
| 352 | +the URL string. In alignment with browser behavior, this now returns |
| 353 | +synchronously. |
347 | 354 |
|
348 | | -<!-- eslint-skip --> |
| 355 | +> **Caveat** This can result in synchronous file-system operations, which |
| 356 | +> can impact performance similarly to `require.resolve`. |
349 | 357 |
|
350 | 358 | ```js |
351 | | -const dependencyAsset = await import.meta.resolve('component-lib/asset.css'); |
| 359 | +const dependencyAsset = import.meta.resolve('component-lib/asset.css'); |
352 | 360 | ``` |
353 | 361 |
|
354 | 362 | `import.meta.resolve` also accepts a second argument which is the parent module |
355 | | -from which to resolve from: |
356 | | -
|
357 | | -<!-- eslint-skip --> |
| 363 | +from which to resolve: |
358 | 364 |
|
359 | 365 | ```js |
360 | | -await import.meta.resolve('./dep', import.meta.url); |
| 366 | +import.meta.resolve('./dep', import.meta.url); |
361 | 367 | ``` |
362 | 368 |
|
363 | | -This function is asynchronous because the ES module resolver in Node.js is |
364 | | -allowed to be asynchronous. |
365 | | -
|
366 | 369 | ## Interoperability with CommonJS |
367 | 370 |
|
368 | 371 | ### `import` statements |
@@ -729,6 +732,11 @@ A hook that returns without calling `next<hookName>()` _and_ without returning |
729 | 732 | `shortCircuit: true` also triggers an exception. These errors are to help |
730 | 733 | prevent unintentional breaks in the chain. |
731 | 734 |
|
| 735 | +Hooks are run in a separate thread, isolated from the main. That means it is a |
| 736 | +different [realm](https://tc39.es/ecma262/#realm). The hooks thread may be |
| 737 | +terminated by the main thread at any time, so do not depend on asynchronous |
| 738 | +operations to (like `console.log`) complete. |
| 739 | +
|
732 | 740 | #### `resolve(specifier, context, nextResolve)` |
733 | 741 |
|
734 | 742 | <!-- YAML |
@@ -759,7 +767,7 @@ changes: |
759 | 767 | Node.js default `resolve` hook after the last user-supplied `resolve` hook |
760 | 768 | * `specifier` {string} |
761 | 769 | * `context` {Object} |
762 | | -* Returns: {Object} |
| 770 | +* Returns: {Object|Promise} |
763 | 771 | * `format` {string|null|undefined} A hint to the load hook (it might be |
764 | 772 | ignored) |
765 | 773 | `'builtin' | 'commonjs' | 'json' | 'module' | 'wasm'` |
@@ -769,6 +777,9 @@ changes: |
769 | 777 | terminate the chain of `resolve` hooks. **Default:** `false` |
770 | 778 | * `url` {string} The absolute URL to which this input resolves |
771 | 779 |
|
| 780 | +> **Caveat** Despite support for returning promises and async functions, calls |
| 781 | +> to `resolve` may block the main thread which can impact performance. |
| 782 | +
|
772 | 783 | The `resolve` hook chain is responsible for telling Node.js where to find and |
773 | 784 | how to cache a given `import` statement or expression. It can optionally return |
774 | 785 | its format (such as `'module'`) as a hint to the `load` hook. If a format is |
@@ -794,7 +805,7 @@ Node.js module specifier resolution behavior_ when calling `defaultResolve`, the |
794 | 805 | `context.conditions` array originally passed into the `resolve` hook. |
795 | 806 |
|
796 | 807 | ```js |
797 | | -export async function resolve(specifier, context, nextResolve) { |
| 808 | +export function resolve(specifier, context, nextResolve) { |
798 | 809 | const { parentURL = null } = context; |
799 | 810 |
|
800 | 811 | if (Math.random() > 0.5) { // Some condition. |
@@ -1067,6 +1078,25 @@ import CoffeeScript from 'coffeescript'; |
1067 | 1078 |
|
1068 | 1079 | const baseURL = pathToFileURL(`${cwd()}/`).href; |
1069 | 1080 |
|
| 1081 | +// CoffeeScript files end in .coffee, .litcoffee, or .coffee.md. |
| 1082 | +const extensionsRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/; |
| 1083 | +
|
| 1084 | +export function resolve(specifier, context, nextResolve) { |
| 1085 | + if (extensionsRegex.test(specifier)) { |
| 1086 | + const { parentURL = baseURL } = context; |
| 1087 | +
|
| 1088 | + // Node.js normally errors on unknown file extensions, so return a URL for |
| 1089 | + // specifiers ending in the CoffeeScript file extensions. |
| 1090 | + return { |
| 1091 | + shortCircuit: true, |
| 1092 | + url: new URL(specifier, parentURL).href, |
| 1093 | + }; |
| 1094 | + } |
| 1095 | +
|
| 1096 | + // Let Node.js handle all other specifiers. |
| 1097 | + return nextResolve(specifier); |
| 1098 | +} |
| 1099 | +
|
1070 | 1100 | export async function load(url, context, nextLoad) { |
1071 | 1101 | if (extensionsRegex.test(url)) { |
1072 | 1102 | // Now that we patched resolve to let CoffeeScript URLs through, we need to |
|