Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module: refator ESM loader for adding future synchronous hooks #54769

Merged
merged 1 commit into from
Sep 17, 2024

Conversation

joyeecheung
Copy link
Member

This lays the foundation for supporting synchronous hooks proposed in nodejs/loaders#198 for ESM.

  • Corrects and adds several JSDoc comments for internal functions of the ESM loader, as well as explaining how require() for import CJS work in the special resolve/load paths. This doesn't consolidate it with import in require(esm) yet due to caching differences, which is left as a TODO.
  • The moduleProvider passed into ModuleJob is replaced as moduleOrModulePromise, we call the translators directly in the ESM loader and verify it right after loading for clarity.
  • Reuse a few refactored out helpers for require(esm) in getModuleJobForRequire().

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-bot nodejs-github-bot added esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run. labels Sep 4, 2024
@joyeecheung joyeecheung added the request-ci Add this label to start a Jenkins CI on a PR. label Sep 4, 2024
const wrap = FunctionPrototypeCall(translator, this, responseURL, source, isMain);
assert(wrap instanceof ModuleWrap); // No asynchronous translators should be called.
const wrap = this.#translate(url, finalFormat, source, isMain);
assert(wrap instanceof ModuleWrap, `Translator used for require(${url}) should not be async`);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertions for translators could be removed if we just switch to compiled = new WebAssembly.Module(source) in the wasm translator, though I am not sure if anyone still wants to keep the imported wasm asynchronously compiled (import 'wasm' is not really all that useful after https://github.com/WebAssembly/esm-integration/blob/main/proposals/esm-integration/README.md is shipped by V8 anyway)

@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Sep 4, 2024
@nodejs-github-bot
Copy link
Collaborator

Copy link

codecov bot commented Sep 4, 2024

Codecov Report

Attention: Patch coverage is 98.86364% with 3 lines in your changes missing coverage. Please review.

Project coverage is 88.07%. Comparing base (c1afd2c) to head (5ecaf9c).
Report is 516 commits behind head on main.

Files with missing lines Patch % Lines
lib/internal/modules/esm/loader.js 98.57% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #54769      +/-   ##
==========================================
+ Coverage   88.06%   88.07%   +0.01%     
==========================================
  Files         652      652              
  Lines      183545   183653     +108     
  Branches    35866    35860       -6     
==========================================
+ Hits       161639   161758     +119     
+ Misses      15150    15140      -10     
+ Partials     6756     6755       -1     
Files with missing lines Coverage Δ
lib/internal/modules/esm/module_job.js 100.00% <100.00%> (ø)
lib/internal/modules/esm/translators.js 92.45% <100.00%> (+0.75%) ⬆️
lib/internal/modules/esm/loader.js 98.34% <98.57%> (+0.57%) ⬆️

... and 33 files with indirect coverage changes

@RedYetiDev
Copy link
Member

nit: refator->refactor in commit

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the commit message but otherwise LGTM

@joyeecheung
Copy link
Member Author

joyeecheung commented Sep 5, 2024

Fixed the typo commit message - also I noticed there are a few typos in the return type of the JSDocs of getModuleJobForImport and getModuleJobForRequireInImportedCJS (deleted the wrong Promise< and > after copy-pasting somehow) so I fixed that as well.

@joyeecheung joyeecheung added the request-ci Add this label to start a Jenkins CI on a PR. label Sep 5, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Sep 5, 2024
@nodejs-github-bot
Copy link
Collaborator

@joyeecheung joyeecheung added the request-ci Add this label to start a Jenkins CI on a PR. label Sep 16, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Sep 16, 2024
@nodejs-github-bot
Copy link
Collaborator

This lays the foundation for supporting synchronous hooks proposed
in nodejs/loaders#198 for ESM.

- Corrects and adds several JSDoc comments for internal functions
  of the ESM loader, as well as explaining how require() for
  import CJS work in the special resolve/load paths. This doesn't
  consolidate it with import in require(esm) yet due to caching
  differences, which is left as a TODO.
- The moduleProvider passed into ModuleJob is replaced as
  moduleOrModulePromise, we call the translators directly in the
  ESM loader and verify it right after loading for clarity.
- Reuse a few refactored out helpers for require(esm) in
  getModuleJobForRequire().
@joyeecheung
Copy link
Member Author

Rebased to resolve the merge conflicts.

@joyeecheung joyeecheung added the request-ci Add this label to start a Jenkins CI on a PR. label Sep 16, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Sep 16, 2024
@nodejs-github-bot
Copy link
Collaborator

@joyeecheung
Copy link
Member Author

@mcollina @Qard @jasnell this needs a re-approval after the rebase. Can you take a look again? Thanks

@joyeecheung joyeecheung added the commit-queue Add this label to land a pull request using GitHub Actions. label Sep 17, 2024
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Sep 17, 2024
@nodejs-github-bot nodejs-github-bot merged commit 3ac5b49 into nodejs:main Sep 17, 2024
56 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in 3ac5b49

joyeecheung added a commit to joyeecheung/node that referenced this pull request Oct 1, 2024
This lays the foundation for supporting synchronous hooks proposed
in nodejs/loaders#198 for ESM.

- Corrects and adds several JSDoc comments for internal functions
  of the ESM loader, as well as explaining how require() for
  import CJS work in the special resolve/load paths. This doesn't
  consolidate it with import in require(esm) yet due to caching
  differences, which is left as a TODO.
- The moduleProvider passed into ModuleJob is replaced as
  moduleOrModulePromise, we call the translators directly in the
  ESM loader and verify it right after loading for clarity.
- Reuse a few refactored out helpers for require(esm) in
  getModuleJobForRequire().

PR-URL: nodejs#54769
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Stephen Belanger <[email protected]>
Reviewed-By: James M Snell <[email protected]>
targos pushed a commit that referenced this pull request Oct 4, 2024
This lays the foundation for supporting synchronous hooks proposed
in nodejs/loaders#198 for ESM.

- Corrects and adds several JSDoc comments for internal functions
  of the ESM loader, as well as explaining how require() for
  import CJS work in the special resolve/load paths. This doesn't
  consolidate it with import in require(esm) yet due to caching
  differences, which is left as a TODO.
- The moduleProvider passed into ModuleJob is replaced as
  moduleOrModulePromise, we call the translators directly in the
  ESM loader and verify it right after loading for clarity.
- Reuse a few refactored out helpers for require(esm) in
  getModuleJobForRequire().

PR-URL: #54769
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Stephen Belanger <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@aduh95 aduh95 mentioned this pull request Oct 9, 2024
@laverdet
Copy link
Contributor

@joyeecheung was it intentional to remove responseURL?

$ cat loader.mjs 
export async function load(urlString, context, nextLoad) {
	const result = await nextLoad(urlString, context);
	return {
		...result,
		responseURL: 'test://',
	};
}

$ cat register.mjs 
import { register } from 'node:module';

register('./loader.mjs', {
	parentURL: import.meta.url,
});

$ cat main.mjs 
console.log(import.meta.url);

$ node -v
v22.4.1

$ node --import ./register.mjs main.mjs                                                         
test://

$ [...]
$ node -v
v22.10.0

$ node --import ./register.mjs main.mjs  
file:///Users/marcel/tmp/main.mjs

This feature was useful because it allows you to control import.meta.url. I used it pretty significantly to hide implementation details in my hot reloader dynohot. The resolve hook would resolve something like "hot:module?url=file:///file.mjs" and the load hook knows how to unwrap that parameter and load the underlying resource. We don't want to affect the result of import.meta at runtime though.

@joyeecheung
Copy link
Member Author

was it intentional to remove responseURL?

It was not intended to break any public API, though it seems responseURL was never properly documented nor tested. Do you want to submit a PR to add it back with proper tests and documentation?

louwers pushed a commit to louwers/node that referenced this pull request Nov 2, 2024
This lays the foundation for supporting synchronous hooks proposed
in nodejs/loaders#198 for ESM.

- Corrects and adds several JSDoc comments for internal functions
  of the ESM loader, as well as explaining how require() for
  import CJS work in the special resolve/load paths. This doesn't
  consolidate it with import in require(esm) yet due to caching
  differences, which is left as a TODO.
- The moduleProvider passed into ModuleJob is replaced as
  moduleOrModulePromise, we call the translators directly in the
  ESM loader and verify it right after loading for clarity.
- Reuse a few refactored out helpers for require(esm) in
  getModuleJobForRequire().

PR-URL: nodejs#54769
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Stephen Belanger <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@marco-ippolito marco-ippolito added the backport-requested-v20.x PRs awaiting manual backport to the v20.x-staging branch. label Nov 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-requested-v20.x PRs awaiting manual backport to the v20.x-staging branch. esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants