-
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(node): stabilize detecting if CJS via "type": "commonjs"
in a package.json
#26439
Conversation
We should check how this affects popular frameworks/libraries before merging |
Yeah I think we’ll have to wait to fix this one with the stabilization of unstable-detect-cjs |
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
--unstable-detect-cjs
)"type": "commonjs"
in a package.json
} | ||
DenoSubcommand::Run(run_flags) => { | ||
if run_flags.is_stdin() { | ||
resolve_url_or_path("./$deno$stdin.ts", self.initial_cwd())? | ||
resolve_url_or_path("./$deno$stdin.mts", self.initial_cwd())? |
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.
Uses mts now so that these commands continue using esm even if the current directory has a "type": "commonjs"
@@ -797,6 +832,7 @@ impl FileSystemDocuments { | |||
pub fn get( | |||
&self, | |||
specifier: &ModuleSpecifier, | |||
is_cjs_resolver: &LspIsCjsResolver, |
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.
We need to split up data/storage and services that act on that data in the lsp. Passing around these "services" as method parameters (horizontal movement) is bad because it makes introducing new functionality tedious, verbose, and noisy. I've continued doing this here though because it would be too much of a refactor for 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.
That's reasonable - maybe open an issue to refactor it and add it to Q4 project board?
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.
Opened #26847
@@ -182,6 +185,8 @@ impl LspScopeResolver { | |||
.resolve_req_reference( | |||
&req_ref, | |||
&referrer, | |||
// todo(dsherret): this is wrong because it doesn't consider CJS referrers | |||
NodeModuleKind::Esm, |
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 is ok for now :)
Ideally we'd store this keyed on NodeModuleKind
as well because resolution could differ.
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.
Open an issue for this TODO, especially if you have an example program that will not work correctly in the LSP
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 opened #26846
#[derive(Debug)] | ||
pub struct LspCjsTracker { | ||
cjs_tracker: Arc<CjsTracker>, | ||
} |
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.
We don't use the cjs tracker in the lsp anymore. Instead we inspect the state of the documents each time.
@@ -732,7 +735,7 @@ delete Object.prototype.__proto__; | |||
/** @type {Array<[string, ts.Extension] | undefined>} */ | |||
const resolved = ops.op_resolve( | |||
base, | |||
isCjsCache.get(base) ?? false, | |||
containingSourceFile?.impliedNodeFormat === ts.ModuleKind.CommonJS, |
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.
Doing this is better.
cli/args/mod.rs
Outdated
self.flags.unstable_config.detect_cjs | ||
|| self.workspace().has_unstable("detect-cjs") | ||
pub fn detect_cjs(&self) -> bool { | ||
self.workspace().package_jsons().next().is_some() |
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 this correct? Doesn't it check for existence of package.json
and not consulting if it has type: "commonjs"
?
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 is only to activate the feature of it searching for the closest package.json files on every ambiguous module load. That means only projects with a package.json get opted into this feature and other Deno programs won't have the perf penalty of the extra work.
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.
That makes sense, consider adding a docstring here to avoid confusion in the future.
@@ -182,6 +185,8 @@ impl LspScopeResolver { | |||
.resolve_req_reference( | |||
&req_ref, | |||
&referrer, | |||
// todo(dsherret): this is wrong because it doesn't consider CJS referrers | |||
NodeModuleKind::Esm, |
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.
Open an issue for this TODO, especially if you have an example program that will not work correctly in the LSP
…ary main entrypoints, and various small improvements/tests
Ok(None) | ||
} | ||
} | ||
} |
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.
Fixes #26742
The issue here is previously we happened to resolve these kind of entrypoints because it would try running the specifier as a CJS entrypoint with an "unknown" media type.
Stabilizes --unstable-detect-cjs.
This will respect
"type": "commonjs"
in a package.json to determine if.js
/.jsx
/.ts
/.tsx` files are CJS or ESM. If the file is found to be ESM it will be loaded as ESM though.Breaking change to remove referrer based CJS/ESM assignment
An extremely important part of module resolution is the referrer should never impact if a file is considered ESM or CJS. This should be done solely based on the file itself without any other context (in other words, it should only be based on its location or its contents).
It seems that
require(...)
in Deno was treating.js
modules outside a node_modules folder as CJS and then falling back to ESM. This means that Deno could potentially load the same module twice. This fix partly fixes #26438 but it seems like there's still something else going on still.This bug fix will break some existing code, but it will also make some other code work. The code that gets broken by this can be fixed by adding an explicit
"type": "commonjs"
to the closest package.json file.Todo:
Closes #26225
Closes #26742