Skip to content

esm: avoid import.meta setup costs for unused properties - #57003

Closed
JakobJingleheimer wants to merge 3 commits into
nodejs:mainfrom
JakobJingleheimer:esm/avoid-setup-costs-for-unused-importmeta-props
Closed

esm: avoid import.meta setup costs for unused properties#57003
JakobJingleheimer wants to merge 3 commits into
nodejs:mainfrom
JakobJingleheimer:esm/avoid-setup-costs-for-unused-importmeta-props

Conversation

@JakobJingleheimer

@JakobJingleheimerJakobJingleheimer commented Feb 11, 2025

Copy link
Copy Markdown
Member

Currently, the cost of deriving import.meta.dirname and import.meta.filename is paid up-front, regardless of whether they are actually used. This can instead be delayed until they are accessed, and then to avoid re-paying the cost, overwrite the getter with the derived value.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-botnodejs-github-bot added esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run. labels Feb 11, 2025
@JakobJingleheimer
JakobJingleheimerforce-pushed the esm/avoid-setup-costs-for-unused-importmeta-props branch from 90d6aac to b3575a0CompareFebruary 11, 2025 11:34

@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.

For what it's worth, my personal time identity backed this out due to a lot of waffling and someone finally providing evidence against it -- #48740 (comment)

(Very easy to overlook that in all of the nonsense on that PR.)

@codecov

codecovBot commented Feb 11, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 93.93939% with 2 lines in your changes missing coverage. Please review.

Project coverage is 90.27%. Comparing base (3186468) to head (c3c12a4).
Report is 546 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/modules/esm/initialize_import_meta.js93.93%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #57003 +/- ##
==========================================
+ Coverage 89.13% 90.27% +1.14% 
==========================================
Files 665 630 -35 Lines 193125 186189 -6936 Branches 37182 36474 -708 ==========================================
- Hits 172136 168089 -4047 + Misses 13734 10979 -2755 + Partials 7255 7121 -134 
Files with missing linesCoverage Δ
lib/internal/modules/esm/initialize_import_meta.js98.16% <93.93%> (-1.84%)⬇️

... and 270 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.

@JakobJingleheimer

Copy link
Copy Markdown
MemberAuthor

(Very easy to overlook that in all of the nonsense on that PR.)

😆

For what it's worth, my personal time identity backed this out due to a lot of waffling and someone finally providing evidence against it -- #48740 (comment)

It looks like the spec was misquoted.

I'm not sure what Antoine was getting at with

I don't get it though, the getters are evaluated right away, there's no point in keeping them or am I missing something?

Getters are not run right away—that's their whole point.

@jsumners-nr

Copy link
Copy Markdown

I don't get it though, the getters are evaluated right away, there's no point in keeping them or am I missing something?

Getters are not run right away—that's their whole point.

They were in that specific implementation. But I was quite happy to stop churning on the detail.

I am not against these being getters. I'm just linking the history.

@ljharb

Copy link
Copy Markdown
Member

https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation

The spec’s intention is very much that import.meta only contains data properties. It’s surely possible to use C++ to make an object that appears to have data properties but avoids paying the up front cost, but it wouldnt be possible in JS.

As is, this change is observable to someone looking at property descriptors, and this i think needs to be semver major.

@hybrist

Copy link
Copy Markdown
Contributor

https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation

The spec’s intention is very much that import.meta only contains data properties. It’s surely possible to use C++ to make an object that appears to have data properties but avoids paying the up front cost, but it wouldnt be possible in JS.

As is, this change is observable to someone looking at property descriptors, and this i think needs to be semver major.

I agree with Bradley in the other thread that HostFinalizeImportMeta does exist in that algorithm and gives the host/nodejs explicit permission to make other changes to the object, including adding non-data properties.

I don't think the exact property descriptor is "part of the API" here but I don't feel strongly enough about it to say that it must be semver minor over major.

Comment threadlib/internal/modules/esm/initialize_import_meta.js
@ljharb

Copy link
Copy Markdown
Member

It absolutely allows it - but the intention was for freezing and not for making getters, as i recall.

@mcollinamcollina 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.

lgtm

@bmeck

Copy link
Copy Markdown
Member

@ljharb as I recall it was for freezing from Agoric side of convo and altering proto from web vendor side (including a potential desire for accessors from proto).

@ljharb

Copy link
Copy Markdown
Member

ah, I don't recall that second part.

@bmeck

Copy link
Copy Markdown
Member

@ljharb they never shipped it and likely never will at this point

@bmeck

Copy link
Copy Markdown
Member

an alternative that is still a data property and is lazy is to use https://v8.github.io/api/head/classv8_1_1Object.html#a918a985db244fdc1bde268741e840620

@JakobJingleheimer
JakobJingleheimerforce-pushed the esm/avoid-setup-costs-for-unused-importmeta-props branch from ed9b3cb to c3c12a4CompareApril 22, 2025 19:15

@ljharbljharb 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 still consider this a breaking change, but LGTM

@ljharbljharb added the semver-major PRs that contain breaking changes and should be released in the next major version. label Apr 22, 2025
@JakobJingleheimer

Copy link
Copy Markdown
MemberAuthor

Ah, damn. Looks like it will miss 24.0.0; I was thinking it still might land for that and breaking/non-breaking would be a discussion we don't have to have 😅 (aside from backport).

@ljharb

Copy link
Copy Markdown
Member

Doing it in C++ would make it nonbreaking, if that's preferred.

@JakobJingleheimer

Copy link
Copy Markdown
MemberAuthor

Doing it in C++ would make it nonbreaking, if that's preferred.

