summaryrefslogtreecommitdiff
path: root/cli/node
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-10-01 06:15:56 -0400
committerGitHub <noreply@github.com>2022-10-01 12:15:56 +0200
commitecfafda9d8ead19cb35708f310e49176db2ec2b5 (patch)
tree222a52e0e5c06cc946d45240a6194c57b46a8724 /cli/node
parent1058d1868fcc28ce115d1cc231e66016308b76ce (diff)
perf: node cjs & esm analysis cache (#16097)
This commit adds a cache for CJS and ESM analysis that is backed by an SQLite file. The connection to the DB is lazily created on first use, so shouldn't have impact on the startup time. Benched with running Vite Deno v1.26: ``` $ deno task dev Warning deno task is unstable and may drastically change in the future Task dev deno run -A --unstable --node-modules-dir npm:vite VITE v3.1.4 ready in 961 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ``` This branch: ``` ../deno/target/release/deno task dev Warning deno task is unstable and may drastically change in the future Task dev deno run -A --unstable --node-modules-dir npm:vite VITE v3.1.4 ready in 330 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ``` Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
Diffstat (limited to 'cli/node')
-rw-r--r--cli/node/analyze.rs40
-rw-r--r--cli/node/mod.rs22
2 files changed, 50 insertions, 12 deletions
diff --git a/cli/node/analyze.rs b/cli/node/analyze.rs
index ed2536390..9b449f675 100644
--- a/cli/node/analyze.rs
+++ b/cli/node/analyze.rs
@@ -12,6 +12,8 @@ use deno_core::error::AnyError;
use deno_runtime::deno_node::NODE_GLOBAL_THIS_NAME;
use std::fmt::Write;
+use crate::cache::NodeAnalysisCache;
+
static NODE_GLOBALS: &[&str] = &[
"Buffer",
"clearImmediate",
@@ -32,18 +34,34 @@ static NODE_GLOBALS: &[&str] = &[
// `var` decls are taken into consideration.
pub fn esm_code_with_node_globals(
+ analysis_cache: &NodeAnalysisCache,
specifier: &ModuleSpecifier,
code: String,
) -> Result<String, AnyError> {
- let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
- specifier: specifier.to_string(),
- text_info: deno_ast::SourceTextInfo::from_string(code),
- media_type: deno_ast::MediaType::from(specifier),
- capture_tokens: true,
- scope_analysis: true,
- maybe_syntax: None,
- })?;
- let top_level_decls = analyze_top_level_decls(&parsed_source)?;
+ let source_hash = NodeAnalysisCache::compute_source_hash(&code);
+ let text_info = deno_ast::SourceTextInfo::from_string(code);
+ let top_level_decls = if let Some(decls) =
+ analysis_cache.get_esm_analysis(specifier.as_str(), &source_hash)
+ {
+ HashSet::from_iter(decls)
+ } else {
+ let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
+ specifier: specifier.to_string(),
+ text_info: text_info.clone(),
+ media_type: deno_ast::MediaType::from(specifier),
+ capture_tokens: true,
+ scope_analysis: true,
+ maybe_syntax: None,
+ })?;
+ let top_level_decls = analyze_top_level_decls(&parsed_source)?;
+ analysis_cache.set_esm_analysis(
+ specifier.as_str(),
+ &source_hash,
+ &top_level_decls.clone().into_iter().collect(),
+ );
+ top_level_decls
+ };
+
let mut globals = Vec::with_capacity(NODE_GLOBALS.len());
let has_global_this = top_level_decls.contains("globalThis");
for global in NODE_GLOBALS.iter() {
@@ -64,7 +82,7 @@ pub fn esm_code_with_node_globals(
write!(result, "var {0} = {1}.{0};", global, global_this_expr).unwrap();
}
- let file_text = parsed_source.text_info().text_str();
+ let file_text = text_info.text_str();
// strip the shebang
let file_text = if file_text.starts_with("#!/") {
let start_index = file_text.find('\n').unwrap_or(file_text.len());
@@ -148,6 +166,7 @@ mod tests {
#[test]
fn test_esm_code_with_node_globals() {
let r = esm_code_with_node_globals(
+ &NodeAnalysisCache::new(None),
&ModuleSpecifier::parse("https://example.com/foo/bar.js").unwrap(),
"export const x = 1;".to_string(),
)
@@ -163,6 +182,7 @@ mod tests {
#[test]
fn test_esm_code_with_node_globals_with_shebang() {
let r = esm_code_with_node_globals(
+ &NodeAnalysisCache::new(None),
&ModuleSpecifier::parse("https://example.com/foo/bar.js").unwrap(),
"#!/usr/bin/env node\nexport const x = 1;".to_string(),
)
diff --git a/cli/node/mod.rs b/cli/node/mod.rs
index 3ea263b04..2e431eaa0 100644
--- a/cli/node/mod.rs
+++ b/cli/node/mod.rs
@@ -5,6 +5,7 @@ use std::collections::VecDeque;
use std::path::Path;
use std::path::PathBuf;
+use crate::cache::NodeAnalysisCache;
use crate::deno_std::CURRENT_STD_URL;
use deno_ast::CjsAnalysis;
use deno_ast::MediaType;
@@ -734,12 +735,20 @@ pub fn translate_cjs_to_esm(
code: String,
media_type: MediaType,
npm_resolver: &NpmPackageResolver,
+ node_analysis_cache: &NodeAnalysisCache,
) -> Result<String, AnyError> {
fn perform_cjs_analysis(
+ analysis_cache: &NodeAnalysisCache,
specifier: &str,
media_type: MediaType,
code: String,
) -> Result<CjsAnalysis, AnyError> {
+ let source_hash = NodeAnalysisCache::compute_source_hash(&code);
+ if let Some(analysis) =
+ analysis_cache.get_cjs_analysis(specifier, &source_hash)
+ {
+ return Ok(analysis);
+ }
let parsed_source = deno_ast::parse_script(deno_ast::ParseParams {
specifier: specifier.to_string(),
text_info: deno_ast::SourceTextInfo::new(code.into()),
@@ -748,7 +757,10 @@ pub fn translate_cjs_to_esm(
scope_analysis: false,
maybe_syntax: None,
})?;
- Ok(parsed_source.analyze_cjs())
+ let analysis = parsed_source.analyze_cjs();
+ analysis_cache.set_cjs_analysis(specifier, &source_hash, &analysis);
+
+ Ok(analysis)
}
let mut temp_var_count = 0;
@@ -758,7 +770,12 @@ pub fn translate_cjs_to_esm(
r#"const require = Deno[Deno.internal].require.Module.createRequire(import.meta.url);"#.to_string(),
];
- let analysis = perform_cjs_analysis(specifier.as_str(), media_type, code)?;
+ let analysis = perform_cjs_analysis(
+ node_analysis_cache,
+ specifier.as_str(),
+ media_type,
+ code,
+ )?;
let mut all_exports = analysis
.exports
@@ -804,6 +821,7 @@ pub fn translate_cjs_to_esm(
{
let analysis = perform_cjs_analysis(
+ node_analysis_cache,
reexport_specifier.as_str(),
reexport_file.media_type,
reexport_file.source.to_string(),