Skip to content

src: port initializeImportMeta to native - #57286

Merged
aduh95 merged 12 commits into
nodejs:mainfrom
aduh95:port-import-meta-native
Apr 29, 2025
Merged

src: port initializeImportMeta to native#57286
aduh95 merged 12 commits into
nodejs:mainfrom
aduh95:port-import-meta-native

Conversation

@aduh95

Copy link
Copy Markdown
Contributor

Supersedes #57003.

We should probably avoid translating the URL to a path twice when the user needs both dirname and filename, but I'm not sure if there's an elegant way to do it without crossing the C++/JS bundary.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run. labels Mar 3, 2025
@codecov

codecovBot commented Mar 3, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 68.42105% with 18 lines in your changes missing coverage. Please review.

Project coverage is 90.26%. Comparing base (9cc0195) to head (6b10319).
Report is 366 commits behind head on main.

Files with missing linesPatch %Lines
src/node_modules.cc64.00%6 Missing and 12 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #57286 +/- ##
==========================================
- Coverage 90.28% 90.26% -0.02% 
==========================================
Files 630 630 Lines 186158 186208 +50 Branches 36484 36488 +4 ==========================================
+ Hits 168067 168077 +10 - Misses 10974 10987 +13 - Partials 7117 7144 +27 
Files with missing linesCoverage Δ
lib/internal/modules/esm/initialize_import_meta.js100.00% <100.00%> (ø)
src/node_modules.cc77.30% <64.00%> (-1.44%)⬇️

... and 29 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JakobJingleheimerJakobJingleheimer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not great with cpp, but it looks fine AFAICT, and conceptually checks out 🙂

Comment threadlib/internal/modules/esm/initialize_import_meta.js Outdated
Comment threadsrc/node_modules.cc Outdated
Comment threadsrc/node_modules.cc Outdated
Comment threadsrc/node_modules.cc Outdated

@jsumners-nrjsumners-nr left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think the original implementation is much easier to understand and maintain.

@aduh95

Copy link
Copy Markdown
ContributorAuthor

I think the original implementation is much easier to understand and maintain.

Do you have any suggestions on how to improve it?

@jsumners-nr

Copy link
Copy Markdown

I think the original implementation is much easier to understand and maintain.

Do you have any suggestions on how to improve it?

Not with it all being in C++. The original was plain JavaScript that only required JavaScript domain knowledge. This PR shifts it all in to C++, thus requiring the reader to know that language along with all of the underlying APIs used to implement the feature.

@aduh95aduh95 added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. request-ci Add this label to start a Jenkins CI on a PR. labels Mar 10, 2025
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Mar 10, 2025
@nodejs-github-bot

nodejs-github-bot commented Mar 10, 2025

Copy link
Copy Markdown
Collaborator

CI: https://ci.nodejs.org/job/node-test-pull-request/65676/
Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1677/