Mmm, I was hoping/expecting that approach to tick all the boxes. But it seems a mixed bag, IMO leaning towards the less ideal.

I was just planning to get this PR to a landable state so then we can decide A or B.

To me, the approach in this PR is in the vicinity of breaking territory in that it may be observable. But, I'm thinking it won't actually be tangible (and thus won't actually break anything).

@JakobJingleheimerJakobJingleheimer 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 Apr 22, 2025
@ljharb

Copy link
Copy Markdown
Member

I agree that breakage is unlikely, but semver doesn't deal in likelihoods :-)

fwiw it seems perfectly fine to land this on 25+, and then convert it to C++ in a future PR, at which point both commits would be maximally backportable together.

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

Copy link
Copy Markdown
Collaborator

@JakobJingleheimerJakobJingleheimer added commit-queue Add this label to land a pull request using GitHub Actions. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. labels Apr 23, 2025
@nodejs-github-botnodejs-github-bot added commit-queue-failed An error occurred while landing this pull request using GitHub Actions. and removed commit-queue Add this label to land a pull request using GitHub Actions. labels Apr 23, 2025
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator
Commit Queue failed
- Loading data for nodejs/node/pull/57003
✔ Done loading data for nodejs/node/pull/57003
----------------------------------- PR info ------------------------------------
Title esm: avoid `import.meta` setup costs for unused properties (#57003)
⚠ Could not retrieve the email or name of the PR author's from user's GitHub profile!
Branch JakobJingleheimer:esm/avoid-setup-costs-for-unused-importmeta-props -> nodejs:main
Labels semver-major, esm, author ready, needs-ci, commit-queue-squash
Commits 3
- esm: avoid `import.meta` setup costs for unused properties
- !fixup: correct autocomplete of prop name
- fixup!: add test case for re-assigning `dirname` & `filename`
Committers 1
- Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com>
PR-URL: https://github.com/nodejs/node/pull/57003
Reviewed-By: Jan Martin <jan.krems@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Jordan Harband <ljharb@gmail.com>
------------------------------ Generated metadata ------------------------------
PR-URL: https://github.com/nodejs/node/pull/57003
Reviewed-By: Jan Martin <jan.krems@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Jordan Harband <ljharb@gmail.com>
--------------------------------------------------------------------------------
ℹ This PR was created on Tue, 11 Feb 2025 10:54:37 GMT
✔ Approvals: 3
✔ - Jan Martin (@jkrems): https://github.com/nodejs/node/pull/57003#pullrequestreview-2785333954
✔ - Matteo Collina (@mcollina) (TSC): https://github.com/nodejs/node/pull/57003#pullrequestreview-2610219287
✔ - Jordan Harband (@ljharb): https://github.com/nodejs/node/pull/57003#pullrequestreview-2785323386
✘ semver-major requires at least 2 TSC approvals
✔ Last GitHub CI successful
ℹ Last Full PR CI on 2025-04-22T20:58:45Z: https://ci.nodejs.org/job/node-test-pull-request/66416/
- Querying data for job/node-test-pull-request/66416/
✔ Last Jenkins CI successful
--------------------------------------------------------------------------------
✔ Aborted `git node land` session in /home/runner/work/node/node/.ncu
https://github.com/nodejs/node/actions/runs/14614621512

@JakobJingleheimer

Copy link
Copy Markdown
MemberAuthor

Ah, needs 2 TSC approvals, not just 1.

@JakobJingleheimerJakobJingleheimer removed the commit-queue-failed An error occurred while landing this pull request using GitHub Actions. label Apr 23, 2025
@aduh95

aduh95 commented Apr 25, 2025

Copy link
Copy Markdown
Contributor

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

esm/esm-legacyMainResolve.js resolvedFile='node_modules/test/index.js' packageConfigMain='' packageJsonUrl='node_modules/test/package.json' n=10000 ** -0.80 % ±0.52%
esm/import-meta.js n=1000 *** -9.01 % ±0.81%

@JakobJingleheimer

Copy link
Copy Markdown
MemberAuthor

I don't know how to read that benchmark 😅

Could we also run CitGM? (I don't know how to trigger it)

@aduh95

Copy link
Copy Markdown
Contributor

The benchmark shows a worst result than #57286 for esm/import-meta.js, I guess that's not surprising, and is not a deal breaker I don't think. That being said, it'd probably be a good idea for me (or someone else) to go back to that other PR to see if where we could improve it as it would address Jordan concerns and be potentially better perf-wise

@aduh95

aduh95 commented Apr 29, 2025

Copy link
Copy Markdown
Contributor

Benchmark CI to include the results form #58056: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1710/

 confidence improvement accuracy (*)
esm/esm-loader-import.js specifier='node:prefixed-nonexistent' n=1000 * -3.67 % ±3.56%
esm/import-meta.js valuesToRead='dirname-and-filename' n=1000 *** -7.97 % ±0.62%
esm/import-meta.js valuesToRead='dirname' n=1000 *** -7.81 % ±0.82%
esm/import-meta.js valuesToRead='filename' n=1000 *** -6.14 % ±0.83%

@aduh95

Copy link
Copy Markdown
Contributor

Superseded by #57286

@aduh95aduh95 closed this Apr 29, 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.commit-queue-squashAdd this label to instruct the Commit Queue to squash all the PR commits into the first one.esmIssues and PRs related to the ECMAScript Modules implementation.needs-ciPRs that need a full CI run.semver-majorPRs that contain breaking changes and should be released in the next major version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@JakobJingleheimer@nodejs-github-bot@jsumners-nr@ljharb@hybrist@bmeck@aduh95@mcollina