Fixes two issues:
- If a cached packument was out of date and missing a version from the
lockfile, we would fail. Instead we should try again with a forced
re-fetch
- We weren't threading through the workspace patch packages correctly
This extracts out the shared libraries and `.node` native modules to a
temp file and opens them from there. **This means that this
implementation will not work in every scenario.** For example, a library
could require other files that only exist in the in-memory file system.
To solve that, we'll introduce
https://github.com/denoland/deno/issues/28918 later or adapt this
solution to solve more issues.
Additionally, this will not work when run on readonly file systems.
Fixes#27264. Fixes https://github.com/denoland/deno/issues/28161.
Currently the new lockfile version is gated behind an unstable flag
(`--unstable-lockfile-v5`) until the next minor release, where it will
become the default.
The main motivation here is that it improves startup performance when
using the global cache or `--node-modules-dir=auto`.
In a create-next-app project, running an empty file:
```
❯ hyperfine --warmup 25 -N --setup "rm -f deno.lock" "deno run --node-modules-dir=auto -A empty.js" "deno-this-pr run --node-modules-dir=auto -A empty.js" "deno-this-pr run --node-modules-dir=auto --unstable-lockfile-v5 empty.js" "deno run --node-modules-dir=manual -A empty.js" "deno-this-pr run --node-modules-dir=manual -A empty.js"
Benchmark 1: deno run --node-modules-dir=auto -A empty.js
Time (mean ± σ): 247.6 ms ± 1.7 ms [User: 228.7 ms, System: 19.0 ms]
Range (min … max): 245.5 ms … 251.5 ms 12 runs
Benchmark 2: deno-this-pr run --node-modules-dir=auto -A empty.js
Time (mean ± σ): 169.8 ms ± 1.0 ms [User: 152.9 ms, System: 17.9 ms]
Range (min … max): 168.9 ms … 172.5 ms 17 runs
Benchmark 3: deno-this-pr run --node-modules-dir=auto --unstable-lockfile-v5 empty.js
Time (mean ± σ): 16.2 ms ± 0.7 ms [User: 12.3 ms, System: 5.7 ms]
Range (min … max): 15.2 ms … 19.2 ms 185 runs
Benchmark 4: deno run --node-modules-dir=manual -A empty.js
Time (mean ± σ): 16.2 ms ± 0.8 ms [User: 11.6 ms, System: 5.5 ms]
Range (min … max): 14.9 ms … 19.7 ms 187 runs
Benchmark 5: deno-this-pr run --node-modules-dir=manual -A empty.js
Time (mean ± σ): 16.0 ms ± 0.9 ms [User: 12.0 ms, System: 5.5 ms]
Range (min … max): 14.8 ms … 22.3 ms 190 runs
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
Summary
deno-this-pr run --node-modules-dir=manual -A empty.js ran
1.01 ± 0.08 times faster than deno run --node-modules-dir=manual -A empty.js
1.01 ± 0.07 times faster than deno-this-pr run --node-modules-dir=auto --unstable-lockfile-v5 empty.js
10.64 ± 0.60 times faster than deno-this-pr run --node-modules-dir=auto -A empty.js
15.51 ± 0.88 times faster than deno run --node-modules-dir=auto -A empty.js
```
When using the new lockfile version, this leads to a 15.5x faster
startup time compared to the current deno version.
Install times benefit as well, though to a lesser degree.
`deno install` on a create-next-app project, with everything cached
(just setting up node_modules from scratch):
```
❯ hyperfine --warmup 5 -N --prepare "rm -rf node_modules" --setup "rm -rf deno.lock" "deno i" "deno-this-pr i" "deno-this-pr i --unstable-lockfile-v5"
Benchmark 1: deno i
Time (mean ± σ): 464.4 ms ± 8.8 ms [User: 227.7 ms, System: 217.3 ms]
Range (min … max): 452.6 ms … 478.3 ms 10 runs
Benchmark 2: deno-this-pr i
Time (mean ± σ): 368.8 ms ± 22.0 ms [User: 150.8 ms, System: 198.1 ms]
Range (min … max): 344.8 ms … 397.6 ms 10 runs
Benchmark 3: deno-this-pr i --unstable-lockfile-v5
Time (mean ± σ): 211.9 ms ± 17.1 ms [User: 7.1 ms, System: 177.2 ms]
Range (min … max): 191.3 ms … 233.4 ms 10 runs
Summary
deno-this-pr i --unstable-lockfile-v5 ran
1.74 ± 0.17 times faster than deno-this-pr i
2.19 ± 0.18 times faster than deno i
```
With lockfile v5, a 2.19x faster install time compared to the current
deno.
Deno.serve `Request` abort signals are aborted by default even when it
is finished successfully. This PR gates this behavior behind the
"legacy_abort" which is the default right now.
Turning the `no_legacy_abort` runtime option on is a **breaking change**
and will only abort request signals when there is a failure, thereby
cannot be used to determine if the request finished. This aligns with
`fetch` API.
Ref https://github.com/denoland/deno/issues/27005
This adds support for using a local copy of an npm package.
```js
// deno.json
{
"patch": [
"../path/to/local_npm_package"
],
// required until Deno 2.3, but it will still be considered unstable
"unstable": ["npm-patch"]
}
```
1. Requires using a node_modules folder.
2. When using `"nodeModulesDir": "auto"`, it recreates the folder in the
node_modules directory on each run which will slightly increase startup
time.
3. When using the default with a package.json (`"nodeModulesDir":
"manual"`), updating the package requires running `deno install`. This
is to get the package into the node_modules directory of the current
workspace. This is necessary instead of linking because packages can
have multiple "copy packages" due to peer dep resolution.
Caveat: Specifying a local copy of an npm package or making changes to
its dependencies will purge npm packages from the lockfile. This might
cause npm resolution to resolve differently and it may end up not using
the local copy of the npm package. It's very difficult to only
invalidate resolution midway through the graph and then only rebuild
that part of the resolution, so this is just a first pass that can be
improved in the future. In practice, this probably won't be an issue for
most people.
Another limitation is this also requires the npm package name to exist
in the registry at the moment.
Adds support for re-exporting an ES module from a CJS one and then
importing the CJS module from ESM. Also fixes a bug where require esm
wasn't working in deno compile.
In particular this helps startup of the TSC isolate because
`00_typescript.js` can use the code cache.
Overall, this offsets a fair bit of the hit we took when we removed the
TSC snapshot.
```
❯ hyperfine --warmup 5 -p "rm -rf ~/Library/Caches/deno/check_cache_v2" "./deno-this-pr check main.ts" "./deno-no-snapshot check main.ts" "./deno-with-snapshot check main.ts"
Benchmark 1: ../../deno/target/release-lite/deno check main.ts
Time (mean ± σ): 145.7 ms ± 3.6 ms [User: 347.6 ms, System: 36.9 ms]
Range (min … max): 142.2 ms … 155.9 ms 19 runs
Benchmark 2: ./deno-no-snapshot check main.ts
Time (mean ± σ): 195.4 ms ± 3.3 ms [User: 397.7 ms, System: 34.9 ms]
Range (min … max): 192.1 ms … 206.0 ms 15 runs
Benchmark 3: ./deno-with-snapshot check main.ts
Time (mean ± σ): 109.0 ms ± 2.2 ms [User: 155.9 ms, System: 19.3 ms]
Range (min … max): 106.5 ms … 118.0 ms 26 runs
Summary
./deno-with-snapshot check main.ts ran
1.34 ± 0.04 times faster than ./deno-this-pr check main.ts
1.79 ± 0.05 times faster than ./deno-no-snapshot check main.ts
```
This commit changes the TS host implementation
in the LSP to use the same snapshot as the runtime worker
and web worker use.
This is due to upcoming V8 upgrade that might require
that all isolates in the same process use the exact same
snapshot.
Allows easily constructing a `DenoResolver` using the exact same logic
that we use in the CLI (useful for dnt and for external bundlers). This
code is then used in the CLI to ensure the logic is always up-to-date.
```rs
use std::rc::Rc;
use deno_resolver:🏭:ResolverFactory;
use deno_resolver:🏭:WorkspaceFactory;
use sys_traits::impls::RealSys;
let sys = RealSys;
let cwd = sys.env_current_dir()?;
let workspace_factory = Rc::new(WorkspaceFactory::new(sys, cwd, Default::default()));
let resolver_factory = ResolverFactory::new(workspace_factory.clone(), Default::default());
let deno_resolver = resolver_factory.deno_resolver().await?;
```
This is achieved by storing CJS export analysis ahead of time in the
executable, which should also improve the performance of `denort` by
this never being done anymore (I'm too lazy atm to bench this, but it
will be significant for some programs).
This slightly degrades the performance of CJS export analysis on
subsequent runs because I changed it to no longer cache in the DENO_DIR
with this PR (denort now properly has no idea about the DENO_DIR). We'll
have to change it to embed this data in the binary and that will also
allow us to get rid of swc in denort (will do that in a follow-up PR).
Instead of hard erroring, we now surface module not found errors as
TypeScript diagnostics (we have yet to show the source code of the
error, but something we can improve over time).
Currently deno eagerly caches all npm packages in the workspace's npm
resolution. So, for instance, running a file `foo.ts` that imports
`npm:chalk` will also install all dependencies listed in `package.json`
and all `npm` dependencies listed in the lockfile.
This PR refactors things to give more control over when and what npm
packages are automatically cached while building the module graph.
After this PR, by default the current behavior is unchanged _except_ for
`deno install --entrypoint`, which will only cache npm packages used by
the given entrypoint. For the other subcommands, this behavior can be
enabled with `--unstable-npm-lazy-caching`
Fixes#25782.
---------
Signed-off-by: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com>
Co-authored-by: Luca Casonato <hello@lcas.dev>
This commit adds support for understanding "workpace:^"
and "workspace:~" version constraints in npm/pnpm workspaces.
This is done by upgrading various crates to their latest versions.
Closes https://github.com/denoland/deno/issues/26726
---------
Co-authored-by: David Sherret <dsherret@gmail.com>
This resurrects the `--unstable-detect-cjs` flag (which became stable),
and repurposes it to attempt loading .js/.jsx/.ts/.tsx files as CJS in
the following additional scenarios:
1. There is no package.json
1. There is a package.json without a "type" field
Also cleans up the implementation of this in the LSP a lot by hanging
`resolution_mode()` off `Document` (didn't think about doing that until
now).
```
> deno compile --allow-read=. --include data-file.txt main.js
```
This only applies to files on the filesystem. For remote modules, that's
going to have to wait for `import ... from "./data.txt" with { "type":
"bytes" }` or whatever it will be.
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.
Initial import of OTEL code supporting tracing. Metrics soon to come.
Implements APIs for https://jsr.io/@deno/otel so that code using
OpenTelemetry.js just works tm.
There is still a lot of work to do with configuration and adding
built-in tracing to core APIs, which will come in followup PRs.
---------
Co-authored-by: Luca Casonato <hello@lcas.dev>
* cts support
* better cjs/cts type checking
* deno compile cjs/cts support
* More efficient detect cjs (going towards stabilization)
* Determination of whether .js, .ts, .jsx, or .tsx is cjs or esm is only
done after loading
* Support `import x = require(...);`
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
When using the `--unstable-detect-cjs` flag or adding `"unstable":
["detect-cjs"]` to a deno.json, it will make a JS file CJS if the
closest package.json contains `"type": "commonjs"` and the file is not
an ESM module (no TLA, no `import.meta`, no `import`/`export`).