Results
esm/cjs-parse.js n=100 -0.20 % ±0.89%
esm/detect-esm-syntax.js n=10000 type='with-package-json' 0.41 % ±0.99%
esm/detect-esm-syntax.js n=10000 type='without-package-json' 0.25 % ±0.79%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 0.12 % ±0.76%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 *** 1.44 % ±0.66%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 *** 1.35 % ±0.56%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 ** 0.59 % ±0.43%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.json' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 0.76 % ±0.86%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.json' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 0.57 % ±0.58%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.node' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 ** 0.89 % ±0.52%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.node' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 *** 1.25 % ±0.71%
esm/esm-loader-defaultResolve.js specifier='./relative-existing.js' n=1000 1.15 % ±2.06%
esm/esm-loader-defaultResolve.js specifier='./relative-nonexistent.js' n=1000 0.02 % ±1.16%
esm/esm-loader-defaultResolve.js specifier='node:os' n=1000 -0.80 % ±3.99%
esm/esm-loader-defaultResolve.js specifier='node:prefixed-nonexistent' n=1000 -1.62 % ±4.91%
esm/esm-loader-defaultResolve.js specifier='unprefixed-existing' n=1000 0.47 % ±1.24%
esm/esm-loader-defaultResolve.js specifier='unprefixed-nonexistent' n=1000 ** 1.11 % ±0.68%
esm/esm-loader-import.js specifier='./relative-existing.js' n=1000 1.86 % ±4.63%
esm/esm-loader-import.js specifier='./relative-nonexistent.js' n=1000 0.82 % ±1.10%
esm/esm-loader-import.js specifier='data:text/javascript,{i}' n=1000 -1.30 % ±1.70%
esm/esm-loader-import.js specifier='node:os' n=1000 -1.84 % ±3.60%
esm/esm-loader-import.js specifier='node:prefixed-nonexistent' n=1000 1.61 % ±4.81%
esm/import-meta.js n=1000 *** -5.10 % ±0.61%
esm/require-esm.js n=1000 exports='default' type='access' -1.44 % ±1.49%
esm/require-esm.js n=1000 exports='default' type='all' *** -1.72 % ±0.62%
esm/require-esm.js n=1000 exports='default' type='load' * -0.64 % ±0.51%
esm/require-esm.js n=1000 exports='named' type='access' 1.15 % ±1.81%
esm/require-esm.js n=1000 exports='named' type='all' *** -1.53 % ±0.57%
esm/require-esm.js n=1000 exports='named' type='load' ** -0.91 % ±0.58%

@aduh95

aduh95 commented Mar 13, 2025

Copy link
Copy Markdown
ContributorAuthor

Banchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1680/

Results
confidence improvement accuracy (*)
esm/esm-loader-defaultResolve.js specifier='node:os' n=1000 * -3.36 % ±2.64%
esm/esm-loader-defaultResolve.js specifier='node:prefixed-nonexistent' n=1000 * -4.92 % ±3.88%
esm/esm-loader-defaultResolve.js specifier='unprefixed-existing' n=1000 ** -1.88 % ±1.37%
esm/esm-loader-import.js specifier='data:text/javascript,{i}' n=1000 * 1.51 % ±1.27%
esm/import-meta.js n=1000 *** -4.65 % ±0.53%
esm/require-esm.js n=1000 exports='default' type='access' * -1.65 % ±1.50%
esm/require-esm.js n=1000 exports='default' type='load' *** -1.86 % ±0.62%
esm/require-esm.js n=1000 exports='named' type='all' *** -1.59 % ±0.59%
esm/require-esm.js n=1000 exports='named' type='load' *** -1.29 % ±0.51%

@aduh95

aduh95 commented Mar 13, 2025

Copy link
Copy Markdown
ContributorAuthor

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1682/

Results
confidence improvement accuracy (*)
esm/cjs-parse.js n=100 1.09 % ±1.13%
esm/detect-esm-syntax.js n=10000 type='with-package-json' -0.44 % ±0.85%
esm/detect-esm-syntax.js n=10000 type='without-package-json' 0.63 % ±0.74%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 ** 1.05 % ±0.68%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 0.31 % ±0.72%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 0.62 % ±0.64%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 0.45 % ±0.46%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.json' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 0.39 % ±0.76%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.json' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 0.37 % ±0.64%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.node' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 0.65 % ±0.72%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.node' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 *** 1.02 % ±0.46%
esm/esm-loader-defaultResolve.js specifier='./relative-existing.js' n=1000 * -1.57 % ±1.42%
esm/esm-loader-defaultResolve.js specifier='./relative-nonexistent.js' n=1000 -0.08 % ±1.70%
esm/esm-loader-defaultResolve.js specifier='node:os' n=1000 -0.26 % ±2.28%
esm/esm-loader-defaultResolve.js specifier='node:prefixed-nonexistent' n=1000 -1.75 % ±3.87%
esm/esm-loader-defaultResolve.js specifier='unprefixed-existing' n=1000 1.20 % ±1.25%
esm/esm-loader-defaultResolve.js specifier='unprefixed-nonexistent' n=1000 0.48 % ±0.87%
esm/esm-loader-import.js specifier='./relative-existing.js' n=1000 -1.16 % ±3.86%
esm/esm-loader-import.js specifier='./relative-nonexistent.js' n=1000 -0.48 % ±0.72%
esm/esm-loader-import.js specifier='data:text/javascript,{i}' n=1000 -0.41 % ±1.82%
esm/esm-loader-import.js specifier='node:os' n=1000 -1.91 % ±3.28%
esm/esm-loader-import.js specifier='node:prefixed-nonexistent' n=1000 0.33 % ±3.81%
esm/import-meta.js n=1000 *** -5.62 % ±0.69%
esm/require-esm.js n=1000 exports='default' type='access' ** -2.03 % ±1.45%
esm/require-esm.js n=1000 exports='default' type='all' *** -1.31 % ±0.62%
esm/require-esm.js n=1000 exports='default' type='load' *** -1.50 % ±0.70%
esm/require-esm.js n=1000 exports='named' type='access' -0.42 % ±1.68%
esm/require-esm.js n=1000 exports='named' type='all' *** -1.19 % ±0.49%
esm/require-esm.js n=1000 exports='named' type='load' *** -1.06 % ±0.46%

