mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
perf: v8 code cache (#23081)
This PR enables V8 code cache for ES modules and for `require` scripts through `op_eval_context`. Code cache artifacts are transparently stored and fetched using sqlite db and are passed to V8. `--no-code-cache` can be used to disable. --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
parent
9acbf90b06
commit
b3d7df5535
31 changed files with 889 additions and 76 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1836,6 +1836,7 @@ dependencies = [
|
|||
"notify",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"regex",
|
||||
"ring",
|
||||
"rustyline",
|
||||
|
|
|
@ -517,6 +517,7 @@ pub struct Flags {
|
|||
pub unstable_config: UnstableConfig,
|
||||
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
|
||||
pub v8_flags: Vec<String>,
|
||||
pub code_cache_enabled: bool,
|
||||
}
|
||||
|
||||
fn join_paths(allowlist: &[String], d: &str) -> String {
|
||||
|
@ -2236,6 +2237,7 @@ fn run_subcommand() -> Command {
|
|||
.trailing_var_arg(true),
|
||||
)
|
||||
.arg(env_file_arg())
|
||||
.arg(no_code_cache_arg())
|
||||
.about("Run a JavaScript or TypeScript program")
|
||||
.long_about(
|
||||
"Run a JavaScript or TypeScript program
|
||||
|
@ -3222,6 +3224,13 @@ fn no_clear_screen_arg() -> Arg {
|
|||
.help("Do not clear terminal screen when under watch mode")
|
||||
}
|
||||
|
||||
fn no_code_cache_arg() -> Arg {
|
||||
Arg::new("no-code-cache")
|
||||
.long("no-code-cache")
|
||||
.help("Disable V8 code cache feature")
|
||||
.action(ArgAction::SetTrue)
|
||||
}
|
||||
|
||||
fn watch_exclude_arg() -> Arg {
|
||||
Arg::new("watch-exclude")
|
||||
.long("watch-exclude")
|
||||
|
@ -3829,6 +3838,8 @@ fn run_parse(
|
|||
) -> clap::error::Result<()> {
|
||||
runtime_args_parse(flags, matches, true, true);
|
||||
|
||||
flags.code_cache_enabled = !matches.get_flag("no-code-cache");
|
||||
|
||||
let mut script_arg =
|
||||
matches.remove_many::<String>("script_arg").ok_or_else(|| {
|
||||
let mut app = app;
|
||||
|
@ -4469,6 +4480,7 @@ mod tests {
|
|||
..Default::default()
|
||||
},
|
||||
log_level: Some(Level::Error),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4540,6 +4552,7 @@ mod tests {
|
|||
"script.ts".to_string()
|
||||
)),
|
||||
reload: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4561,6 +4574,7 @@ mod tests {
|
|||
exclude: vec![],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4585,6 +4599,7 @@ mod tests {
|
|||
exclude: vec![],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4609,6 +4624,7 @@ mod tests {
|
|||
exclude: vec![],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4633,6 +4649,7 @@ mod tests {
|
|||
exclude: vec![],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4659,6 +4676,7 @@ mod tests {
|
|||
exclude: vec![],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4687,6 +4705,7 @@ mod tests {
|
|||
exclude: vec![],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4715,6 +4734,7 @@ mod tests {
|
|||
exclude: vec![String::from("foo")],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4739,6 +4759,7 @@ mod tests {
|
|||
exclude: vec![String::from("bar")],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4764,6 +4785,7 @@ mod tests {
|
|||
exclude: vec![String::from("foo"), String::from("bar")],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4789,6 +4811,7 @@ mod tests {
|
|||
exclude: vec![String::from("baz"), String::from("qux"),],
|
||||
}),
|
||||
}),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4806,6 +4829,7 @@ mod tests {
|
|||
"script.ts".to_string()
|
||||
)),
|
||||
allow_write: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4819,6 +4843,7 @@ mod tests {
|
|||
Flags {
|
||||
subcommand: DenoSubcommand::Run(RunFlags::new_default("_".to_string())),
|
||||
v8_flags: svec!["--help"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4836,6 +4861,7 @@ mod tests {
|
|||
"script.ts".to_string()
|
||||
)),
|
||||
v8_flags: svec!["--expose-gc", "--gc-stats=1"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4889,6 +4915,7 @@ mod tests {
|
|||
)),
|
||||
argv: svec!["--title", "X"],
|
||||
allow_net: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4912,6 +4939,7 @@ mod tests {
|
|||
allow_write: Some(vec![]),
|
||||
allow_ffi: Some(vec![]),
|
||||
allow_hrtime: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4927,6 +4955,7 @@ mod tests {
|
|||
"gist.ts".to_string()
|
||||
)),
|
||||
allow_read: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4942,6 +4971,7 @@ mod tests {
|
|||
"gist.ts".to_string()
|
||||
)),
|
||||
deny_read: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4957,6 +4987,7 @@ mod tests {
|
|||
"gist.ts".to_string(),
|
||||
)),
|
||||
allow_hrtime: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4972,6 +5003,7 @@ mod tests {
|
|||
"gist.ts".to_string(),
|
||||
)),
|
||||
deny_hrtime: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -4999,6 +5031,7 @@ mod tests {
|
|||
)),
|
||||
argv: svec!["--", "-D", "--allow-net"],
|
||||
allow_write: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -5713,6 +5746,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6007,6 +6041,7 @@ mod tests {
|
|||
subcommand: DenoSubcommand::Run(RunFlags::new_default(
|
||||
"script.ts".to_string(),
|
||||
)),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6031,6 +6066,7 @@ mod tests {
|
|||
subcommand: DenoSubcommand::Run(RunFlags::new_default(
|
||||
"script.ts".to_string(),
|
||||
)),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6055,6 +6091,7 @@ mod tests {
|
|||
subcommand: DenoSubcommand::Run(RunFlags::new_default(
|
||||
"script.ts".to_string(),
|
||||
)),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6079,6 +6116,7 @@ mod tests {
|
|||
subcommand: DenoSubcommand::Run(RunFlags::new_default(
|
||||
"script.ts".to_string(),
|
||||
)),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6099,6 +6137,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
allow_net: Some(svec!["127.0.0.1"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6115,6 +6154,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
deny_net: Some(svec!["127.0.0.1"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6131,6 +6171,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
allow_env: Some(svec!["HOME"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6147,6 +6188,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
deny_env: Some(svec!["HOME"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6167,6 +6209,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
allow_env: Some(svec!["HOME", "PATH"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6183,6 +6226,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
deny_env: Some(svec!["HOME", "PATH"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6224,6 +6268,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
allow_sys: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6239,6 +6284,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
deny_sys: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6255,6 +6301,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
allow_sys: Some(svec!["hostname"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6271,6 +6318,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
deny_sys: Some(svec!["hostname"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6291,6 +6339,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
allow_sys: Some(svec!["hostname", "osRelease"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6311,6 +6360,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
deny_sys: Some(svec!["hostname", "osRelease"]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6618,6 +6668,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
import_map_path: Some("import_map.json".to_owned()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6699,6 +6750,22 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
env_file: Some(".env".to_owned()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_no_code_cache() {
|
||||
let r =
|
||||
flags_from_vec(svec!["deno", "run", "--no-code-cache", "script.ts"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Run(RunFlags::new_default(
|
||||
"script.ts".to_string(),
|
||||
)),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6715,6 +6782,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
env_file: Some(".another_env".to_owned()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6746,6 +6814,7 @@ mod tests {
|
|||
)),
|
||||
seed: Some(250_u64),
|
||||
v8_flags: svec!["--random-seed=250"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6769,6 +6838,7 @@ mod tests {
|
|||
)),
|
||||
seed: Some(250_u64),
|
||||
v8_flags: svec!["--expose-gc", "--random-seed=250"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6907,6 +6977,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
log_level: Some(Level::Debug),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6922,6 +6993,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
log_level: Some(Level::Error),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6955,6 +7027,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
argv: svec!["--allow-read", "--allow-net"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6980,6 +7053,7 @@ mod tests {
|
|||
location: Some(Url::parse("https://foo/").unwrap()),
|
||||
allow_read: Some(vec![]),
|
||||
argv: svec!["--allow-net", "-r", "--help", "--foo", "bar"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -6992,6 +7066,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
argv: svec!["foo", "bar"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7003,6 +7078,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
argv: svec!["-"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7016,6 +7092,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
argv: svec!["-", "foo", "bar"],
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7031,6 +7108,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
type_check_mode: TypeCheckMode::None,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7047,6 +7125,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
type_check_mode: TypeCheckMode::Local,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7091,6 +7170,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
unsafely_ignore_certificate_errors: Some(vec![]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7118,6 +7198,7 @@ mod tests {
|
|||
"[::1]",
|
||||
"1.2.3.4"
|
||||
]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7161,6 +7242,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
no_remote: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7176,6 +7258,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
no_npm: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7192,6 +7275,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
node_modules_dir: Some(true),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7209,6 +7293,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
node_modules_dir: Some(false),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7224,6 +7309,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
vendor: Some(true),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7236,6 +7322,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
vendor: Some(false),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7251,6 +7338,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
cached_only: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7279,6 +7367,7 @@ mod tests {
|
|||
"127.0.0.1:4545",
|
||||
"localhost:4545"
|
||||
]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7307,6 +7396,7 @@ mod tests {
|
|||
"127.0.0.1:4545",
|
||||
"localhost:4545"
|
||||
]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7338,6 +7428,7 @@ mod tests {
|
|||
"localhost:5678",
|
||||
"[::1]:8080"
|
||||
]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7369,6 +7460,7 @@ mod tests {
|
|||
"localhost:5678",
|
||||
"[::1]:8080"
|
||||
]),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7391,6 +7483,7 @@ mod tests {
|
|||
)),
|
||||
lock_write: true,
|
||||
lock: Some(String::from("lock.json")),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7403,6 +7496,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
no_lock: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7422,6 +7516,7 @@ mod tests {
|
|||
)),
|
||||
lock_write: true,
|
||||
lock: Some(String::from("./deno.lock")),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7442,6 +7537,7 @@ mod tests {
|
|||
)),
|
||||
lock_write: true,
|
||||
lock: Some(String::from("lock.json")),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7454,6 +7550,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
lock_write: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7546,6 +7643,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
ca_data: Some(CaData::File("example.crt".to_owned())),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -7566,6 +7664,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
enable_testing_features: true,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8244,6 +8343,7 @@ mod tests {
|
|||
"foo.js".to_string(),
|
||||
)),
|
||||
inspect: Some("127.0.0.1:9229".parse().unwrap()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8259,6 +8359,7 @@ mod tests {
|
|||
"foo.js".to_string(),
|
||||
)),
|
||||
inspect_wait: Some("127.0.0.1:9229".parse().unwrap()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8276,6 +8377,7 @@ mod tests {
|
|||
"foo.js".to_string(),
|
||||
)),
|
||||
inspect_wait: Some("127.0.0.1:3567".parse().unwrap()),
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8802,6 +8904,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
type_check_mode: TypeCheckMode::Local,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8814,6 +8917,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
type_check_mode: TypeCheckMode::All,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8826,6 +8930,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
type_check_mode: TypeCheckMode::None,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -8850,6 +8955,7 @@ mod tests {
|
|||
"script.ts".to_string(),
|
||||
)),
|
||||
config_flag: ConfigFlag::Disabled,
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1653,6 +1653,10 @@ impl CliOptions {
|
|||
&self.flags.v8_flags
|
||||
}
|
||||
|
||||
pub fn code_cache_enabled(&self) -> bool {
|
||||
self.flags.code_cache_enabled
|
||||
}
|
||||
|
||||
pub fn watch_paths(&self) -> Vec<PathBuf> {
|
||||
let mut full_paths = Vec::new();
|
||||
if let DenoSubcommand::Run(RunFlags {
|
||||
|
|
15
cli/cache/caches.rs
vendored
15
cli/cache/caches.rs
vendored
|
@ -8,6 +8,7 @@ use once_cell::sync::OnceCell;
|
|||
use super::cache_db::CacheDB;
|
||||
use super::cache_db::CacheDBConfiguration;
|
||||
use super::check::TYPE_CHECK_CACHE_DB;
|
||||
use super::code_cache::CODE_CACHE_DB;
|
||||
use super::deno_dir::DenoDirProvider;
|
||||
use super::fast_check::FAST_CHECK_CACHE_DB;
|
||||
use super::incremental::INCREMENTAL_CACHE_DB;
|
||||
|
@ -22,6 +23,7 @@ pub struct Caches {
|
|||
fast_check_db: OnceCell<CacheDB>,
|
||||
node_analysis_db: OnceCell<CacheDB>,
|
||||
type_checking_cache_db: OnceCell<CacheDB>,
|
||||
code_cache_db: OnceCell<CacheDB>,
|
||||
}
|
||||
|
||||
impl Caches {
|
||||
|
@ -34,6 +36,7 @@ impl Caches {
|
|||
fast_check_db: Default::default(),
|
||||
node_analysis_db: Default::default(),
|
||||
type_checking_cache_db: Default::default(),
|
||||
code_cache_db: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,4 +127,16 @@ impl Caches {
|
|||
.map(|dir| dir.type_checking_cache_db_file_path()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn code_cache_db(&self) -> CacheDB {
|
||||
Self::make_db(
|
||||
&self.code_cache_db,
|
||||
&CODE_CACHE_DB,
|
||||
self
|
||||
.dir_provider
|
||||
.get_or_create()
|
||||
.ok()
|
||||
.map(|dir| dir.code_cache_db_file_path()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
231
cli/cache/code_cache.rs
vendored
Normal file
231
cli/cache/code_cache.rs
vendored
Normal file
|
@ -0,0 +1,231 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_runtime::code_cache;
|
||||
use deno_runtime::deno_webstorage::rusqlite::params;
|
||||
|
||||
use super::cache_db::CacheDB;
|
||||
use super::cache_db::CacheDBConfiguration;
|
||||
use super::cache_db::CacheFailure;
|
||||
|
||||
pub static CODE_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration {
|
||||
table_initializer: "CREATE TABLE IF NOT EXISTS codecache (
|
||||
specifier TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
source_hash TEXT NOT NULL,
|
||||
data BLOB NOT NULL,
|
||||
PRIMARY KEY (specifier, type)
|
||||
);",
|
||||
on_version_change: "DELETE FROM codecache;",
|
||||
preheat_queries: &[],
|
||||
on_failure: CacheFailure::Blackhole,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CodeCache {
|
||||
inner: CodeCacheInner,
|
||||
}
|
||||
|
||||
impl CodeCache {
|
||||
pub fn new(db: CacheDB) -> Self {
|
||||
Self {
|
||||
inner: CodeCacheInner::new(db),
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_ok<T: Default>(res: Result<T, AnyError>) -> T {
|
||||
match res {
|
||||
Ok(x) => x,
|
||||
Err(err) => {
|
||||
// TODO(mmastrac): This behavior was inherited from before the refactoring but it probably makes sense to move it into the cache
|
||||
// at some point.
|
||||
// should never error here, but if it ever does don't fail
|
||||
if cfg!(debug_assertions) {
|
||||
panic!("Error using code cache: {err:#}");
|
||||
} else {
|
||||
log::debug!("Error using code cache: {:#}", err);
|
||||
}
|
||||
T::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: code_cache::CodeCacheType,
|
||||
source_hash: &str,
|
||||
) -> Option<Vec<u8>> {
|
||||
Self::ensure_ok(self.inner.get_sync(
|
||||
specifier,
|
||||
code_cache_type,
|
||||
source_hash,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn set_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: code_cache::CodeCacheType,
|
||||
source_hash: &str,
|
||||
data: &[u8],
|
||||
) {
|
||||
Self::ensure_ok(self.inner.set_sync(
|
||||
specifier,
|
||||
code_cache_type,
|
||||
source_hash,
|
||||
data,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
impl code_cache::CodeCache for CodeCache {
|
||||
fn get_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: code_cache::CodeCacheType,
|
||||
source_hash: &str,
|
||||
) -> Option<Vec<u8>> {
|
||||
self.get_sync(specifier, code_cache_type, source_hash)
|
||||
}
|
||||
|
||||
fn set_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: code_cache::CodeCacheType,
|
||||
source_hash: &str,
|
||||
data: &[u8],
|
||||
) {
|
||||
self.set_sync(specifier, code_cache_type, source_hash, data);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CodeCacheInner {
|
||||
conn: CacheDB,
|
||||
}
|
||||
|
||||
impl CodeCacheInner {
|
||||
pub fn new(conn: CacheDB) -> Self {
|
||||
Self { conn }
|
||||
}
|
||||
|
||||
pub fn get_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: code_cache::CodeCacheType,
|
||||
source_hash: &str,
|
||||
) -> Result<Option<Vec<u8>>, AnyError> {
|
||||
let query = "
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
codecache
|
||||
WHERE
|
||||
specifier=?1 AND type=?2 AND source_hash=?3
|
||||
LIMIT 1";
|
||||
let params = params![specifier, code_cache_type.as_str(), source_hash,];
|
||||
self.conn.query_row(query, params, |row| {
|
||||
let value: Vec<u8> = row.get(0)?;
|
||||
Ok(value)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: code_cache::CodeCacheType,
|
||||
source_hash: &str,
|
||||
data: &[u8],
|
||||
) -> Result<(), AnyError> {
|
||||
let sql = "
|
||||
INSERT OR REPLACE INTO
|
||||
codecache (specifier, type, source_hash, data)
|
||||
VALUES
|
||||
(?1, ?2, ?3, ?4)";
|
||||
let params =
|
||||
params![specifier, code_cache_type.as_str(), source_hash, data];
|
||||
self.conn.execute(sql, params)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn end_to_end() {
|
||||
let conn = CacheDB::in_memory(&CODE_CACHE_DB, "1.0.0");
|
||||
let cache = CodeCacheInner::new(conn);
|
||||
|
||||
assert!(cache
|
||||
.get_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::EsModule,
|
||||
"hash",
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
let data_esm = vec![1, 2, 3];
|
||||
cache
|
||||
.set_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::EsModule,
|
||||
"hash",
|
||||
&data_esm,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
cache
|
||||
.get_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::EsModule,
|
||||
"hash",
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
data_esm
|
||||
);
|
||||
|
||||
assert!(cache
|
||||
.get_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::Script,
|
||||
"hash",
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
let data_script = vec![4, 5, 6];
|
||||
cache
|
||||
.set_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::Script,
|
||||
"hash",
|
||||
&data_script,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
cache
|
||||
.get_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::Script,
|
||||
"hash",
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
data_script
|
||||
);
|
||||
assert_eq!(
|
||||
cache
|
||||
.get_sync(
|
||||
"file:///foo/bar.js",
|
||||
code_cache::CodeCacheType::EsModule,
|
||||
"hash",
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
data_esm
|
||||
);
|
||||
}
|
||||
}
|
6
cli/cache/deno_dir.rs
vendored
6
cli/cache/deno_dir.rs
vendored
|
@ -142,6 +142,12 @@ impl DenoDir {
|
|||
self.root.join("npm")
|
||||
}
|
||||
|
||||
/// Path for the V8 code cache.
|
||||
pub fn code_cache_db_file_path(&self) -> PathBuf {
|
||||
// bump this version name to invalidate the entire cache
|
||||
self.root.join("v8_code_cache_v1")
|
||||
}
|
||||
|
||||
/// Path used for the REPL history file.
|
||||
/// Can be overridden or disabled by setting `DENO_REPL_HISTORY` environment variable.
|
||||
pub fn repl_history_file_path(&self) -> Option<PathBuf> {
|
||||
|
|
2
cli/cache/mod.rs
vendored
2
cli/cache/mod.rs
vendored
|
@ -25,6 +25,7 @@ use std::time::SystemTime;
|
|||
mod cache_db;
|
||||
mod caches;
|
||||
mod check;
|
||||
mod code_cache;
|
||||
mod common;
|
||||
mod deno_dir;
|
||||
mod disk_cache;
|
||||
|
@ -37,6 +38,7 @@ mod parsed_source;
|
|||
|
||||
pub use caches::Caches;
|
||||
pub use check::TypeCheckCache;
|
||||
pub use code_cache::CodeCache;
|
||||
pub use common::FastInsecureHasher;
|
||||
pub use deno_dir::DenoDir;
|
||||
pub use deno_dir::DenoDirProvider;
|
||||
|
|
24
cli/cache/module_info.rs
vendored
24
cli/cache/module_info.rs
vendored
|
@ -39,6 +39,7 @@ pub static MODULE_INFO_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration {
|
|||
on_failure: CacheFailure::InMemory,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleInfoCacheSourceHash(String);
|
||||
|
||||
impl ModuleInfoCacheSourceHash {
|
||||
|
@ -55,6 +56,12 @@ impl ModuleInfoCacheSourceHash {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ModuleInfoCacheSourceHash> for String {
|
||||
fn from(source_hash: ModuleInfoCacheSourceHash) -> String {
|
||||
source_hash.0
|
||||
}
|
||||
}
|
||||
|
||||
/// A cache of `deno_graph::ModuleInfo` objects. Using this leads to a considerable
|
||||
/// performance improvement because when it exists we can skip parsing a module for
|
||||
/// deno_graph.
|
||||
|
@ -80,6 +87,23 @@ impl ModuleInfoCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_module_source_hash(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
) -> Result<Option<ModuleInfoCacheSourceHash>, AnyError> {
|
||||
let query = "SELECT source_hash FROM moduleinfocache WHERE specifier=?1 AND media_type=?2";
|
||||
let res = self.conn.query_row(
|
||||
query,
|
||||
params![specifier.as_str(), serialize_media_type(media_type)],
|
||||
|row| {
|
||||
let source_hash: String = row.get(0)?;
|
||||
Ok(ModuleInfoCacheSourceHash(source_hash))
|
||||
},
|
||||
)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn get_module_info(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::args::PackageJsonDepsProvider;
|
|||
use crate::args::StorageKeyResolver;
|
||||
use crate::args::TsConfigType;
|
||||
use crate::cache::Caches;
|
||||
use crate::cache::CodeCache;
|
||||
use crate::cache::DenoDir;
|
||||
use crate::cache::DenoDirProvider;
|
||||
use crate::cache::EmitCache;
|
||||
|
@ -178,6 +179,7 @@ struct CliFactoryServices {
|
|||
cjs_resolutions: Deferred<Arc<CjsResolutionStore>>,
|
||||
cli_node_resolver: Deferred<Arc<CliNodeResolver>>,
|
||||
feature_checker: Deferred<Arc<FeatureChecker>>,
|
||||
code_cache: Deferred<Arc<CodeCache>>,
|
||||
}
|
||||
|
||||
pub struct CliFactory {
|
||||
|
@ -226,6 +228,9 @@ impl CliFactory {
|
|||
_ = caches.fast_check_db();
|
||||
_ = caches.type_checking_cache_db();
|
||||
}
|
||||
if self.options.code_cache_enabled() {
|
||||
_ = caches.code_cache_db();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -534,6 +539,12 @@ impl CliFactory {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn code_cache(&self) -> Result<&Arc<CodeCache>, AnyError> {
|
||||
self.services.code_cache.get_or_try_init(|| {
|
||||
Ok(Arc::new(CodeCache::new(self.caches()?.code_cache_db())))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parsed_source_cache(&self) -> &Arc<ParsedSourceCache> {
|
||||
self
|
||||
.services
|
||||
|
@ -790,6 +801,12 @@ impl CliFactory {
|
|||
fs.clone(),
|
||||
cli_node_resolver.clone(),
|
||||
),
|
||||
if self.options.code_cache_enabled() {
|
||||
Some(self.code_cache()?.clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
self.module_info_cache()?.clone(),
|
||||
)),
|
||||
self.root_cert_store_provider().clone(),
|
||||
self.fs().clone(),
|
||||
|
@ -804,6 +821,11 @@ impl CliFactory {
|
|||
// self.options.disable_deprecated_api_warning,
|
||||
true,
|
||||
self.options.verbose_deprecated_api_warning,
|
||||
if self.options.code_cache_enabled() {
|
||||
Some(self.code_cache()?.clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ use crate::tools::check;
|
|||
use crate::tools::check::TypeChecker;
|
||||
use crate::util::file_watcher::WatcherCommunicator;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use crate::util::sync::TaskQueue;
|
||||
use crate::util::sync::TaskQueuePermit;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use deno_config::WorkspaceMemberConfig;
|
||||
use deno_core::anyhow::bail;
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::args::jsr_url;
|
|||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::tools::lint::create_linter;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use deno_ast::SourceRange;
|
||||
use deno_ast::SourceRangedForSpanned;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::cache::HttpCache;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
|
|
@ -15,7 +15,7 @@ use super::tsc;
|
|||
use crate::jsr::JsrFetchResolver;
|
||||
use crate::util::path::is_importable_ext;
|
||||
use crate::util::path::relative_specifier;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use deno_ast::LineAndColumnIndex;
|
||||
use deno_ast::SourceTextInfo;
|
||||
|
|
|
@ -10,7 +10,6 @@ use crate::lsp::logging::lsp_warn;
|
|||
use crate::tools::lint::get_configured_rules;
|
||||
use crate::tools::lint::ConfiguredRules;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_ast::MediaType;
|
||||
use deno_config::FmtOptionsConfig;
|
||||
use deno_config::TsConfig;
|
||||
|
@ -25,6 +24,7 @@ use deno_core::serde_json::Value;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_lockfile::Lockfile;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_runtime::permissions::PermissionsContainer;
|
||||
use import_map::ImportMap;
|
||||
use lsp::Url;
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::resolver::CliNodeResolver;
|
|||
use crate::resolver::SloppyImportsFsEntry;
|
||||
use crate::resolver::SloppyImportsResolution;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use deno_ast::MediaType;
|
||||
|
|
|
@ -120,10 +120,10 @@ use crate::tools::upgrade::check_for_upgrades_for_lsp;
|
|||
use crate::tools::upgrade::upgrade_check_enabled;
|
||||
use crate::util::fs::remove_dir_all_if_exists;
|
||||
use crate::util::path::is_importable_ext;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use crate::util::path::to_percent_decoded_str;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
struct LspRootCertStoreProvider(RootCertStore);
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ use crate::tsc;
|
|||
use crate::tsc::ResolveArgs;
|
||||
use crate::tsc::MISSING_DEPENDENCY_SPECIFIER;
|
||||
use crate::util::path::relative_specifier;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use crate::util::path::to_percent_decoded_str;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use deno_ast::MediaType;
|
||||
|
|
|
@ -4,6 +4,8 @@ use crate::args::jsr_url;
|
|||
use crate::args::CliOptions;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::TsTypeLib;
|
||||
use crate::cache::CodeCache;
|
||||
use crate::cache::ModuleInfoCache;
|
||||
use crate::cache::ParsedSourceCache;
|
||||
use crate::emit::Emitter;
|
||||
use crate::graph_util::graph_lock_or_exit;
|
||||
|
@ -50,7 +52,9 @@ use deno_graph::JsonModule;
|
|||
use deno_graph::Module;
|
||||
use deno_graph::Resolution;
|
||||
use deno_lockfile::Lockfile;
|
||||
use deno_runtime::code_cache;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::fs_util::code_timestamp;
|
||||
use deno_runtime::permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_terminal::colors;
|
||||
|
@ -311,6 +315,8 @@ struct SharedCliModuleLoaderState {
|
|||
resolver: Arc<CliGraphResolver>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
code_cache: Option<Arc<CodeCache>>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
}
|
||||
|
||||
pub struct CliModuleLoaderFactory {
|
||||
|
@ -328,6 +334,8 @@ impl CliModuleLoaderFactory {
|
|||
resolver: Arc<CliGraphResolver>,
|
||||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
code_cache: Option<Arc<CodeCache>>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared: Arc::new(SharedCliModuleLoaderState {
|
||||
|
@ -348,6 +356,8 @@ impl CliModuleLoaderFactory {
|
|||
resolver,
|
||||
node_resolver,
|
||||
npm_module_loader,
|
||||
code_cache,
|
||||
module_info_cache,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -458,12 +468,40 @@ impl CliModuleLoader {
|
|||
return Err(generic_error("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement."));
|
||||
}
|
||||
|
||||
let code_cache = if module_type == ModuleType::JavaScript {
|
||||
self.shared.code_cache.as_ref().and_then(|cache| {
|
||||
let code_hash = self
|
||||
.get_code_hash_or_timestamp(specifier, code_source.media_type)
|
||||
.ok()
|
||||
.flatten();
|
||||
if let Some(code_hash) = code_hash {
|
||||
cache
|
||||
.get_sync(
|
||||
specifier.as_str(),
|
||||
code_cache::CodeCacheType::EsModule,
|
||||
&code_hash,
|
||||
)
|
||||
.map(Cow::from)
|
||||
.inspect(|_| {
|
||||
// This log line is also used by tests.
|
||||
log::debug!(
|
||||
"V8 code cache hit for ES module: {specifier}, [{code_hash:?}]"
|
||||
);
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ModuleSource::new_with_redirect(
|
||||
module_type,
|
||||
ModuleSourceCode::String(code),
|
||||
specifier,
|
||||
&code_source.found_url,
|
||||
None,
|
||||
code_cache,
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -603,6 +641,25 @@ impl CliModuleLoader {
|
|||
|
||||
resolution.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
fn get_code_hash_or_timestamp(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let hash = self
|
||||
.shared
|
||||
.module_info_cache
|
||||
.get_module_source_hash(specifier, media_type)?;
|
||||
if let Some(hash) = hash {
|
||||
return Ok(Some(hash.into()));
|
||||
}
|
||||
|
||||
// Use the modified timestamp from the local file system if we don't have a hash.
|
||||
let timestamp = code_timestamp(specifier.as_str())
|
||||
.map(|timestamp| timestamp.to_string())?;
|
||||
Ok(Some(timestamp))
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleLoader for CliModuleLoader {
|
||||
|
@ -678,6 +735,33 @@ impl ModuleLoader for CliModuleLoader {
|
|||
}
|
||||
.boxed_local()
|
||||
}
|
||||
|
||||
fn code_cache_ready(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
code_cache: &[u8],
|
||||
) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
if let Some(cache) = self.shared.code_cache.as_ref() {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
let code_hash = self
|
||||
.get_code_hash_or_timestamp(specifier, media_type)
|
||||
.ok()
|
||||
.flatten();
|
||||
if let Some(code_hash) = code_hash {
|
||||
// This log line is also used by tests.
|
||||
log::debug!(
|
||||
"Updating V8 code cache for ES module: {specifier}, [{code_hash:?}]"
|
||||
);
|
||||
cache.set_sync(
|
||||
specifier.as_str(),
|
||||
code_cache::CodeCacheType::EsModule,
|
||||
&code_hash,
|
||||
code_cache,
|
||||
);
|
||||
}
|
||||
}
|
||||
async {}.boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
struct CliSourceMapGetter {
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::args::package_json::get_local_package_json_version_reqs;
|
|||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists_with_fs;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
use super::common::types_package_name;
|
||||
use super::CliNpmResolver;
|
||||
|
|
|
@ -27,6 +27,7 @@ use deno_runtime::deno_node::NodeResolutionMode;
|
|||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_node::NpmResolver as DenoNodeNpmResolver;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_runtime::permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
|
@ -48,7 +49,6 @@ use crate::node::CliNodeCodeTranslator;
|
|||
use crate::npm::ByonmCliNpmResolver;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::InnerCliNpmResolverRef;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use crate::util::sync::AtomicFlag;
|
||||
|
||||
pub fn format_range_with_colors(range: &deno_graph::Range) -> String {
|
||||
|
|
|
@ -572,6 +572,8 @@ pub async fn run(
|
|||
// metadata.disable_deprecated_api_warning,
|
||||
true,
|
||||
false,
|
||||
// Code cache is not supported for standalone binary yet.
|
||||
None,
|
||||
);
|
||||
|
||||
// Initialize v8 once from the main thread.
|
||||
|
|
2
cli/tools/vendor/mod.rs
vendored
2
cli/tools/vendor/mod.rs
vendored
|
@ -24,7 +24,7 @@ use crate::tools::fmt::format_json;
|
|||
use crate::util::fs::canonicalize_path;
|
||||
use crate::util::fs::resolve_from_cwd;
|
||||
use crate::util::path::relative_specifier;
|
||||
use crate::util::path::specifier_to_file_path;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
mod analyze;
|
||||
mod build;
|
||||
|
|
|
@ -9,8 +9,6 @@ use deno_ast::ModuleSpecifier;
|
|||
use deno_config::glob::PathGlobMatch;
|
||||
use deno_config::glob::PathOrPattern;
|
||||
use deno_config::glob::PathOrPatternSet;
|
||||
use deno_core::error::uri_error;
|
||||
use deno_core::error::AnyError;
|
||||
|
||||
/// Checks if the path has an extension Deno supports for script execution.
|
||||
pub fn is_script_ext(path: &Path) -> bool {
|
||||
|
@ -82,49 +80,6 @@ pub fn mapped_specifier_for_tsc(
|
|||
}
|
||||
}
|
||||
|
||||
/// Attempts to convert a specifier to a file path. By default, uses the Url
|
||||
/// crate's `to_file_path()` method, but falls back to try and resolve unix-style
|
||||
/// paths on Windows.
|
||||
pub fn specifier_to_file_path(
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
let result = if specifier.scheme() != "file" {
|
||||
Err(())
|
||||
} else if cfg!(windows) {
|
||||
match specifier.to_file_path() {
|
||||
Ok(path) => Ok(path),
|
||||
Err(()) => {
|
||||
// This might be a unix-style path which is used in the tests even on Windows.
|
||||
// Attempt to see if we can convert it to a `PathBuf`. This code should be removed
|
||||
// once/if https://github.com/servo/rust-url/issues/730 is implemented.
|
||||
if specifier.scheme() == "file"
|
||||
&& specifier.host().is_none()
|
||||
&& specifier.port().is_none()
|
||||
&& specifier.path_segments().is_some()
|
||||
{
|
||||
let path_str = specifier.path();
|
||||
match String::from_utf8(
|
||||
percent_encoding::percent_decode(path_str.as_bytes()).collect(),
|
||||
) {
|
||||
Ok(path_str) => Ok(PathBuf::from(path_str)),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
specifier.to_file_path()
|
||||
};
|
||||
match result {
|
||||
Ok(path) => Ok(path),
|
||||
Err(()) => Err(uri_error(format!(
|
||||
"Invalid file path.\n Specifier: {specifier}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// `from.make_relative(to)` but with fixes.
|
||||
pub fn relative_specifier(
|
||||
from: &ModuleSpecifier,
|
||||
|
@ -330,24 +285,6 @@ mod test {
|
|||
assert!(!is_importable_ext(Path::new("foo.mjsx")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_specifier_to_file_path() {
|
||||
run_success_test("file:///", "/");
|
||||
run_success_test("file:///test", "/test");
|
||||
run_success_test("file:///dir/test/test.txt", "/dir/test/test.txt");
|
||||
run_success_test(
|
||||
"file:///dir/test%20test/test.txt",
|
||||
"/dir/test test/test.txt",
|
||||
);
|
||||
|
||||
fn run_success_test(specifier: &str, expected_path: &str) {
|
||||
let result =
|
||||
specifier_to_file_path(&ModuleSpecifier::parse(specifier).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(result, PathBuf::from(expected_path));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relative_specifier() {
|
||||
let fixtures: Vec<(&str, &str, Option<&str>)> = vec![
|
||||
|
|
|
@ -22,6 +22,7 @@ use deno_core::PollEventLoopOptions;
|
|||
use deno_core::SharedArrayBufferStore;
|
||||
use deno_core::SourceMapGetter;
|
||||
use deno_lockfile::Lockfile;
|
||||
use deno_runtime::code_cache;
|
||||
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node;
|
||||
|
@ -140,6 +141,7 @@ struct SharedWorkerState {
|
|||
enable_future_features: bool,
|
||||
disable_deprecated_api_warning: bool,
|
||||
verbose_deprecated_api_warning: bool,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
}
|
||||
|
||||
impl SharedWorkerState {
|
||||
|
@ -411,6 +413,7 @@ impl CliMainWorkerFactory {
|
|||
enable_future_features: bool,
|
||||
disable_deprecated_api_warning: bool,
|
||||
verbose_deprecated_api_warning: bool,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared: Arc::new(SharedWorkerState {
|
||||
|
@ -434,6 +437,7 @@ impl CliMainWorkerFactory {
|
|||
enable_future_features,
|
||||
disable_deprecated_api_warning,
|
||||
verbose_deprecated_api_warning,
|
||||
code_cache,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -628,6 +632,7 @@ impl CliMainWorkerFactory {
|
|||
stdio,
|
||||
feature_checker,
|
||||
skip_op_registration: shared.options.skip_op_registration,
|
||||
v8_code_cache: shared.code_cache.clone(),
|
||||
};
|
||||
|
||||
let mut worker = MainWorker::bootstrap_from_options(
|
||||
|
|
|
@ -112,6 +112,7 @@ log.workspace = true
|
|||
netif = "0.1.6"
|
||||
notify.workspace = true
|
||||
once_cell.workspace = true
|
||||
percent-encoding.workspace = true
|
||||
regex.workspace = true
|
||||
ring.workspace = true
|
||||
rustyline = { workspace = true, features = ["custom-bindings"] }
|
||||
|
|
31
runtime/code_cache.rs
Normal file
31
runtime/code_cache.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
pub enum CodeCacheType {
|
||||
EsModule,
|
||||
Script,
|
||||
}
|
||||
|
||||
impl CodeCacheType {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::EsModule => "esmodule",
|
||||
Self::Script => "script",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CodeCache: Send + Sync {
|
||||
fn get_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: CodeCacheType,
|
||||
source_hash: &str,
|
||||
) -> Option<Vec<u8>>;
|
||||
fn set_sync(
|
||||
&self,
|
||||
specifier: &str,
|
||||
code_cache_type: CodeCacheType,
|
||||
source_hash: &str,
|
||||
data: &[u8],
|
||||
);
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::uri_error;
|
||||
use deno_core::error::AnyError;
|
||||
pub use deno_core::normalize_path;
|
||||
use std::path::Path;
|
||||
|
@ -18,6 +20,60 @@ pub fn resolve_from_cwd(path: &Path) -> Result<PathBuf, AnyError> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Attempts to convert a specifier to a file path. By default, uses the Url
|
||||
/// crate's `to_file_path()` method, but falls back to try and resolve unix-style
|
||||
/// paths on Windows.
|
||||
pub fn specifier_to_file_path(
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
let result = if specifier.scheme() != "file" {
|
||||
Err(())
|
||||
} else if cfg!(windows) {
|
||||
match specifier.to_file_path() {
|
||||
Ok(path) => Ok(path),
|
||||
Err(()) => {
|
||||
// This might be a unix-style path which is used in the tests even on Windows.
|
||||
// Attempt to see if we can convert it to a `PathBuf`. This code should be removed
|
||||
// once/if https://github.com/servo/rust-url/issues/730 is implemented.
|
||||
if specifier.scheme() == "file"
|
||||
&& specifier.host().is_none()
|
||||
&& specifier.port().is_none()
|
||||
&& specifier.path_segments().is_some()
|
||||
{
|
||||
let path_str = specifier.path();
|
||||
match String::from_utf8(
|
||||
percent_encoding::percent_decode(path_str.as_bytes()).collect(),
|
||||
) {
|
||||
Ok(path_str) => Ok(PathBuf::from(path_str)),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
specifier.to_file_path()
|
||||
};
|
||||
match result {
|
||||
Ok(path) => Ok(path),
|
||||
Err(()) => Err(uri_error(format!(
|
||||
"Invalid file path.\n Specifier: {specifier}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn code_timestamp(specifier: &str) -> Result<u64, AnyError> {
|
||||
let specifier = ModuleSpecifier::parse(specifier)?;
|
||||
let path = specifier_to_file_path(&specifier)?;
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let timestamp = std::fs::metadata(path)?
|
||||
.modified()?
|
||||
.duration_since(std::time::UNIX_EPOCH)?
|
||||
.as_millis() as u64;
|
||||
Ok(timestamp)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -69,4 +125,22 @@ mod tests {
|
|||
let absolute_expected = cwd.join(expected);
|
||||
assert_eq!(resolve_from_cwd(expected).unwrap(), absolute_expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_specifier_to_file_path() {
|
||||
run_success_test("file:///", "/");
|
||||
run_success_test("file:///test", "/test");
|
||||
run_success_test("file:///dir/test/test.txt", "/dir/test/test.txt");
|
||||
run_success_test(
|
||||
"file:///dir/test%20test/test.txt",
|
||||
"/dir/test test/test.txt",
|
||||
);
|
||||
|
||||
fn run_success_test(specifier: &str, expected_path: &str) {
|
||||
let result =
|
||||
specifier_to_file_path(&ModuleSpecifier::parse(specifier).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(result, PathBuf::from(expected_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ pub use deno_webidl;
|
|||
pub use deno_websocket;
|
||||
pub use deno_webstorage;
|
||||
|
||||
pub mod code_cache;
|
||||
pub mod errors;
|
||||
pub mod fmt_errors;
|
||||
pub mod fs_util;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
@ -41,6 +42,9 @@ use deno_tls::RootCertStoreProvider;
|
|||
use deno_web::BlobStore;
|
||||
use log::debug;
|
||||
|
||||
use crate::code_cache::CodeCache;
|
||||
use crate::code_cache::CodeCacheType;
|
||||
use crate::fs_util::code_timestamp;
|
||||
use crate::inspector_server::InspectorServer;
|
||||
use crate::ops;
|
||||
use crate::permissions::PermissionsContainer;
|
||||
|
@ -193,6 +197,9 @@ pub struct WorkerOptions {
|
|||
pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
|
||||
pub stdio: Stdio,
|
||||
pub feature_checker: Arc<FeatureChecker>,
|
||||
|
||||
/// V8 code cache for module and script source code.
|
||||
pub v8_code_cache: Option<Arc<dyn CodeCache>>,
|
||||
}
|
||||
|
||||
impl Default for WorkerOptions {
|
||||
|
@ -227,6 +234,7 @@ impl Default for WorkerOptions {
|
|||
bootstrap: Default::default(),
|
||||
stdio: Default::default(),
|
||||
feature_checker: Default::default(),
|
||||
v8_code_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -296,6 +304,51 @@ pub fn create_op_metrics(
|
|||
(op_summary_metrics, op_metrics_factory_fn)
|
||||
}
|
||||
|
||||
fn get_code_cache(
|
||||
code_cache: Arc<dyn CodeCache>,
|
||||
specifier: &str,
|
||||
) -> Option<Vec<u8>> {
|
||||
// Code hashes are not maintained for op_eval_context scripts. Instead we use
|
||||
// the modified timestamp from the local file system.
|
||||
if let Ok(code_timestamp) = code_timestamp(specifier) {
|
||||
code_cache
|
||||
.get_sync(
|
||||
specifier,
|
||||
CodeCacheType::Script,
|
||||
code_timestamp.to_string().as_str(),
|
||||
)
|
||||
.inspect(|_| {
|
||||
// This log line is also used by tests.
|
||||
log::debug!(
|
||||
"V8 code cache hit for script: {specifier}, [{code_timestamp}]"
|
||||
);
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn set_code_cache(
|
||||
code_cache: Arc<dyn CodeCache>,
|
||||
specifier: &str,
|
||||
data: &[u8],
|
||||
) {
|
||||
// Code hashes are not maintained for op_eval_context scripts. Instead we use
|
||||
// the modified timestamp from the local file system.
|
||||
if let Ok(code_timestamp) = code_timestamp(specifier) {
|
||||
// This log line is also used by tests.
|
||||
log::debug!(
|
||||
"Updating V8 code cache for script: {specifier}, [{code_timestamp}]",
|
||||
);
|
||||
code_cache.set_sync(
|
||||
specifier,
|
||||
CodeCacheType::Script,
|
||||
code_timestamp.to_string().as_str(),
|
||||
data,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl MainWorker {
|
||||
pub fn bootstrap_from_options(
|
||||
main_module: ModuleSpecifier,
|
||||
|
@ -495,6 +548,18 @@ impl MainWorker {
|
|||
validate_import_attributes_cb: Some(Box::new(
|
||||
validate_import_attributes_callback,
|
||||
)),
|
||||
enable_code_cache: options.v8_code_cache.is_some(),
|
||||
eval_context_code_cache_cbs: options.v8_code_cache.map(|cache| {
|
||||
let cache_clone = cache.clone();
|
||||
(
|
||||
Box::new(move |specifier: &str| {
|
||||
Ok(get_code_cache(cache.clone(), specifier).map(Cow::Owned))
|
||||
}) as Box<dyn Fn(&_) -> _>,
|
||||
Box::new(move |specifier: &str, data: &[u8]| {
|
||||
set_code_cache(cache_clone.clone(), specifier, data);
|
||||
}) as Box<dyn Fn(&_, &_)>,
|
||||
)
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
|
|
@ -5177,3 +5177,205 @@ fn run_etag_delete_source_cache() {
|
|||
"[WILDCARD]Cache body not found. Trying again without etag.[WILDCARD]",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_cache_test() {
|
||||
let deno_dir = TempDir::new();
|
||||
let test_context = TestContextBuilder::new().use_temp_cwd().build();
|
||||
let temp_dir = test_context.temp_dir();
|
||||
temp_dir.write("main.js", "console.log('Hello World - A');");
|
||||
|
||||
// First run with no prior cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("Hello World - A[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("V8 code cache hit"));
|
||||
|
||||
// Check that the code cache database exists.
|
||||
let code_cache_path = deno_dir.path().join("v8_code_cache_v1");
|
||||
assert!(code_cache_path.exists());
|
||||
}
|
||||
|
||||
// 2nd run with cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("Hello World - A[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/main.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("Updating V8 code cache"));
|
||||
}
|
||||
|
||||
// Rerun with --no-code-cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("--no-code-cache")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("Hello World - A[WILDCARD]")
|
||||
.skip_stderr_check();
|
||||
assert!(!output.stderr().contains("V8 code cache"));
|
||||
}
|
||||
|
||||
// Modify the script, and make sure that the cache is rejected.
|
||||
temp_dir.write("main.js", "console.log('Hello World - B');");
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("Hello World - B[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("V8 code cache hit"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_cache_npm_test() {
|
||||
let deno_dir = TempDir::new();
|
||||
let test_context = TestContextBuilder::new()
|
||||
.use_temp_cwd()
|
||||
.use_http_server()
|
||||
.build();
|
||||
let temp_dir = test_context.temp_dir();
|
||||
temp_dir.write(
|
||||
"main.js",
|
||||
"import chalk from \"npm:chalk@5\";console.log(chalk('Hello World'));",
|
||||
);
|
||||
|
||||
// First run with no prior cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.envs(env_vars_for_npm_tests())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("-A")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("Hello World[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/npm/registry/chalk/5.[WILDCARD]/source/index.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("V8 code cache hit"));
|
||||
|
||||
// Check that the code cache database exists.
|
||||
let code_cache_path = deno_dir.path().join("v8_code_cache_v1");
|
||||
assert!(code_cache_path.exists());
|
||||
}
|
||||
|
||||
// 2nd run with cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.envs(env_vars_for_npm_tests())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("-A")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("Hello World[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/main.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/npm/registry/chalk/5.[WILDCARD]/source/index.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("Updating V8 code cache"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_cache_npm_with_require_test() {
|
||||
let deno_dir = TempDir::new();
|
||||
let test_context = TestContextBuilder::new()
|
||||
.use_temp_cwd()
|
||||
.use_http_server()
|
||||
.build();
|
||||
let temp_dir = test_context.temp_dir();
|
||||
temp_dir.write(
|
||||
"main.js",
|
||||
"import fraction from \"npm:autoprefixer\";console.log(typeof fraction);",
|
||||
);
|
||||
|
||||
// First run with no prior cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.envs(env_vars_for_npm_tests())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("-A")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("function[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/main.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for ES module: file:///[WILDCARD]/npm/registry/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for script: file:///[WILDCARD]/npm/registry/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]Updating V8 code cache for script: file:///[WILDCARD]/npm/registry/browserslist/[WILDCARD]/index.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("V8 code cache hit"));
|
||||
|
||||
// Check that the code cache database exists.
|
||||
let code_cache_path = deno_dir.path().join("v8_code_cache_v1");
|
||||
assert!(code_cache_path.exists());
|
||||
}
|
||||
|
||||
// 2nd run with cache.
|
||||
{
|
||||
let output = test_context
|
||||
.new_command()
|
||||
.env("DENO_DIR", deno_dir.path())
|
||||
.envs(env_vars_for_npm_tests())
|
||||
.arg("run")
|
||||
.arg("-Ldebug")
|
||||
.arg("-A")
|
||||
.arg("main.js")
|
||||
.split_output()
|
||||
.run();
|
||||
|
||||
output
|
||||
.assert_stdout_matches_text("function[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/main.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for ES module: file:///[WILDCARD]/npm/registry/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for script: file:///[WILDCARD]/npm/registry/autoprefixer/[WILDCARD]/autoprefixer.js[WILDCARD]")
|
||||
.assert_stderr_matches_text("[WILDCARD]V8 code cache hit for script: file:///[WILDCARD]/npm/registry/browserslist/[WILDCARD]/index.js[WILDCARD]");
|
||||
assert!(!output.stderr().contains("Updating V8 code cache"));
|
||||
}
|
||||
}
|
||||
|
|
2
tests/testdata/run/rejection_handled.ts
vendored
2
tests/testdata/run/rejection_handled.ts
vendored
|
@ -14,4 +14,4 @@ setTimeout(async () => {
|
|||
|
||||
setTimeout(() => {
|
||||
console.log("Success");
|
||||
}, 50);
|
||||
}, 200);
|
||||
|
|
Loading…
Reference in a new issue