Design Meeting Notes, 8/31/2022
DanielRosenwasser opened this issue · 0 comments
DanielRosenwasser commented
Module Resolution Proposals
- What's the history?
classic- node-like extensionless resolution implemented wrongnode- a version of Node 11 and earlier resolutionnode16- a version of resolutiont that captures all the new Node 16 features for ESM.
- What's the problem?
- Bundlers support lots of useful things. TypeScript doesn't really capture their behavior.
- Example scenario:
- Your project starts off using the
noderesolution strategy. - You add a dependency which specifies an
exportsfield - but thenodestrategy doesn't understand that.- So TypeScript errors, but your bundler (e.g. Webpack) is fine.
- You swap to the
node16ornodenextmodule resolution options to fix it. - TypeScript starts erroring on another dependency because it has
"type": "module"but your project doesn't.- So TypeScript errors, but your bundler (e.g. Webpack) is fine.
- You switch your file to a module - either by renaming it to
.mtsor adding"type": "module"to yourpackage.json. - TypeScript starts erroring on a relative import because you didn't specify the extension.
- So TypeScript errors, but your bundler (e.g. Webpack) is fine.
- You specify the
.jsextension as TypeScript suggests. - Your bundler can no longer resolve the relative import because it doesn't know that a file ending in
.jsis supposed to map to.ts.- So your bundler (e.g. Webpack) errors, but TypeScript is fine.
- You have to now configure your bundler further.
- Your project starts off using the
- Friction!
- Many behaviors of Node16 have been brought into bundlers, and bundlers can continue to provide many features that provide a nice UX (e.g. extensionless resolution).
- Maybe a new
hybridmode?- Name is bikesheddable.
- A basis for bundlers and maybe more.
node_moduleslookups- Index files (e.g.
./folder->./folder/index.ts) - Extensionless (e.g.
./foo/bar->./foo/bar.ts) - Resolution of the
exportsfield ofpackage.json .mts,.cts,"type"don't matter. Everything is
minimal- A basis for browsers and maybe more.
- No
node_modulesetc. - Just relative URL paths with required extensions.
- URLs?
- Yes,
%20is a space. - So
./our%20assets/file.jsisour assets/file.js.
- Yes,
- URLs?
- Does
import "bar.js"resolve to relative in browser contexts?- Have to check - believe WHATWG reserved this?
- We probably don't want to resolve relative even if that's the case.
- Maybe
nodebecomesnode-legacy- Feedback from the TC39 tools group was
node->node-legacymight not be a good call. Maybe call itnode11 - Does it make sense to call this
node-cjs?- But it's the old
node-cjs.
- But it's the old
- Feedback from the TC39 tools group was
- So it sounds like this new
hybrid/conventionalmode really thinks of everything as possibly synchronous ES modules.- How does this work with top-level
await? - Some runtime shimming
- Things are a little different...but mostly works.
- How does this work with top-level
- Name the
hybridmode--moduleResolution bundler?- Accurate now, but
- ts-node
- bun
- etc.
- Not just one runtime.
- Accurate now, but
- The name should communicate the scenario.
- Yes, but the scenarios keep changing.
Yarn Plug'n'Play
- Way to work around some of the shortcomings from package manager installation and package resolution.
- Instead extracting all packages fully into
node_modulesand having your code resolve from the disk at runtime, Yarn calculates all the information ahead of time for packages. - Yarn creates a
.pnp.cjsfile that interceptsrequire(and sometimes file system APIs) - What's the advantage?
- It's faster because it doesn't have to shuffle directory trees around.
- Just plop a cached
zip - "just check in your
node_modules"
- Gotcha?
- Non-standard-ish
- Nothing in Node that emulates it.
- Have discussed it a few times. Why revisiting?
- Resolution steps have been published.
- Where do these
zipfiles come from?- There's a cache, but it gets created from the npm registry.
- You can navigate it with the right VS Code extension!
- It causes crashes because we don't think files can exist in zip files.
- Importing a resolver JS file is no longer a hard requirement.
- Statically resolvable and specified.
- Need to be able to read from a
.zipfile
- PnP + "check in your dependencies" is one of the few things that mitigates supply chain attacks.
- But
npm cietc? - Not really the reason for this. It is a nice bonus maybe. But the convenience is just fast workflows.
- But
- Okay, it's not in an executable file. Where is it?
.pnp.data.json
- Great, we have the JSON, so how do we do the zip file support?
- Have to roll our own or add a dependency.
- Old
.cjsfile did all this for us. It was nice!- But did it? We still need to support path completion, virtualizing files, etc. Things work now, but the demo keeps crashing on the mounted files.
- zip support is technically optional
- But not really?
- What about the old competing crux? Other possible strategies here?
- Versioning concerns of specification?
- Wrong abstraction? Shouldn't this be in Node.js anyway?
- That's what's Yarn is trying to do out of band anyway - provide a way to leverage the right hooks.
- Doesn't matter, TypeScript and friends need to reimplement their own custom resolution rules anyway.
- Can we make it easier for Yarn to patch these?
- Unclear - seems very hard.
- Has to patch the
Systemhost, theModuleResolutionHost, and more.
- How does this compose between all the upcoming module work?
- Substantial cost - short-term and long-term.
- Last time the executable JS was the biggest concern. Are we changing our view?
- Took time to address the original concerns.
- Not seeing community convergence between different package managers and runtimes - though is this a blocker?
- Hard to promise that we can keep up with updates.
- What are the concerns?
- Can't add every custom resolution algorithm - adding this means it'll be there forever.
- Not clear on what the spec will add over time.
- What can we do to alleviate here? Work with the existing process?
- Is there a way to make patching easier?