It's not any better, reverting

@aduh95aduh95 added the request-ci Add this label to start a Jenkins CI on a PR. label Mar 13, 2025
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Mar 13, 2025
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Comment threadsrc/node_modules.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: remove the v8:: qualifier and add v8::PropertyCallbackInfo to the using section at the top if it is not already there.

Comment threadsrc/node_modules.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Setting Data to a single internal object that has both dirname and filename set on it the first time either is accessed on it should work, yes?

Comment threadsrc/node_modules.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: can these please avoid the use of Check() and propagate errors up correctly?

@jsumners-nr

Copy link
Copy Markdown

Banchmark CI: ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1680
Results

confidence improvement accuracy (*)
esm/esm-loader-defaultResolve.js specifier='node:os' n=1000 * -3.36 % ±2.64%
esm/esm-loader-defaultResolve.js specifier='node:prefixed-nonexistent' n=1000 * -4.92 % ±3.88%
esm/esm-loader-defaultResolve.js specifier='unprefixed-existing' n=1000 ** -1.88 % ±1.37%
esm/esm-loader-import.js specifier='data:text/javascript,{i}' n=1000 * 1.51 % ±1.27%
esm/import-meta.js n=1000 *** -4.65 % ±0.53%
esm/require-esm.js n=1000 exports='default' type='access' * -1.65 % ±1.50%
esm/require-esm.js n=1000 exports='default' type='load' *** -1.86 % ±0.62%
esm/require-esm.js n=1000 exports='named' type='all' *** -1.59 % ±0.59%
esm/require-esm.js n=1000 exports='named' type='load' *** -1.29 % ±0.51%

The actual benchmarks site is asking for a login. How do we interpret this snippet?

@jasnell

Copy link
Copy Markdown
Member

hmm... looking at the benchmark results there it's just not clear to me that moving the init to native code has enough realized benefit. Moving into native does make the code a bit more difficult to maintain while also being slight slower. A lazy getter defined in JavaScript could likely achieve the same result while being easier for more people to help maintain. Not going to block on it tho... just not seeing the full benefit.

@aduh95

Copy link
Copy Markdown
ContributorAuthor

A lazy getter defined in JavaScript could likely achieve the same result while being easier for more people to help maintain

It's unclear whether a JS getter would be spec compliant, see the discussion in #57003 – that being said, I'm also a bit puzzled by the benchmark results

@JakobJingleheimer

Copy link
Copy Markdown
Member

What you've done here is pretty cool. But if the c++ implementation isn't faster, and we can stay spec compliant (which that discussion seemed to end that it is), I think the JS implementation would be better because it's more maintainable.

@aduh95
aduh95force-pushed the port-import-meta-native branch from f38430c to e7c7320CompareApril 25, 2025 14:27
@aduh95

