-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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(unstable): fast subset type checking of JSR dependencies #21873
Conversation
.default_missing_value(".") | ||
.value_hint(ValueHint::DirPath) | ||
.required(true), | ||
) |
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.
Removed for now because it was broken. A lot of our code currently resolves stuff like the config file being resolved based on the 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.
After some consideration I think we really need to have this soon - maybe as a quick-fix we could spawn subprocess in the correct CWD to it working that way?
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 seems easy to just do (cd some_dir && deno publish)
? Most people will be publishing from the directory they're in.
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 don't think I even used it in a CWD, not a big deal though. We can address it in a follow 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.
If you remove this, you can’t publish single modules in a workspace anymore. That seems annoying
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.
You can by not publishing from the root (instead you publish in the dir of the package)
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 added a test demonstrating this: https://github.com/denoland/deno/pull/21873/files#diff-4d2dc43bd5ca3db03f1a2ab469b13e12e9305f4934b714950429687eb2f09973
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.
@dsherret But this doesn't work if you have two deno.json (workspace level and package level), and you have import maps in both, and your package requires an import map entry from the workspace level one.
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.
@lucacasonato if it doesn't then that's a bug there (not a limitation with not being able to provide a publish directory)
.default_missing_value(".") | ||
.value_hint(ValueHint::DirPath) | ||
.required(true), | ||
) |
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.
After some consideration I think we really need to have this soon - maybe as a quick-fix we could spawn subprocess in the correct CWD to it working that way?
// this won't be type checked against because the subset | ||
// type graph will ignore it | ||
const invalidTypeCheck: number = ""; | ||
console.log(invalidTypeCheck); |
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.
Could you describe the reason for different behavior between this...
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 updated the comments for these. Let me know if the new comments don't explain it well enough.
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 good, thanks!
// this will be analyzed because the method above is missing an | ||
// explicit type which is required for the subset type graph | ||
const invalidTypeCheck: number = ""; | ||
console.log(invalidTypeCheck); |
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.
...and this?
// todo(dsherret): use a short lived cache to prevent parsing | ||
// source maps so often | ||
if let Ok(source_map) = | ||
SourceMap::from_slice(&fast_check_module.source_map) | ||
{ |
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.
Could you do it in this PR by adding a cache in apply_fast_check_source_map
? Or do you feel it's not gonna have much impact without it 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.
I opened #21877
@@ -586,7 +590,7 @@ fn op_resolve( | |||
let resolved_dep = graph | |||
.get(&referrer) | |||
.and_then(|m| m.esm()) | |||
.and_then(|m| m.dependencies.get(&specifier)) |
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.
Does this line applies fast check for all type checking in 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.
Yeah, only if it appears in the 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.
Wow, positively surprising that no other test failed!
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 internally does if let Some(module) = &self.fast_check { &module.dependencies } else { &self.dependencies }
.
.default_missing_value(".") | ||
.value_hint(ValueHint::DirPath) | ||
.required(true), | ||
) |
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 don't think I even used it in a CWD, not a big deal though. We can address it in a follow up
@@ -586,7 +590,7 @@ fn op_resolve( | |||
let resolved_dep = graph | |||
.get(&referrer) | |||
.and_then(|m| m.esm()) | |||
.and_then(|m| m.dependencies.get(&specifier)) |
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.
Wow, positively surprising that no other test failed!
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
Integrates denoland/deno_graph#346 ("fast check")
This leads to a major speedup of type checking of remote JSR dependencies in Deno that are distributed as TypeScript by only providing TypeScript with the code relevant to the public API of dependencies.
Performance Improvement Example
Before (no check cache):
After (no check cache):
How this works
If the public API or a type in the public API cannot be determined, then it falls back to not using this feature and instead uses the full TypeScript sources.
Since this is something hidden away in the runtime, we can drop this feature at any time or provide overrides to disable it.
This feature is not implemented in the LSP atm, but in that case it would expand to the full source once opening a remote dependency (ex. doing "go to definition" on a symbol that ends up in a remote dep), but otherwise it would use the subset.
Example
Given the following source:
We can strip out the non-relevant parts and end up with the following for type checking purposes:
Why not transform to a declaration file?
.d.ts
file.What about globals?
Globals can be defined in any file in TypeScript and if someone defined a global deep in their dependency then this wouldn't work. In this case, this feature only applies to JSR dependencies and we currently do not allow globals being defined in JSR deps. In the future we'll look at relaxing this restriction to likely require defining globals in a certain place. That would allow this to quickly check for globals there and maintain that code.