feat(compat): Node CJS and ESM resolvers#12424
Conversation
|
So I removed injection of import map when Ie. globals are no longer part of type-checked module graph, even though they are still injected using |
| // TODO(bartlomieju): this is hacky, remove | ||
| // needed to add it here because `deno_std/node` has | ||
| // triple-slash references and they should still resolve | ||
| // the regular way (I think) | ||
| if referrer.as_str().starts_with("https://deno.land/std") { | ||
| return referrer.join(specifier).map_err(AnyError::from); | ||
| } |
There was a problem hiding this comment.
I think the type checking problem might be somehow related to this bit...
There was a problem hiding this comment.
Actually, I think the problem stems from the fact that deno.land/std/node/global.ts is not part of the graph roots...
There was a problem hiding this comment.
It will be part of the graph, but I think the problem is that it isn't being "imported" anywhere from the view of TypeScript. So while the module is available to be loaded, it doesn't get loaded, and therefore its globals don't get added to the global scope.
So there are couple options, I think:
- Use a synthetic module like we do for eval, to do the importing.
- We create a
node/globals.d.tsthat is an ambient declaration and we import that into the graph.
While I am not a fan of the synthetic modules, I think it might be the only way to do it. It would also mean you don't have to do any "side loading" of modules either, as the synthetic module should import everything as the "root" of the compat graph.
There was a problem hiding this comment.
Thanks! The synthetic module approach seems reasonable to me. I will look up some existing examples and try to fix it.
There was a problem hiding this comment.
So I just manually added node/global.ts to roots that is passed to the module graph. This is probably ugly solution but works for now. I was unable to figure out how to do "synthetic module".
|
I want to land this PR before 1.15.2 is released (so probably tomorrow), let me know if you want me to integrate this resolution in all possible subcommands or is it enough just for The CI will stay red until new version of @kitsonk @dsherret I would appreciate reviews, especially around integration with I believe we can punt on the remaining points from the first comment till next release. |
| Ok(url) | ||
| } | ||
|
|
||
| fn to_file_path(url: &Url) -> PathBuf { |
There was a problem hiding this comment.
I believe we have these sorts of things elsewhere in the code base. Is there are specific reason why we aren't DRY-ing this up?
There was a problem hiding this comment.
I ported everything from codebase as-is to have the least amount of divergence; I guess we could DRY this up in a follow up?
| let maybe_locker = as_maybe_locker(self.lockfile.clone()); | ||
| let maybe_imports = self.get_maybe_imports(); | ||
| let maybe_resolver = | ||
| let node_resolver = NodeEsmResolver; |
There was a problem hiding this comment.
So you can't use import maps with --compat mode?
Ideally the NodeEsmResolver would take an optional Resolver that it backs off to.
There was a problem hiding this comment.
So you can't use import maps with
--compatmode?
Currently no, I haven't seen a Node package that used import map. Is there a concrete use case right now to support import map?
Ideally the
NodeEsmResolverwould take an optionalResolverthat it backs off to.
I'm not sure what you mean, could you expand on that? Are you suggesting that NodeEsmResolver should fallback to our regular module resolution? (And in turn support http(s) imports too)
There was a problem hiding this comment.
Is there a concrete use case right now to support import map?
What happens when someone specifies --compat --importmap import_map.json?
I'm not sure what you mean, could you expand on that? Are you suggesting that
NodeEsmResolvershould fallback to our regular module resolution? (And in turn support http(s) imports too)
I am not exactly sure what I am saying. So you are saying the objective of --compat mode is to not allow existing Deno code to run? So there is no way anyone can use --compat as a temporary crutch and that they have to have all their dependencies loaded in node_modules with no opportunity to use the Deno features like remote imports, data URLs, blob URLs, import maps, etc?
There was a problem hiding this comment.
Is there a concrete use case right now to support import map?
What happens when someone specifies
--compat --importmap import_map.json?
Right now nothing, import map will be ignored - I can make the two flags mutually exclusive for now.
I'm not sure what you mean, could you expand on that? Are you suggesting that
NodeEsmResolvershould fallback to our regular module resolution? (And in turn support http(s) imports too)I am not exactly sure what I am saying. So you are saying the objective of
--compatmode is to not allow existing Deno code to run? So there is no way anyone can use--compatas a temporary crutch and that they have to have all their dependencies loaded innode_moduleswith no opportunity to use the Deno features like remote imports, data URLs, blob URLs, import maps, etc?
At the moment this is the case - --compat doesn't try to marry the two resolutions. That said data URLs and blob URLs should still work, because they are supported by Node. In theory this is a simple change to make - we could try to do regular resolution before falling back to Node resolution, however I'm unsure right now of ramifications of such decision. I'll be happy to discuss this in detail on the next meeting, but I'm feeling like it's something we could address in the next iteration.
| import_map_resolver.as_ref().map(|im| im.as_resolver()) | ||
| }; | ||
| // TODO(bartlomieju): this is very make-shift, is there an existing API | ||
| // that we could include it like with "maybe_imports"? |
There was a problem hiding this comment.
I do think there is a way, I think we need to modify the logic that gets the roots for tsc.
I would create an issue and assign it to me to clean up post this PR.
| // each release, a better mechanism is preferable, but it's a quick and dirty | ||
| // solution to avoid printing `X-Deno-Warning` headers when the compat layer is | ||
| // downloaded | ||
| static STD_URL_STR: &str = "https://raw.githubusercontent.com/denoland/deno_std/b83eb65244c676608a69205569bd294113476464/"; |
There was a problem hiding this comment.
Why use raw.githubusercontent instead of deno.land?
There was a problem hiding this comment.
Because the code used is not yet available in an std release. I assume Bartek will update this during the release process once std has been cut.
There was a problem hiding this comment.
This circular dependency is obviously not ideal. I think we'll have to bring std/node/module.ts into CLI... but let's release like this for now.
There was a problem hiding this comment.
This circular dependency is obviously not ideal. I think we'll have to bring std/node/module.ts into CLI... but let's release like this for now.
std/node/module.ts depends on other modules. I think we should just bring all of std/node into the CLI.
So now all methods are ported, there are a few missing bits:
package.json(need to figure out if Node does that globally or per-isolateit's per isolate)