aduh95 commented Apr 25, 2025

Copy link
Copy Markdown
ContributorAuthor

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1697/

Results
confidence improvement accuracy (*)
esm/detect-esm-syntax.js n=10000 type='without-package-json' *** -1.43 % ±0.76%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 ** 0.70 % ±0.42%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 *** 0.80 % ±0.33%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.json' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 ** 1.02 % ±0.60%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.json' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 *** 1.08 % ±0.60%
esm/esm-loader-defaultResolve.js specifier='node:os' n=1000 * 3.20 % ±3.07%
esm/import-meta.js n=1000 *** -7.21 % ±0.71%
esm/require-esm.js n=1000 exports='default' type='access' ** 2.28 % ±1.57%
esm/require-esm.js n=1000 exports='default' type='all' * -0.78 % ±0.62%
esm/require-esm.js n=1000 exports='default' type='load' * -0.74 % ±0.60%
esm/require-esm.js n=1000 exports='named' type='access' * -2.11 % ±1.64%
esm/require-esm.js n=1000 exports='named' type='load' *** -1.22 % ±0.54%

@aduh95

aduh95 commented Apr 25, 2025

Copy link
Copy Markdown
ContributorAuthor

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1698/

Results
confidence improvement accuracy (*)
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 *** 1.06 % ±0.49%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 * 0.80 % ±0.64%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 * 0.65 % ±0.50%
esm/import-meta.js valuesToRead='dirname-and-filename' n=1000 *** -6.91 % ±0.63%
esm/import-meta.js valuesToRead='dirname' n=1000 *** -6.04 % ±0.67%
esm/import-meta.js valuesToRead='filename' n=1000 *** -6.25 % ±0.75%
esm/require-esm.js n=1000 exports='default' type='all' * -0.82 % ±0.69%
esm/require-esm.js n=1000 exports='named' type='all' * -0.64 % ±0.54%
esm/require-esm.js n=1000 exports='named' type='load' * -0.56 % ±0.51%

@aduh95

aduh95 commented Apr 25, 2025

Copy link
Copy Markdown
ContributorAuthor

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1699/

Results
confidence improvement accuracy (*)
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='./index.js' packageJsonUrl='node_modules/test/package.json' n=10000 * 0.67 % ±0.55%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/non-exist' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 ** 0.77 % ±0.54%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 * 0.43 % ±0.37%
esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.node' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 * 0.68 % ±0.56%
esm/esm-loader-defaultResolve.js specifier='node:os' n=1000 * 2.12 % ±1.99%
esm/import-meta.js valuesToRead='dirname-and-filename' n=1000 *** -6.39 % ±0.70%
esm/import-meta.js valuesToRead='dirname' n=1000 *** -5.30 % ±0.70%
esm/import-meta.js valuesToRead='filename' n=1000 *** -4.77 % ±0.75%

@aduh95

Copy link
Copy Markdown
ContributorAuthor

Landed in 50cfc6c

@aduh95
aduh95 deleted the port-import-meta-native branch April 29, 2025 20:55
RafaelGSS pushed a commit that referenced this pull request May 1, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
RafaelGSS pushed a commit that referenced this pull request May 2, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
aduh95 added a commit that referenced this pull request May 6, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
aduh95 added a commit that referenced this pull request May 6, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
RafaelGSS pushed a commit that referenced this pull request May 14, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
aduh95 added a commit that referenced this pull request May 16, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
aduh95 added a commit that referenced this pull request May 17, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
aduh95 added a commit that referenced this pull request May 18, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
aduh95 added a commit that referenced this pull request May 19, 2025
PR-URL: #57286
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
@ghostghost mentioned this pull request Jun 8, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs that have at least one approval, no pending requests for changes, and a CI started.c++Issues and PRs that require attention from people who are familiar with C++.esmIssues and PRs related to the ECMAScript Modules implementation.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@aduh95@nodejs-github-bot@jsumners-nr@jasnell@JakobJingleheimer@geeksilva97@marco-ippolito