Skip to content
This repository has been archived by the owner on Apr 16, 2020. It is now read-only.

ESM_FORMAT: Avoid reading package.json when extension is unambiguous #33

Closed
wants to merge 14 commits into from

Conversation

mathiasbynens
Copy link
Contributor

It’s wasteful to load the package.json even if the extension is unambiguous. This patch optimizes for the zero-config case by avoiding needless package.json loads.

With this patch, the mental model becomes a lot simpler too:

  • .cjs means commonjs
  • .mjs means module

See discussion thread: https://twitter.com/mathias/status/1096167102455709696

Checklist

guybedford and others added 13 commits February 15, 2019 09:06
Refs: nodejs/modules#180

PR-URL: nodejs#6
Reviewed-By: Myles Borins <MylesBorins@google.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Refs: nodejs/modules#180

PR-URL: nodejs#6
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Refs: nodejs/modules#180

PR-URL: nodejs#6
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Refs: nodejs/modules#180

PR-URL: nodejs#6
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
PR-URL: nodejs#6
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
PR-URL: nodejs#6
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Myles Borins <mylesborins@google.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
PR-URL: nodejs#6
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Myles Borins <mylesborins@google.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
It’s wasteful to load the package.json even if the extension is unambiguous. This patch optimizes for the zero-config case by avoiding needless package.json loads.

With this patch, the mental model becomes a lot simpler too:

- `.cjs` means `commonjs`
- `.mjs` means `module`

See discussion thread: https://twitter.com/mathias/status/1096167102455709696
@ljharb
Copy link
Member

ljharb commented Feb 16, 2019

I don’t think this is a future-looking optimization; eventually package.json should be able to override any extension to parse in any way.

@mathiasbynens
Copy link
Contributor Author

mathiasbynens commented Feb 16, 2019

That’s what’s under discussion. IMHO it’s worth carving out .cjs and .mjs since they’re unambiguous, and only enable overriding other extensions. From the Twitter thread it sounded like people were on board with that.

We need to weigh the cost of allowing .cjs and .mjs to be overridden (i.e. load package.json all the time) with the performance benefits of not having to do so for the zero-config case.

@robpalme
Copy link

This PR looks good.

My view is that package.json is about defining package-scoped things, whereas extensions/pragmas are a way of specialising/overriding behaviour on a per-file basis.

This locality simplifies the mental model and eliminates a data-dependency.

@guybedford
Copy link
Contributor

Thanks @mathiasbynens for the PR. This is a simplification of the existing spec that seems sensible to me.

There is effectively only one behavioural change here from what was written previously and that is that previously if there was no package boundary, we would load .mjs files as CommonJS which seems wrong anyway.

This sounds like a spec bug to me, where the fix happens to enable an optimization.

We as a group can decide over time whether we want that optimization to remain, but what we're really deciding from a behavioural perspective is if node x.mjs where there is no package.json at all should load as a module.

@mathiasbynens
Copy link
Contributor Author

what we're really deciding from a behavioural perspective is if node x.mjs where there is no package.json at all should load as a module.

+1 FWIW, there is precedent for this in both jsc and d8. It seems reasonable, and even expected, to me.

@guybedford
Copy link
Contributor

Note that the implementation already does this too, so that this is actually just a spec bug.

@GeoffreyBooth
Copy link
Member

This is fine for where the implementation is now, but if we add package exports we'll always need to read package.json to know what the valid paths inside a package are. Also package-level loaders, if added, would also require always reading package.json. Ditto for file extension configuration like @ljharb said.

Another point is if type: module ever defines anything in a package more than just file extension mappings, separately than what .mjs defines (globals like Buffer come to mind, and the discussion about making them package-scoped).

But for right now, sure.

Copy link
Contributor

@guybedford guybedford left a comment

Choose a reason for hiding this comment

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

Just noticed this line is missing.

doc/api/esm.md Outdated Show resolved Hide resolved
Copy link
Member

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

@ljharb ljharb left a comment

Choose a reason for hiding this comment

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

We don’t even have consensus that the cjs extension will be a thing, and no extension should be special - if any of them can’t br overridden, then none of them can (including js)

@guybedford
Copy link
Contributor

@ljharb please read #33 (comment) and then let me know if you want to revise your comment.

@ljharb
Copy link
Member

ljharb commented Feb 16, 2019

@guybedford that comment hasn’t made anything clear to me about why I’d revise it.

In the absence of a package.json, and perhaps when run as an entry point, it makes sense that a file extension unambiguously determines the parse goal, but if a package.json is present (and certainly when it’s not an entry point), it must always be consulted regardless of the file extension. No extension should be special; either they can all be overridden from package.json or none of them can.

Separately, adding the cjs extension, without any consensus besides apparent side channel discussions about it, isn’t something that should be done via a PR.

@guybedford
Copy link
Contributor

In the absence of a package.json, and perhaps when run as an entry point, it makes sense that a file extension unambiguously determines the parse goal

Currently, by the spec, node x.mjs where there is no package.json will execute as CommonJS, so this is not the case as written.

The change here ONLY changes the above. That is the only behavioural change.

@nodejs-ci nodejs-ci force-pushed the modules-lkgr branch 2 times, most recently from bd5c877 to 0237465 Compare March 7, 2019 09:06
@MylesBorins MylesBorins force-pushed the modules-lkgr branch 2 times, most recently from 484d1fb to 7efc53d Compare March 18, 2019 22:07
@nodejs-ci nodejs-ci force-pushed the modules-lkgr branch 3 times, most recently from c7fa700 to d69f765 Compare March 21, 2019 08:06
@MylesBorins MylesBorins force-pushed the modules-lkgr branch 5 times, most recently from 335d584 to 9a343ce Compare March 21, 2019 19:09
@nodejs-ci nodejs-ci force-pushed the modules-lkgr branch 3 times, most recently from 3a00b51 to bc101f6 Compare March 24, 2019 08:06
@MylesBorins MylesBorins force-pushed the modules-lkgr branch 3 times, most recently from fd5b55a to 3a40599 Compare March 27, 2019 02:42
@Trott
Copy link
Member

Trott commented Apr 9, 2020

I imagine this can/should be closed at this point? Or if not closed, then at least transferred to the main repository?

@MylesBorins MylesBorins closed this Apr 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants