-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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): 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 |
cli/compat/node_module_loader.rs
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the type checking problem might be somehow related to this bit...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.ts
that 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
cli/compat/esm_resolver.rs
Outdated
Ok(url) | ||
} | ||
|
||
fn to_file_path(url: &Url) -> PathBuf { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?
@@ -316,14 +291,29 @@ impl ProcState { | |||
); | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you can't use import maps with
--compat
mode?
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
NodeEsmResolver
would take an optionalResolver
that 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
NodeEsmResolver
should 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
NodeEsmResolver
should 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 innode_modules
with 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
cli/compat/mod.rs
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use raw.githubusercontent instead of deno.land?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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)