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

feat(compat): integrate import map and classic resolutions in ESM resolution #12549

Merged

Conversation

bartlomieju
Copy link
Member

This commit integrates import map and "classic" resolutions in
the "--compat" mode when using ES modules; in effect
"http:", "https:" and "blob:" imports now work in compat mode.

The algorithm works as follows:

  1. If there's an import map, try to resolve using it and if succeeded
    return the specifier
  2. Try to resolve using "Node ESM resolution", and if succeeded return
    the specifier
  3. Fall back to regular ESM resolution

Copy link
Member

@kt3k kt3k left a comment

Choose a reason for hiding this comment

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

LGTM

@kt3k
Copy link
Member

kt3k commented Oct 26, 2021

I'd like @kitsonk to have another look

@guybedford
Copy link
Contributor

A few questions:

  1. Do the URL mappings in the import map apply to resolutions of the Node.js or traditional ESM resolver? It can be useful to consider these URL mappings as part of the finalization stage for all resolution exit paths when wanting to do global module replacements.
  2. Note that relative URL resolutions are always just relative URL resolutions in the Node.js resolver by design. Does this immediate exit happen here? In theory that means stage (1) can exit on all relative imports without even hitting the Node.js resolver, as a kind of short path. It's more architectural / technical detail, but worth considering.
  3. I assume import maps aren't implemented for require()? That seems fine, and can potentially change, although it could be worth considering these use cases as well.... Node.js would likely support import maps for both itself when it gets around to supporting import maps.

@bartlomieju
Copy link
Member Author

A few questions:

  1. Do the URL mappings in the import map apply to resolutions of the Node.js or traditional ESM resolver? It can be useful to consider these URL mappings as part of the finalization stage for all resolution exit paths when wanting to do global module replacements.

URL mappings in the import maps are applied first - if there is a match coming from import map that URL is used and resolution "short-circuits" without going through finalization stage (because import map might remap to http:, https: or blob: which are not allowed in Node resolution). I guess you're suggesting that import map resolution should be applied last in the finalization stage so that if Node resolution resolves "foo" to "./node_modules/foo/index.js", the file path should still be remapped. Is that correct?

  1. Note that relative URL resolutions are always just relative URL resolutions in the Node.js resolver by design. Does this immediate exit happen here? In theory that means stage (1) can exit on all relative imports without even hitting the Node.js resolver, as a kind of short path. It's more architectural / technical detail, but worth considering.

That's correct, if we resolve "./relative/path/to/foo.js` and there's an entry in import map that remaps this specifier then both Node and "regular" resolution are skipped.

  1. I assume import maps aren't implemented for require()? That seems fine, and can potentially change, although it could be worth considering these use cases as well.... Node.js would likely support import maps for both itself when it gets around to supporting import maps.

Correct, as mentioned in the previous PR our resolver implementation is split across Rust and TypeScript, where require() is implemented in the latter and thus doesn't take part in import map resolution as of now - or in other world require() works exactly like in Node without being able to leverage import map or http:, https: imports.

@guybedford I believe this is not the final form of the resolution algorithm and it will change still, do you consider this approach to be a wrong one? @kitsonk what do you think about it?

@kitsonk
Copy link
Contributor

kitsonk commented Oct 27, 2021

Yeah, I think the code here reflects what we discussed. It feels like something we want to maybe flesh out more test/cases scenarios, but it is just code and we can iterate on it.

@bartlomieju bartlomieju merged commit f77c570 into denoland:main Oct 28, 2021
@bartlomieju bartlomieju deleted the compat_wire_import_map_and_http_imports branch October 28, 2021 08:12
@DefinitelyMaybe
Copy link

Not sure if appropriate to add as it is early days on this but wanted to chime in.

Following from this tweet how was one meant to run rollup?

My first thoughts were along the lines of using the JavascriptAPI like so:

// main.js
import * as rollup from "https://esm.sh/rollup";
console.log(rollup);
// ...

And running deno run -A --unstable --compat .\main.js. Just trying to get off the ground yunno but that ran into node's esm loader [ERR_UNSUPPORTED_ESM_URL_SCHEME] from using the https

@bartlomieju
Copy link
Member Author

@DefinitelyMaybe if you pull from esm.sh you don't need to run with --compat flag. If you install rollup locally via npm install rollup then you can use ./node_modules/rollup/dist/cli.js as an entry point. I'm on mobile so can provide more instruction when I'm back at desk.

@DefinitelyMaybe
Copy link

DefinitelyMaybe commented Oct 28, 2021

oops. I'll give that a try.

sounds like still doing an npm install to generate the node_modules folder was [the/one-of] intended direction? or would urls from skypack work too?

also, sorry, by doc's before I meant the manual. I realize I should've also looked into the unstable api pages

@bartlomieju
Copy link
Member Author

oops. I'll give that a try.

sounds like still doing an npm install to generate the node_modules folder was [the/one-of] intended direction? or would urls from skypack work too?

With this PR landed you can use both, but again, if you want to use URL from skypack/esm/etc, you don't need to use --compat mode. Compat mode is meant to emulate Node environment and is thus most useful when you're trying to use modules installed via npm/yarn/pnpm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants