From 6dc8e68c496f61dd31de3f1d753f9bc976845f7a Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Mon, 13 Sep 2021 22:12:08 -0700 Subject: [PATCH 1/7] Print diagnostics for scope hoisting bailouts at verbose log level (#6918) --- packages/reporters/cli/src/CLIReporter.js | 2 +- packages/transformers/js/core/src/fs.rs | 8 +- packages/transformers/js/core/src/hoist.rs | 148 +++++++++++++++--- packages/transformers/js/core/src/lib.rs | 5 +- packages/transformers/js/core/src/utils.rs | 100 ++++++++++++ packages/transformers/js/src/JSTransformer.js | 1 + 6 files changed, 238 insertions(+), 26 deletions(-) diff --git a/packages/reporters/cli/src/CLIReporter.js b/packages/reporters/cli/src/CLIReporter.js index 3f08065018d..246f8175e5b 100644 --- a/packages/reporters/cli/src/CLIReporter.js +++ b/packages/reporters/cli/src/CLIReporter.js @@ -200,7 +200,7 @@ async function writeDiagnostic( writeOut(indentString(codeframe, indent), isError); } - if ((stack || codeframe) && hints.length > 0) { + if ((stack || codeframe) && (hints.length > 0 || documentation)) { writeOut(''); } diff --git a/packages/transformers/js/core/src/fs.rs b/packages/transformers/js/core/src/fs.rs index 836c4366313..b0c33849edc 100644 --- a/packages/transformers/js/core/src/fs.rs +++ b/packages/transformers/js/core/src/fs.rs @@ -26,7 +26,13 @@ pub fn inline_fs<'a>( ) -> impl Fold + 'a { InlineFS { filename: Path::new(filename).to_path_buf(), - collect: Collect::new(source_map, decls, Mark::fresh(Mark::root()), global_mark), + collect: Collect::new( + source_map, + decls, + Mark::fresh(Mark::root()), + global_mark, + false, + ), global_mark, project_root, deps, diff --git a/packages/transformers/js/core/src/hoist.rs b/packages/transformers/js/core/src/hoist.rs index 02b5d1d5972..e114daaead7 100644 --- a/packages/transformers/js/core/src/hoist.rs +++ b/packages/transformers/js/core/src/hoist.rs @@ -8,8 +8,8 @@ use swc_ecmascript::ast::*; use swc_ecmascript::visit::{Fold, FoldWith, Node, Visit, VisitWith}; use crate::utils::{ - match_import, match_member_expr, match_require, CodeHighlight, Diagnostic, DiagnosticSeverity, - SourceLocation, + match_import, match_member_expr, match_require, Bailout, BailoutReason, CodeHighlight, + Diagnostic, DiagnosticSeverity, SourceLocation, }; type IdentId = (JsWord, SyntaxContext); @@ -34,8 +34,9 @@ pub fn hoist( decls: HashSet, ignore_mark: Mark, global_mark: Mark, -) -> Result<(Module, HoistResult), Vec> { - let mut collect = Collect::new(source_map, decls, ignore_mark, global_mark); + trace_bailouts: bool, +) -> Result<(Module, HoistResult, Vec), Vec> { + let mut collect = Collect::new(source_map, decls, ignore_mark, global_mark, trace_bailouts); module.visit_with(&Invalid { span: DUMMY_SP } as _, &mut collect); let mut hoist = Hoist::new(module_id, &collect); @@ -44,7 +45,14 @@ pub fn hoist( return Err(hoist.diagnostics); } - Ok((module, hoist.get_result())) + if let Some(bailouts) = &collect.bailouts { + hoist + .diagnostics + .extend(bailouts.iter().map(|bailout| bailout.to_diagnostic())); + } + + let diagnostics = std::mem::take(&mut hoist.diagnostics); + Ok((module, hoist.get_result(), diagnostics)) } struct Hoist<'a> { @@ -554,7 +562,7 @@ impl<'a> Fold for Hoist<'a> { // If there are any non-static accesses of the namespace, don't perform any replacement. // This will be handled in the Ident visitor below, which replaces y -> $id$import$10b1f2ceae7ab64e. if specifier == "*" - && !self.collect.non_static_access.contains(&id!(ident)) + && !self.collect.non_static_access.contains_key(&id!(ident)) && !self.collect.non_const_bindings.contains_key(&id!(ident)) && !self.collect.non_static_requires.contains(source) { @@ -771,7 +779,7 @@ impl<'a> Fold for Hoist<'a> { self .imported_symbols .insert(name, (source.clone(), specifier.clone(), loc.clone())); - } else if self.collect.non_static_access.contains(&id!(node)) { + } else if self.collect.non_static_access.contains_key(&id!(node)) { let name: JsWord = format!("${}$importAsync${:x}", self.module_id, hash!(source)).into(); self @@ -1101,7 +1109,7 @@ pub struct Collect { should_wrap: bool, pub imports: HashMap, exports: HashMap, - non_static_access: HashSet, + non_static_access: HashMap>, non_const_bindings: HashMap>, non_static_requires: HashSet, wrapped_requires: HashSet, @@ -1110,6 +1118,7 @@ pub struct Collect { in_export_decl: bool, in_function: bool, in_assign: bool, + bailouts: Option>, } impl Collect { @@ -1118,6 +1127,7 @@ impl Collect { decls: HashSet, ignore_mark: Mark, global_mark: Mark, + trace_bailouts: bool, ) -> Self { Collect { source_map, @@ -1130,7 +1140,7 @@ impl Collect { should_wrap: false, imports: HashMap::new(), exports: HashMap::new(), - non_static_access: HashSet::new(), + non_static_access: HashMap::new(), non_const_bindings: HashMap::new(), non_static_requires: HashSet::new(), wrapped_requires: HashSet::new(), @@ -1139,6 +1149,7 @@ impl Collect { in_export_decl: false, in_function: false, in_assign: false, + bailouts: if trace_bailouts { Some(vec![]) } else { None }, } } } @@ -1150,6 +1161,21 @@ impl Visit for Collect { self.in_function = false; node.visit_children_with(self); self.in_module_this = false; + + if let Some(bailouts) = &mut self.bailouts { + for key in self.imports.keys() { + if let Some(spans) = self.non_static_access.get(key) { + for span in spans { + bailouts.push(Bailout { + loc: SourceLocation::from(&self.source_map, *span), + reason: BailoutReason::NonStaticAccess, + }) + } + } + } + + bailouts.sort_by(|a, b| a.loc.partial_cmp(&b.loc).unwrap()); + } } collect_visit_fn!(visit_function, Function); @@ -1317,6 +1343,7 @@ impl Visit for Collect { fn visit_return_stmt(&mut self, node: &ReturnStmt, _parent: &dyn Node) { if !self.in_function { self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::TopLevelReturn); } node.visit_children_with(self) @@ -1378,6 +1405,7 @@ impl Visit for Collect { self.has_cjs_exports = true; if !is_static { self.static_cjs_exports = false; + self.add_bailout(node.span, BailoutReason::NonStaticExports); } } return; @@ -1387,7 +1415,8 @@ impl Visit for Collect { if ident.sym == exports && !self.decls.contains(&id!(ident)) { self.has_cjs_exports = true; if !is_static { - self.static_cjs_exports = false + self.static_cjs_exports = false; + self.add_bailout(node.span, BailoutReason::NonStaticExports); } } @@ -1395,11 +1424,16 @@ impl Visit for Collect { self.has_cjs_exports = true; self.static_cjs_exports = false; self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::FreeModule); } // `import` isn't really an identifier... if !is_static && ident.sym != js_word!("import") { - self.non_static_access.insert(id!(ident)); + self + .non_static_access + .entry(id!(ident)) + .or_default() + .push(node.span); } return; } @@ -1408,6 +1442,7 @@ impl Visit for Collect { self.has_cjs_exports = true; if !is_static { self.static_cjs_exports = false; + self.add_bailout(node.span, BailoutReason::NonStaticExports); } } return; @@ -1439,11 +1474,21 @@ impl Visit for Collect { // declaration. We need to wrap the referenced module to preserve side effect ordering. if let Some(source) = self.match_require(node) { self.wrapped_requires.insert(source); + let span = match node { + Expr::Call(c) => c.span, + _ => unreachable!(), + }; + self.add_bailout(span, BailoutReason::NonTopLevelRequire); } if let Some(source) = match_import(node, self.ignore_mark) { self.non_static_requires.insert(source.clone()); self.wrapped_requires.insert(source); + let span = match node { + Expr::Call(c) => c.span, + _ => unreachable!(), + }; + self.add_bailout(span, BailoutReason::NonStaticDynamicImport); } match node { @@ -1457,12 +1502,19 @@ impl Visit for Collect { self.static_cjs_exports = false; if is_module { self.should_wrap = true; + self.add_bailout(ident.span, BailoutReason::FreeModule); + } else { + self.add_bailout(ident.span, BailoutReason::FreeExports); } } // `import` isn't really an identifier... if ident.sym != js_word!("import") { - self.non_static_access.insert(id!(ident)); + self + .non_static_access + .entry(id!(ident)) + .or_default() + .push(ident.span); } } _ => { @@ -1471,10 +1523,11 @@ impl Visit for Collect { } } - fn visit_this_expr(&mut self, _node: &ThisExpr, _parent: &dyn Node) { + fn visit_this_expr(&mut self, node: &ThisExpr, _parent: &dyn Node) { if self.in_module_this { self.has_cjs_exports = true; self.static_cjs_exports = false; + self.add_bailout(node.span, BailoutReason::FreeExports); } } @@ -1504,6 +1557,13 @@ impl Visit for Collect { self.static_cjs_exports = false; self.has_cjs_exports = true; self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::ExportsReassignment); + } else if has_binding_identifier(pat, &"module".into(), &self.decls) { + // Same for `module`. If it is reassigned we can't correctly statically analyze. + self.static_cjs_exports = false; + self.has_cjs_exports = true; + self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::ModuleReassignment); } } } @@ -1582,7 +1642,8 @@ impl Visit for Collect { match &**expr { Expr::Ident(ident) => { if ident.sym == js_word!("eval") && !self.decls.contains(&id!(ident)) { - self.should_wrap = true + self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::Eval); } } Expr::Member(member) => { @@ -1609,6 +1670,7 @@ impl Visit for Collect { } else { self.non_static_requires.insert(source.clone()); self.wrapped_requires.insert(source); + self.add_bailout(node.span, BailoutReason::NonStaticDynamicImport); } expr.visit_with(node, self); @@ -1636,6 +1698,16 @@ impl Collect { self.wrapped_requires.insert(src.clone()); if kind != ImportKind::DynamicImport { self.non_static_requires.insert(src.clone()); + let span = match node { + Pat::Ident(id) => id.id.span, + Pat::Array(arr) => arr.span, + Pat::Object(obj) => obj.span, + Pat::Rest(rest) => rest.span, + Pat::Assign(assign) => assign.span, + Pat::Invalid(i) => i.span, + Pat::Expr(_) => DUMMY_SP, + }; + self.add_bailout(span, BailoutReason::NonTopLevelRequire); } } @@ -1663,6 +1735,7 @@ impl Collect { _ => { // Non-static. E.g. computed property. self.non_static_requires.insert(src.clone()); + self.add_bailout(object.span, BailoutReason::NonStaticDestructuring); continue; } }; @@ -1692,6 +1765,7 @@ impl Collect { _ => { // Non-static. self.non_static_requires.insert(src.clone()); + self.add_bailout(object.span, BailoutReason::NonStaticDestructuring); } } } @@ -1718,6 +1792,7 @@ impl Collect { // let {x, ...y} = require('y'); // Non-static. We don't know what keys are used. self.non_static_requires.insert(src.clone()); + self.add_bailout(object.span, BailoutReason::NonStaticDestructuring); } } } @@ -1725,6 +1800,16 @@ impl Collect { _ => { // Non-static. self.non_static_requires.insert(src.clone()); + let span = match node { + Pat::Ident(id) => id.id.span, + Pat::Array(arr) => arr.span, + Pat::Object(obj) => obj.span, + Pat::Rest(rest) => rest.span, + Pat::Assign(assign) => assign.span, + Pat::Invalid(i) => i.span, + Pat::Expr(_) => DUMMY_SP, + }; + self.add_bailout(span, BailoutReason::NonStaticDestructuring); } } } @@ -1761,6 +1846,15 @@ impl Collect { _ => {} } } + + fn add_bailout(&mut self, span: Span, reason: BailoutReason) { + if let Some(bailouts) = &mut self.bailouts { + bailouts.push(Bailout { + loc: SourceLocation::from(&self.source_map, span), + reason, + }) + } + } } fn has_binding_identifier(node: &Pat, sym: &JsWord, decls: &HashSet) -> bool { @@ -1847,6 +1941,7 @@ mod tests { collect_decls(&module), Mark::fresh(Mark::root()), global_mark, + false, ); module.visit_with(&Invalid { span: DUMMY_SP } as _, &mut collect); @@ -1990,7 +2085,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), false) } ); - assert_eq!(collect.non_static_access, set! {}); + assert_eq!(collect.non_static_access, map! {}); let (_collect, _code, hoist) = parse( r#" @@ -2012,7 +2107,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), false) } ); - assert_eq_set!(collect.non_static_access, set! { w!("x") }); + assert_eq_set!(collect.non_static_access.into_keys(), set! { w!("x") }); let (collect, _code, _hoist) = parse( r#" @@ -2024,7 +2119,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), false) } ); - assert_eq_set!(collect.non_static_access, set! { w!("x") }); + assert_eq_set!(collect.non_static_access.into_keys(), set! { w!("x") }); } #[test] @@ -2050,6 +2145,13 @@ mod tests { "#, ); assert!(collect.should_wrap); + + let (collect, _code, _hoist) = parse( + r#" + module = 2; + "#, + ); + assert!(collect.should_wrap); } #[test] @@ -2228,7 +2330,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), true) } ); - assert_eq_set!(collect.non_static_access, set! {}); + assert_eq_set!(collect.non_static_access.into_keys(), set! {}); assert_eq!(collect.non_static_requires, set! {}); assert_eq!(collect.wrapped_requires, set! {w!("other")}); @@ -2244,7 +2346,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), true) } ); - assert_eq_set!(collect.non_static_access, set! { w!("x") }); + assert_eq_set!(collect.non_static_access.into_keys(), set! { w!("x") }); assert_eq!(collect.non_static_requires, set! {}); assert_eq!(collect.wrapped_requires, set! {w!("other")}); @@ -2285,7 +2387,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), true) } ); - assert_eq_set!(collect.non_static_access, set! {}); + assert_eq_set!(collect.non_static_access.into_keys(), set! {}); assert_eq!(collect.non_static_requires, set! {}); assert_eq!(collect.wrapped_requires, set! {w!("other")}); @@ -2298,7 +2400,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), true) } ); - assert_eq_set!(collect.non_static_access, set! { w!("x") }); + assert_eq_set!(collect.non_static_access.into_keys(), set! { w!("x") }); assert_eq!(collect.non_static_requires, set! {}); assert_eq!(collect.wrapped_requires, set! {w!("other")}); @@ -2335,7 +2437,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), true) } ); - assert_eq_set!(collect.non_static_access, set! {}); + assert_eq_set!(collect.non_static_access.into_keys(), set! {}); assert_eq!(collect.non_static_requires, set! {}); assert_eq!(collect.wrapped_requires, set! {w!("other")}); @@ -2348,7 +2450,7 @@ mod tests { collect.imports, map! { w!("x") => (w!("other"), w!("*"), true) } ); - assert_eq_set!(collect.non_static_access, set! { w!("x") }); + assert_eq_set!(collect.non_static_access.into_keys(), set! { w!("x") }); assert_eq!(collect.non_static_requires, set! {}); assert_eq!(collect.wrapped_requires, set! {w!("other")}); diff --git a/packages/transformers/js/core/src/lib.rs b/packages/transformers/js/core/src/lib.rs index 280d68a22ca..112cb43974b 100644 --- a/packages/transformers/js/core/src/lib.rs +++ b/packages/transformers/js/core/src/lib.rs @@ -83,6 +83,7 @@ pub struct Config { supports_module_workers: bool, is_library: bool, is_esm_output: bool, + trace_bailouts: bool, } #[derive(Serialize, Debug, Deserialize, Default)] @@ -381,10 +382,12 @@ pub fn transform(config: Config) -> Result { decls, ignore_mark, global_mark, + config.trace_bailouts, ); match res { - Ok((module, hoist_result)) => { + Ok((module, hoist_result, hoist_diagnostics)) => { result.hoist_result = Some(hoist_result); + diagnostics.extend(hoist_diagnostics); module } Err(diagnostics) => { diff --git a/packages/transformers/js/core/src/utils.rs b/packages/transformers/js/core/src/utils.rs index 6b55938e4ab..34d22c05017 100644 --- a/packages/transformers/js/core/src/utils.rs +++ b/packages/transformers/js/core/src/utils.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::collections::HashSet; use serde::{Deserialize, Serialize}; @@ -170,6 +171,18 @@ impl SourceLocation { } } +impl PartialOrd for SourceLocation { + fn partial_cmp(&self, other: &SourceLocation) -> Option { + if self.start_line < other.start_line { + Some(Ordering::Less) + } else if self.start_line == other.start_line { + self.start_col.partial_cmp(&other.start_col) + } else { + Some(Ordering::Greater) + } + } +} + #[derive(Serialize, Deserialize, Debug)] pub struct CodeHighlight { pub message: Option, @@ -201,3 +214,90 @@ pub enum SourceType { Script, Module, } + +pub struct Bailout { + pub loc: SourceLocation, + pub reason: BailoutReason, +} + +impl Bailout { + pub fn to_diagnostic(&self) -> Diagnostic { + let (message, documentation_url) = self.reason.info(); + Diagnostic { + message: message.into(), + documentation_url: Some(documentation_url.into()), + code_highlights: Some(vec![CodeHighlight { + loc: self.loc.clone(), + message: None, + }]), + show_environment: false, + severity: DiagnosticSeverity::Warning, + hints: None, + } + } +} + +pub enum BailoutReason { + NonTopLevelRequire, + NonStaticDestructuring, + TopLevelReturn, + Eval, + NonStaticExports, + FreeModule, + FreeExports, + ExportsReassignment, + ModuleReassignment, + NonStaticDynamicImport, + NonStaticAccess, +} + +impl BailoutReason { + fn info(&self) -> (&str, &str) { + match self { + BailoutReason::NonTopLevelRequire => ( + "Conditional or non-top-level `require()` call. This causes the resolved module and all dependendencies to be wrapped.", + "https://v2.parceljs.org/features/scope-hoisting/#avoid-conditional-require()" + ), + BailoutReason::NonStaticDestructuring => ( + "Non-static destructuring of `require` or dynamic `import()`. This causes all exports of the resolved module to be included.", + "https://v2.parceljs.org/features/scope-hoisting/#commonjs" + ), + BailoutReason::TopLevelReturn => ( + "Module contains a top-level `return` statement. This causes the module to be wrapped in a function and tree shaking to be disabled.", + "https://v2.parceljs.org/features/scope-hoisting/#avoid-top-level-return" + ), + BailoutReason::Eval => ( + "Module contains usage of `eval`. This causes the module to be wrapped in a function and minification to be disabled.", + "https://v2.parceljs.org/features/scope-hoisting/#avoid-eval" + ), + BailoutReason::NonStaticExports => ( + "Non-static access of CommonJS `exports` object. This causes tree shaking to be disabled for the module.", + "https://v2.parceljs.org/features/scope-hoisting/#commonjs" + ), + BailoutReason::FreeModule => ( + "Unknown usage of CommonJS `module` object. This causes the module to be wrapped, and tree shaking to be disabled.", + "https://v2.parceljs.org/features/scope-hoisting/#commonjs" + ), + BailoutReason::FreeExports => ( + "Unknown usage of CommonJS `exports` object. This causes tree shaking to be disabled.", + "https://v2.parceljs.org/features/scope-hoisting/#commonjs" + ), + BailoutReason::ExportsReassignment => ( + "Module contains a reassignment of the CommonJS `exports` object. This causes the module to be wrapped and tree-shaking to be disabled.", + "https://v2.parceljs.org/features/scope-hoisting/#avoid-module-and-exports-re-assignment" + ), + BailoutReason::ModuleReassignment => ( + "Module contains a reassignment of the CommonJS `module` object. This causes the module to be wrapped and tree-shaking to be disabled.", + "https://v2.parceljs.org/features/scope-hoisting/#avoid-module-and-exports-re-assignment" + ), + BailoutReason::NonStaticDynamicImport => ( + "Unknown dynamic import usage. This causes tree shaking to be disabled for the resolved module.", + "https://v2.parceljs.org/features/scope-hoisting/#dynamic-imports" + ), + BailoutReason::NonStaticAccess => ( + "Non-static access of an `import` or `require`. This causes tree shaking to be disabled for the resolved module.", + "https://v2.parceljs.org/features/scope-hoisting/#dynamic-member-accesses" + ), + } + } +} diff --git a/packages/transformers/js/src/JSTransformer.js b/packages/transformers/js/src/JSTransformer.js index 87b28c401f1..4a3eee31836 100644 --- a/packages/transformers/js/src/JSTransformer.js +++ b/packages/transformers/js/src/JSTransformer.js @@ -400,6 +400,7 @@ export default (new Transformer({ supports_module_workers: supportsModuleWorkers, is_library: asset.env.isLibrary, is_esm_output: asset.env.outputFormat === 'esmodule', + trace_bailouts: options.logLevel === 'verbose', }); let convertLoc = loc => { From 6f6759e5c2140aa8d7c3be70d56432258439ff19 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Wed, 15 Sep 2021 06:45:01 +0200 Subject: [PATCH 2/7] Bump swc (#6848) --- Cargo.lock | 149 +++++++++--------- .../test/integration/sourcemap/.babelrc | 3 - packages/transformers/js/core/Cargo.toml | 8 +- 3 files changed, 79 insertions(+), 81 deletions(-) delete mode 100644 packages/core/integration-tests/test/integration/sourcemap/.babelrc diff --git a/Cargo.lock b/Cargo.lock index 72961081c26..5b8f28ade7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" [[package]] name = "arrayvec" @@ -155,9 +155,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" dependencies = [ "jobserver", ] @@ -228,9 +228,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] @@ -533,9 +533,9 @@ dependencies = [ [[package]] name = "if_chain" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "image" @@ -596,9 +596,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jemalloc-sys" @@ -670,9 +670,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.99" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libdeflate-sys" @@ -718,9 +718,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memoffset" @@ -773,9 +773,9 @@ dependencies = [ [[package]] name = "napi" -version = "1.7.6" +version = "1.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb22375ec7cbd8bee4535126bb323e4e62cbf8088d84f0225d4d3226d1619bd5" +checksum = "2813a6f24e181eb1faba8bc632e56049901fb71df4bf3e0cd6b4086db6606c78" dependencies = [ "napi-sys", "serde", @@ -907,9 +907,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "ordered-float" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039f02eb0f69271f26abe3202189275d7aa2258b903cb0281b5de710a2570ff3" +checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d" dependencies = [ "num-traits", ] @@ -1128,9 +1128,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] @@ -1330,18 +1330,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1102fa7714968fcf70fd8efa29fb3b189e20ef0e7701fbab9634384dda034bf3" +checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7" dependencies = [ "fnv", "js-sys", @@ -1360,9 +1360,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -1371,9 +1371,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" dependencies = [ "itoa", "ryu", @@ -1382,9 +1382,9 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer", "cfg-if 1.0.0", @@ -1395,9 +1395,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1" +checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" [[package]] name = "smallvec" @@ -1520,9 +1520,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "swc_atoms" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bcdb70cb6ecee568e5acfda1a8c6e851ecf49443e5fb51f1b13613b5d04d2b0" +checksum = "837a3ef86c2817228e733b6f173c821fd76f9eb21a0bc9001a826be48b00b4e7" dependencies = [ "string_cache", "string_cache_codegen", @@ -1530,9 +1530,9 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.11.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc89b8c9f2fa3fc646e7d1a05ebc2063b1396b3ba5277afc741505bd7414fff" +checksum = "0100bddbd0b5587223a862dedc9556715d066205e7e1954ca080567693923ee5" dependencies = [ "ahash", "ast_node", @@ -1553,13 +1553,14 @@ dependencies = [ "swc_visit", "termcolor", "unicode-width", + "url", ] [[package]] name = "swc_ecma_ast" -version = "0.49.4" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3efef728f69665d765c52b233155dcb3290424f56a9f978ecfbd53f136804461" +checksum = "aa0efb0e13ba6545e2b86336937e1641594f78c48484b85c2dc9582eaccb41e1" dependencies = [ "is-macro", "num-bigint", @@ -1571,9 +1572,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.67.0" +version = "0.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a380bd935ce811c0bc8b961abc97cbf3a8c759213634aa59f5b0601162ba4e" +checksum = "7940bff62e5caf62fe6732ce4f07e52c3c208cb58cd9299f7f7c92dddab2bf72" dependencies = [ "bitflags", "num-bigint", @@ -1600,9 +1601,9 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "0.15.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc6a797d2df5f60cc9ab6a85aa7a49ab1bcaac8150d184f79a27deba2d21983" +checksum = "c2f718f0335f9ab7437fecf9f3d73ae6a24c03a3d3f46910a68261703d407f03" dependencies = [ "anyhow", "dashmap", @@ -1620,9 +1621,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.67.0" +version = "0.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0418c8dcb041d74e90c2179290bf3be0e58f2425d1f86843a5e297a13755912" +checksum = "042a901352b84cefbb64916a010ee33f621a7e341ced2b2fa60035858f3146a5" dependencies = [ "either", "enum_kind", @@ -1641,9 +1642,9 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.38.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283a609ec84132c2751bdee13a7a81228007206538ef09a1066163602f0d34d8" +checksum = "7fdb885d7b8ad47fb5f62cff0b36f61d6282b3548a566b8760a800c00de23679" dependencies = [ "dashmap", "fxhash", @@ -1665,9 +1666,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.67.0" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c50b45538663ae18d56768c93567312dd5cbf29786678a94cfa610172ba93a4" +checksum = "b2124504a4203cab8f903b8e8be49dbd6c4bad2b0405ba0c8188f952c224c44b" dependencies = [ "swc_atoms", "swc_common", @@ -1687,9 +1688,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.27.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5de480c55ae93eb59715cfc8f66965d192bc62cd4c12e33cff9f940f9431e12" +checksum = "b26e191df68943565f22059d31b02967e60a62c4f76533b5b5106546785a8e2e" dependencies = [ "fxhash", "once_cell", @@ -1706,9 +1707,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.13.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcbad381d349cbff95f7602bf2d9ad6a40c7df92a391d4af62221bd0d7633a2" +checksum = "ad5a845d5ec140ba8580c6b8d0f51ce417b86395a7b74c4280bb6cdae3c042c6" dependencies = [ "swc_atoms", "swc_common", @@ -1720,9 +1721,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.30.0" +version = "0.34.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cca0020d15ecb278fcdc4cd55f199f39e0c42ceb9e7f9740416f36120c17ad5" +checksum = "cda7278fdc9598ec43d40aa795ec7049532194bbcea861dd89bfe0ad3901446d" dependencies = [ "arrayvec", "fxhash", @@ -1757,9 +1758,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.34.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0abb8acb4b72d1ef37971b0bfed8e267ecaab37b3d34bac96205d7b62689e2" +checksum = "c79229bac86ac213d69c6d5957f9ee281979a9a7c6e5b94ca360a8a4429c6021" dependencies = [ "Inflector", "anyhow", @@ -1779,9 +1780,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.37.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4c8d2613ce06be5cf8160159eb468117ef6257eba744e1bf18125cca31ad" +checksum = "ea2600bc3bd557353511cd90b336943ae30e8807bce989a420cb004953fb940a" dependencies = [ "dashmap", "fxhash", @@ -1801,9 +1802,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.34.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8edf26ee1695c0137a829dbb8bb3c6681c1ae55e23ff45e0e0f41308e795f" +checksum = "637093e49ee993b16fb7bf8918f3d409c986fc77850440a3c779de85d1442cfb" dependencies = [ "either", "fxhash", @@ -1821,9 +1822,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.35.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72eabb27291ac7bef4f1f85e3aa7d335138dde1a1606b7d584e7f414882e5f3c" +checksum = "18bf8799eb49b25f0632b9e60b7871b3f77e18fecb1972e4932ba08005b5c85f" dependencies = [ "base64 0.13.0", "dashmap", @@ -1844,9 +1845,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.36.0" +version = "0.40.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc043fd29ceac49f13c1c994ba784f404cca3e189dd6cb771bfe905a0f776592" +checksum = "98099e3db58fb758715736ea9c8fa68d238e6527f0bfb4a3af0bf7ea063b9162" dependencies = [ "fxhash", "serde", @@ -1861,9 +1862,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.41.3" +version = "0.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bacaf860e4224e1a12bea8730c94de28f990f92685dad57aa572e3473043f7" +checksum = "3c811bca37142f7fe21ce800784db1d537645762ffe8d8a52e2a7179d8cc1723" dependencies = [ "once_cell", "scoped-tls", @@ -1876,9 +1877,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.35.2" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51ce688b7c984d0325261edb3ced4195790c7ac76982e269d2114ec04e3ae7c" +checksum = "78c6721dfbcb8bea64383edb0d59ccb02bc1e140024f2e0f8766792a14f5f466" dependencies = [ "num-bigint", "swc_atoms", @@ -1889,9 +1890,9 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "0.57.0" +version = "0.63.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e41615d9e65c7b148950211dacd0b2343a646d84493b9c8efa8795ee1a6e2f4f" +checksum = "ba53c5582d6e5881b093ece9aaa4b561465afab0560abb19948f2c4bbff1bdb9" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", @@ -1999,9 +2000,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986" dependencies = [ "tinyvec_macros", ] @@ -2020,9 +2021,9 @@ checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicode-bidi" diff --git a/packages/core/integration-tests/test/integration/sourcemap/.babelrc b/packages/core/integration-tests/test/integration/sourcemap/.babelrc deleted file mode 100644 index 1320b9a3272..00000000000 --- a/packages/core/integration-tests/test/integration/sourcemap/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@babel/preset-env"] -} diff --git a/packages/transformers/js/core/Cargo.toml b/packages/transformers/js/core/Cargo.toml index 279d45252d5..27af8cd6b8f 100644 --- a/packages/transformers/js/core/Cargo.toml +++ b/packages/transformers/js/core/Cargo.toml @@ -8,10 +8,10 @@ edition = "2018" crate-type = ["rlib"] [dependencies] -swc_ecmascript = { version = "0.57.0", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils"] } -swc_ecma_preset_env = "0.38.0" -swc_common = { version = "0.11.6", features = ["tty-emitter", "sourcemap"] } -swc_atoms = "0.2.6" +swc_ecmascript = { version = "0.63.1", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils"] } +swc_ecma_preset_env = "0.42.1" +swc_common = { version = "0.12.1", features = ["tty-emitter", "sourcemap"] } +swc_atoms = "0.2.7" indoc = "1.0.3" serde = "1.0.123" serde_bytes = "0.11.5" From b9294c48bdbf8b7603c112c9a324d9dfe83d2a93 Mon Sep 17 00:00:00 2001 From: Brian Do Date: Wed, 15 Sep 2021 18:05:01 -0700 Subject: [PATCH 3/7] Change edge types to numbers (#6126) * change edgetypes to numbers * clean up comments * fix edge colors in graphviz * camelCase edge type objects * add NullEdgeType to generic in Array edge types * Change NullEdgeType to 1 * Fix colors in graphviz * Fix types Co-authored-by: Devon Govett Co-authored-by: Eric Eldredge --- packages/core/core/src/BundleGraph.js | 196 +++++++++++++----- packages/core/core/src/Parcel.js | 13 +- packages/core/core/src/RequestTracker.js | 194 +++++++++++++---- packages/core/core/src/applyRuntimes.js | 8 +- packages/core/core/src/dumpGraphToGraphViz.js | 16 +- .../core/src/public/MutableBundleGraph.js | 14 +- .../core/src/requests/BundleGraphRequest.js | 34 ++- .../core/src/requests/ParcelBuildRequest.js | 3 +- packages/core/core/test/AssetGraph.test.js | 12 +- packages/core/graph/src/ContentGraph.js | 8 +- packages/core/graph/src/Graph.js | 41 ++-- packages/core/graph/src/types.js | 2 +- packages/core/graph/test/Graph.test.js | 34 ++- 13 files changed, 414 insertions(+), 161 deletions(-) diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index ca6aebbad01..6436d994b51 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -35,16 +35,16 @@ import {getBundleGroupId, getPublicId} from './utils'; import {ISOLATED_ENVS} from './public/Environment'; import {fromProjectPath} from './projectPath'; -type BundleGraphEdgeTypes = +export const bundleGraphEdgeTypes = { // A lack of an edge type indicates to follow the edge while traversing // the bundle's contents, e.g. `bundle.traverse()` during packaging. - | null + null: 1, // Used for constant-time checks of presence of a dependency or asset in a bundle, // avoiding bundle traversal in cases like `isAssetInAncestors` - | 'contains' + contains: 2, // Connections between bundles and bundle groups, for quick traversal of the // bundle hierarchy. - | 'bundle' + bundle: 3, // When dependency -> asset: Indicates that the asset a dependency references // is contained in another bundle. // When dependency -> bundle: Indicates the bundle is necessary for any bundles @@ -54,10 +54,13 @@ type BundleGraphEdgeTypes = // This type prevents referenced assets from being traversed from dependencies // along the untyped edge, and enables traversal to referenced bundles that are // not directly connected to bundle group nodes. - | 'references' + references: 4, // Signals that the dependency is internally resolvable via the bundle's ancestry, // and that the bundle connected to the dependency is not necessary for the source bundle. - | 'internal_async'; + internal_async: 5, +}; + +export type BundleGraphEdgeType = $Values; type InternalSymbolResolution = {| asset: Asset, @@ -73,7 +76,7 @@ type InternalExportSymbolResolution = {| type SerializedBundleGraph = {| $$raw: true, - graph: SerializedContentGraph, + graph: SerializedContentGraph, bundleContentHashes: Map, assetPublicIds: Set, publicIdByAssetId: Map, @@ -102,7 +105,7 @@ export default class BundleGraph { // BundlerRunner takes care of invalidating hashes when runtimes are applied, but this is not ideal. _bundleContentHashes: Map; _targetEntryRoots: Map = new Map(); - _graph: ContentGraph; + _graph: ContentGraph; constructor({ graph, @@ -110,7 +113,7 @@ export default class BundleGraph { assetPublicIds, bundleContentHashes, }: {| - graph: ContentGraph, + graph: ContentGraph, publicIdByAssetId: Map, assetPublicIds: Set, bundleContentHashes: Map, @@ -126,7 +129,7 @@ export default class BundleGraph { publicIdByAssetId: Map = new Map(), assetPublicIds: Set = new Set(), ): BundleGraph { - let graph = new ContentGraph(); + let graph = new ContentGraph(); let assetGroupIds = new Set(); let assetGraphNodeIdToBundleGraphNodeId = new Map(); @@ -166,14 +169,22 @@ export default class BundleGraph { for (let edge of assetGraph.getAllEdges()) { let fromIds; if (assetGroupIds.has(edge.from)) { - fromIds = [...assetGraph.inboundEdges.getEdges(edge.from, null)]; + fromIds = [ + ...assetGraph.inboundEdges.getEdges( + edge.from, + bundleGraphEdgeTypes.null, + ), + ]; } else { fromIds = [edge.from]; } for (let from of fromIds) { if (assetGroupIds.has(edge.to)) { - for (let to of assetGraph.outboundEdges.getEdges(edge.to, null)) { + for (let to of assetGraph.outboundEdges.getEdges( + edge.to, + bundleGraphEdgeTypes.null, + )) { graph.addEdge( nullthrows(assetGraphNodeIdToBundleGraphNodeId.get(from)), nullthrows(assetGraphNodeIdToBundleGraphNodeId.get(to)), @@ -240,7 +251,11 @@ export default class BundleGraph { } if (node.type === 'asset' || node.type === 'dependency') { - this._graph.addEdge(bundleNodeId, nodeId, 'contains'); + this._graph.addEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.contains, + ); } if (node.type === 'dependency') { @@ -249,18 +264,26 @@ export default class BundleGraph { .map(id => [id, nullthrows(this._graph.getNode(id))]) .filter(([, node]) => node.type === 'bundle_group')) { invariant(bundleGroupNode.type === 'bundle_group'); - this._graph.addEdge(bundleNodeId, bundleGroupNodeId, 'bundle'); + this._graph.addEdge( + bundleNodeId, + bundleGroupNodeId, + bundleGraphEdgeTypes.bundle, + ); } // If the dependency references a target bundle, add a reference edge from // the source bundle to the dependency for easy traversal. if ( this._graph - .getNodeIdsConnectedFrom(nodeId, 'references') + .getNodeIdsConnectedFrom(nodeId, bundleGraphEdgeTypes.references) .map(id => nullthrows(this._graph.getNode(id))) .some(node => node.type === 'bundle') ) { - this._graph.addEdge(bundleNodeId, nodeId, 'references'); + this._graph.addEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.references, + ); } } }, assetNodeId); @@ -286,7 +309,7 @@ export default class BundleGraph { this._graph.addEdge( this._graph.getNodeIdByContentKey(bundle.id), this._graph.getNodeIdByContentKey(dependency.id), - 'internal_async', + bundleGraphEdgeTypes.internal_async, ); this.removeExternalDependency(bundle, dependency); } @@ -301,7 +324,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), - 'bundle', + bundleGraphEdgeTypes.bundle, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle') @@ -324,11 +347,15 @@ export default class BundleGraph { if ( bundleNodeId != null && - this._graph.hasEdge(bundleNodeId, depNodeId, 'internal_async') + this._graph.hasEdge( + bundleNodeId, + depNodeId, + bundleGraphEdgeTypes.internal_async, + ) ) { let referencedAssetNodeIds = this._graph.getNodeIdsConnectedFrom( depNodeId, - 'references', + bundleGraphEdgeTypes.references, ); let resolved; @@ -396,7 +423,10 @@ export default class BundleGraph { includeInline: true, }); let referenced = this._graph - .getNodeIdsConnectedFrom(dependencyNodeId, 'references') + .getNodeIdsConnectedFrom( + dependencyNodeId, + bundleGraphEdgeTypes.references, + ) .map(id => nullthrows(this._graph.getNode(id))) .find(node => node.type === 'asset'); @@ -426,11 +456,13 @@ export default class BundleGraph { return; } - if (this._graph.hasEdge(bundleNodeId, nodeId, 'contains')) { + if ( + this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains) + ) { this._graph.removeEdge( bundleNodeId, nodeId, - 'contains', + bundleGraphEdgeTypes.contains, // Removing this contains edge should not orphan the connected node. This // is disabled for performance reasons as these edges are removed as part // of a traversal, and checking for orphans becomes quite expensive in @@ -455,11 +487,31 @@ export default class BundleGraph { if (node.type === 'dependency') { this.removeExternalDependency(bundle, node.value); - if (this._graph.hasEdge(bundleNodeId, nodeId, 'references')) { - this._graph.addEdge(bundleNodeId, nodeId, 'references'); + if ( + this._graph.hasEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.references, + ) + ) { + this._graph.addEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.references, + ); } - if (this._graph.hasEdge(bundleNodeId, nodeId, 'internal_async')) { - this._graph.removeEdge(bundleNodeId, nodeId, 'internal_async'); + if ( + this._graph.hasEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.internal_async, + ) + ) { + this._graph.removeEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.internal_async, + ); } } }, assetNodeId); @@ -478,7 +530,7 @@ export default class BundleGraph { let bundleGroupNodeIds = this._graph.getNodeIdsConnectedTo( bundleNodeId, - 'bundle', + bundleGraphEdgeTypes.bundle, ); this._graph.removeNode(bundleNodeId); @@ -551,7 +603,13 @@ export default class BundleGraph { bundleGroupNode.id, ); - if (!this._graph.hasEdge(bundleNodeId, bundleGroupNodeId, 'bundle')) { + if ( + !this._graph.hasEdge( + bundleNodeId, + bundleGroupNodeId, + bundleGraphEdgeTypes.bundle, + ) + ) { continue; } @@ -574,11 +632,15 @@ export default class BundleGraph { this._graph.hasEdge( bundleNodeId, this._graph.getNodeIdByContentKey(dependency.id), - 'internal_async', + bundleGraphEdgeTypes.internal_async, ), ) ) { - this._graph.removeEdge(bundleNodeId, bundleGroupNodeId, 'bundle'); + this._graph.removeEdge( + bundleNodeId, + bundleGroupNodeId, + bundleGraphEdgeTypes.bundle, + ); } } } @@ -591,9 +653,13 @@ export default class BundleGraph { let dependencyId = this._graph.getNodeIdByContentKey(dependency.id); let assetId = this._graph.getNodeIdByContentKey(asset.id); let bundleId = this._graph.getNodeIdByContentKey(bundle.id); - this._graph.addEdge(dependencyId, assetId, 'references'); + this._graph.addEdge(dependencyId, assetId, bundleGraphEdgeTypes.references); - this._graph.addEdge(dependencyId, bundleId, 'references'); + this._graph.addEdge( + dependencyId, + bundleId, + bundleGraphEdgeTypes.references, + ); if (this._graph.hasEdge(dependencyId, assetId)) { this._graph.removeEdge(dependencyId, assetId); } @@ -603,7 +669,7 @@ export default class BundleGraph { this._graph.addEdge( this._graph.getNodeIdByContentKey(from.id), this._graph.getNodeIdByContentKey(to.id), - 'references', + bundleGraphEdgeTypes.references, ); } @@ -611,7 +677,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( this._graph.getNodeIdByContentKey(asset.id), - 'contains', + bundleGraphEdgeTypes.contains, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle') @@ -625,7 +691,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( nullthrows(this._graph.getNodeIdByContentKey(dependency.id)), - 'contains', + bundleGraphEdgeTypes.contains, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle') @@ -670,7 +736,7 @@ export default class BundleGraph { } }, this._graph.getNodeIdByContentKey(dep.id), - 'references', + bundleGraphEdgeTypes.references, ); } @@ -701,7 +767,7 @@ export default class BundleGraph { if ( this._graph - .getNodeIdsConnectedTo(assetNodeId, 'references') + .getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references) .map(id => this._graph.getNode(id)) .some( node => @@ -827,7 +893,7 @@ export default class BundleGraph { // Get a list of parent bundle nodes pointing to the bundle group let parentBundleNodes = this._graph.getNodeIdsConnectedTo( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), - 'bundle', + bundleGraphEdgeTypes.bundle, ); // Check that every parent bundle has a bundle group in its ancestry that contains the asset. @@ -875,7 +941,7 @@ export default class BundleGraph { } } }, - ['references', 'bundle'], + [bundleGraphEdgeTypes.references, bundleGraphEdgeTypes.bundle], ); return isReachable; @@ -901,7 +967,13 @@ export default class BundleGraph { } if (node.type === 'dependency' || node.type === 'asset') { - if (this._graph.hasEdge(bundleNodeId, nodeId, 'contains')) { + if ( + this._graph.hasEdge( + bundleNodeId, + nodeId, + bundleGraphEdgeTypes.contains, + ) + ) { return node; } } @@ -985,7 +1057,7 @@ export default class BundleGraph { }, visit, startBundle ? this._graph.getNodeIdByContentKey(startBundle.id) : null, - ['bundle', 'references'], + [bundleGraphEdgeTypes.bundle, bundleGraphEdgeTypes.references], ); } @@ -1030,7 +1102,7 @@ export default class BundleGraph { referencingBundles.add(node.value); } }, - 'references', + bundleGraphEdgeTypes.references, ); return [...referencingBundles]; @@ -1052,7 +1124,7 @@ export default class BundleGraph { return this._graph .getNodeIdsConnectedTo( nullthrows(this._graph.getNodeIdByContentKey(bundle.id)), - 'bundle', + bundleGraphEdgeTypes.bundle, ) .map(id => nullthrows(this._graph.getNode(id))) .filter(node => node.type === 'bundle_group') @@ -1069,7 +1141,7 @@ export default class BundleGraph { let bundles: Set = new Set(); for (let bundleNodeId of this._graph.getNodeIdsConnectedFrom( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), - 'bundle', + bundleGraphEdgeTypes.bundle, )) { let bundleNode = nullthrows(this._graph.getNode(bundleNodeId)); invariant(bundleNode.type === 'bundle'); @@ -1125,7 +1197,9 @@ export default class BundleGraph { // Shared bundles seem to depend on being used in the opposite order // they were added. // TODO: Should this be the case? - this._graph.getNodeIdsConnectedFrom(nodeId, 'references').reverse(), + this._graph + .getNodeIdsConnectedFrom(nodeId, bundleGraphEdgeTypes.references) + .reverse(), }); return [...referencedBundles]; @@ -1172,13 +1246,21 @@ export default class BundleGraph { bundleHasAsset(bundle: Bundle, asset: Asset): boolean { let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); let assetNodeId = this._graph.getNodeIdByContentKey(asset.id); - return this._graph.hasEdge(bundleNodeId, assetNodeId, 'contains'); + return this._graph.hasEdge( + bundleNodeId, + assetNodeId, + bundleGraphEdgeTypes.contains, + ); } bundleHasDependency(bundle: Bundle, dependency: Dependency): boolean { let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id); - return this._graph.hasEdge(bundleNodeId, dependencyNodeId, 'contains'); + return this._graph.hasEdge( + bundleNodeId, + dependencyNodeId, + bundleGraphEdgeTypes.contains, + ); } filteredTraverse( @@ -1493,13 +1575,23 @@ export default class BundleGraph { getBundleGroupId(bundleGroup), ); let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); - if (this._graph.hasEdge(bundleGroupNodeId, bundleNodeId, 'bundle')) { + if ( + this._graph.hasEdge( + bundleGroupNodeId, + bundleNodeId, + bundleGraphEdgeTypes.bundle, + ) + ) { // Bundle group already has bundle return; } this._graph.addEdge(bundleGroupNodeId, bundleNodeId); - this._graph.addEdge(bundleGroupNodeId, bundleNodeId, 'bundle'); + this._graph.addEdge( + bundleGroupNodeId, + bundleNodeId, + bundleGraphEdgeTypes.bundle, + ); for (let entryAssetId of bundle.entryAssetIds) { let entryAssetNodeId = this._graph.getNodeIdByContentKey(entryAssetId); @@ -1575,7 +1667,7 @@ export default class BundleGraph { nullthrows( this._graph.getNodeIdByContentKey(getBundleGroupId(bundleGroup)), ), - 'bundle', + bundleGraphEdgeTypes.bundle, ) .map(id => nullthrows(this._graph.getNode(id))) .some(n => n.type === 'root'); @@ -1589,7 +1681,7 @@ export default class BundleGraph { let entryBundleGroupIds = this._graph.getNodeIdsConnectedFrom( nullthrows(this._graph.rootNodeId), - 'bundle', + bundleGraphEdgeTypes.bundle, ); let entries = []; diff --git a/packages/core/core/src/Parcel.js b/packages/core/core/src/Parcel.js index 9aa0d713faa..70b3b24d79f 100644 --- a/packages/core/core/src/Parcel.js +++ b/packages/core/core/src/Parcel.js @@ -31,7 +31,10 @@ import {AbortController} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import {PromiseQueue} from '@parcel/utils'; import ParcelConfig from './ParcelConfig'; import logger from '@parcel/logger'; -import RequestTracker, {getWatcherOptions} from './RequestTracker'; +import RequestTracker, { + getWatcherOptions, + requestGraphEdgeTypes, +} from './RequestTracker'; import createValidationRequest from './requests/ValidationRequest'; import createParcelBuildRequest from './requests/ParcelBuildRequest'; import {Disposable} from '@parcel/events'; @@ -274,8 +277,12 @@ export default class Parcel { this.#requestedAssetIds.clear(); - // $FlowFixMe - dumpGraphToGraphViz(this.#requestTracker.graph, 'RequestGraph'); + dumpGraphToGraphViz( + // $FlowFixMe + this.#requestTracker.graph, + 'RequestGraph', + requestGraphEdgeTypes, + ); let event = { type: 'buildSuccess', diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index 1d03e49a6cf..6fedb3cf09a 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -45,6 +45,16 @@ import { ERROR, } from './constants'; +export const requestGraphEdgeTypes = { + subrequest: 2, + invalidated_by_update: 3, + invalidated_by_delete: 4, + invalidated_by_create: 5, + invalidated_by_create_above: 6, + dirname: 7, +}; + +export type RequestGraphEdgeType = $Values; type SerializedRequestGraph = {| ...SerializedContentGraph, invalidNodeIds: Set, @@ -103,14 +113,6 @@ type RequestGraphNode = | EnvNode | OptionNode; -type RequestGraphEdgeType = - | 'subrequest' - | 'invalidated_by_update' - | 'invalidated_by_delete' - | 'invalidated_by_create' - | 'invalidated_by_create_above' - | 'dirname'; - export type RunAPI = {| invalidateOnFileCreate: InternalFileCreateInvalidation => void, invalidateOnFileDelete: ProjectPath => void, @@ -280,7 +282,7 @@ export class RequestGraph extends ContentGraph< requestNodeId, subrequestNodeIds, null, - 'subrequest', + requestGraphEdgeTypes.subrequest, ); } @@ -290,7 +292,10 @@ export class RequestGraph extends ContentGraph< node.invalidateReason |= reason; this.invalidNodeIds.add(nodeId); - let parentNodes = this.getNodeIdsConnectedTo(nodeId, 'subrequest'); + let parentNodes = this.getNodeIdsConnectedTo( + nodeId, + requestGraphEdgeTypes.subrequest, + ); for (let parentNode of parentNodes) { this.invalidateNode(parentNode, reason); } @@ -311,7 +316,7 @@ export class RequestGraph extends ContentGraph< if (env[node.value.key] !== node.value.value) { let parentNodes = this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_update', + requestGraphEdgeTypes.invalidated_by_update, ); for (let parentNode of parentNodes) { this.invalidateNode(parentNode, ENV_CHANGE); @@ -327,7 +332,7 @@ export class RequestGraph extends ContentGraph< if (hashFromOption(options[node.value.key]) !== node.value.hash) { let parentNodes = this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_update', + requestGraphEdgeTypes.invalidated_by_update, ); for (let parentNode of parentNodes) { this.invalidateNode(parentNode, OPTION_CHANGE); @@ -339,16 +344,36 @@ export class RequestGraph extends ContentGraph< invalidateOnFileUpdate(requestNodeId: NodeId, filePath: ProjectPath) { let fileNodeId = this.addNode(nodeFromFilePath(filePath)); - if (!this.hasEdge(requestNodeId, fileNodeId, 'invalidated_by_update')) { - this.addEdge(requestNodeId, fileNodeId, 'invalidated_by_update'); + if ( + !this.hasEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ) + ) { + this.addEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); } } invalidateOnFileDelete(requestNodeId: NodeId, filePath: ProjectPath) { let fileNodeId = this.addNode(nodeFromFilePath(filePath)); - if (!this.hasEdge(requestNodeId, fileNodeId, 'invalidated_by_delete')) { - this.addEdge(requestNodeId, fileNodeId, 'invalidated_by_delete'); + if ( + !this.hasEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_delete, + ) + ) { + this.addEdge( + requestNodeId, + fileNodeId, + requestGraphEdgeTypes.invalidated_by_delete, + ); } } @@ -375,9 +400,17 @@ export class RequestGraph extends ContentGraph< let fileNameNodeId = this.addNode(fileNameNode); if ( lastNodeId != null && - !this.hasEdge(lastNodeId, fileNameNodeId, 'dirname') + !this.hasEdge( + lastNodeId, + fileNameNodeId, + requestGraphEdgeTypes.dirname, + ) ) { - this.addEdge(lastNodeId, fileNameNodeId, 'dirname'); + this.addEdge( + lastNodeId, + fileNameNodeId, + requestGraphEdgeTypes.dirname, + ); } lastNodeId = fileNameNodeId; @@ -399,13 +432,33 @@ export class RequestGraph extends ContentGraph< // node will be invalidated. let firstId = 'file_name:' + parts[0]; let firstNodeId = this.getNodeIdByContentKey(firstId); - if (!this.hasEdge(nodeId, firstNodeId, 'invalidated_by_create_above')) { - this.addEdge(nodeId, firstNodeId, 'invalidated_by_create_above'); + if ( + !this.hasEdge( + nodeId, + firstNodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ) + ) { + this.addEdge( + nodeId, + firstNodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ); } invariant(lastNodeId != null); - if (!this.hasEdge(lastNodeId, nodeId, 'invalidated_by_create_above')) { - this.addEdge(lastNodeId, nodeId, 'invalidated_by_create_above'); + if ( + !this.hasEdge( + lastNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ) + ) { + this.addEdge( + lastNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ); } } else if (input.filePath != null) { node = nodeFromFilePath(input.filePath); @@ -414,8 +467,18 @@ export class RequestGraph extends ContentGraph< } let nodeId = this.addNode(node); - if (!this.hasEdge(requestNodeId, nodeId, 'invalidated_by_create')) { - this.addEdge(requestNodeId, nodeId, 'invalidated_by_create'); + if ( + !this.hasEdge( + requestNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create, + ) + ) { + this.addEdge( + requestNodeId, + nodeId, + requestGraphEdgeTypes.invalidated_by_create, + ); } } @@ -432,8 +495,18 @@ export class RequestGraph extends ContentGraph< let envNode = nodeFromEnv(env, value); let envNodeId = this.addNode(envNode); - if (!this.hasEdge(requestNodeId, envNodeId, 'invalidated_by_update')) { - this.addEdge(requestNodeId, envNodeId, 'invalidated_by_update'); + if ( + !this.hasEdge( + requestNodeId, + envNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ) + ) { + this.addEdge( + requestNodeId, + envNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); } } @@ -445,16 +518,41 @@ export class RequestGraph extends ContentGraph< let optionNode = nodeFromOption(option, value); let optionNodeId = this.addNode(optionNode); - if (!this.hasEdge(requestNodeId, optionNodeId, 'invalidated_by_update')) { - this.addEdge(requestNodeId, optionNodeId, 'invalidated_by_update'); + if ( + !this.hasEdge( + requestNodeId, + optionNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ) + ) { + this.addEdge( + requestNodeId, + optionNodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); } } clearInvalidations(nodeId: NodeId) { this.unpredicatableNodeIds.delete(nodeId); - this.replaceNodeIdsConnectedTo(nodeId, [], null, 'invalidated_by_update'); - this.replaceNodeIdsConnectedTo(nodeId, [], null, 'invalidated_by_delete'); - this.replaceNodeIdsConnectedTo(nodeId, [], null, 'invalidated_by_create'); + this.replaceNodeIdsConnectedTo( + nodeId, + [], + null, + requestGraphEdgeTypes.invalidated_by_update, + ); + this.replaceNodeIdsConnectedTo( + nodeId, + [], + null, + requestGraphEdgeTypes.invalidated_by_delete, + ); + this.replaceNodeIdsConnectedTo( + nodeId, + [], + null, + requestGraphEdgeTypes.invalidated_by_create, + ); } getInvalidations(requestNodeId: NodeId): Array { @@ -465,7 +563,7 @@ export class RequestGraph extends ContentGraph< // For now just handling updates. Could add creates/deletes later if needed. let invalidations = this.getNodeIdsConnectedFrom( requestNodeId, - 'invalidated_by_update', + requestGraphEdgeTypes.invalidated_by_update, ); return invalidations .map(nodeId => { @@ -487,7 +585,10 @@ export class RequestGraph extends ContentGraph< return []; } - let subRequests = this.getNodeIdsConnectedFrom(requestNodeId, 'subrequest'); + let subRequests = this.getNodeIdsConnectedFrom( + requestNodeId, + requestGraphEdgeTypes.subrequest, + ); return subRequests.map(nodeId => { let node = nullthrows(this.getNode(nodeId)); @@ -510,7 +611,11 @@ export class RequestGraph extends ContentGraph< for (let matchNode of matchNodes) { let matchNodeId = this.getNodeIdByContentKey(matchNode.id); if ( - this.hasEdge(nodeId, matchNodeId, 'invalidated_by_create_above') && + this.hasEdge( + nodeId, + matchNodeId, + requestGraphEdgeTypes.invalidated_by_create_above, + ) && isDirectoryInside( path.dirname(fromProjectPathRelative(matchNode.value.filePath)), dirname, @@ -518,7 +623,7 @@ export class RequestGraph extends ContentGraph< ) { let connectedNodes = this.getNodeIdsConnectedTo( matchNodeId, - 'invalidated_by_create', + requestGraphEdgeTypes.invalidated_by_create, ); for (let connectedNode of connectedNodes) { this.invalidateNode(connectedNode, FILE_CREATE); @@ -532,7 +637,11 @@ export class RequestGraph extends ContentGraph< let contentKey = 'file_name:' + basename; if (this.hasContentKey(contentKey)) { if ( - this.hasEdge(nodeId, this.getNodeIdByContentKey(contentKey), 'dirname') + this.hasEdge( + nodeId, + this.getNodeIdByContentKey(contentKey), + requestGraphEdgeTypes.dirname, + ) ) { let parent = nullthrows(this.getNodeByContentKey(contentKey)); invariant(parent.type === 'file_name'); @@ -570,7 +679,10 @@ export class RequestGraph extends ContentGraph< // then also invalidate nodes connected by invalidated_by_update edges. if (hasFileRequest && (type === 'create' || type === 'update')) { let nodeId = this.getNodeIdByContentKey(filePath); - let nodes = this.getNodeIdsConnectedTo(nodeId, 'invalidated_by_update'); + let nodes = this.getNodeIdsConnectedTo( + nodeId, + requestGraphEdgeTypes.invalidated_by_update, + ); for (let connectedNode of nodes) { didInvalidate = true; @@ -580,7 +692,7 @@ export class RequestGraph extends ContentGraph< if (type === 'create') { let nodes = this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_create', + requestGraphEdgeTypes.invalidated_by_create, ); for (let connectedNode of nodes) { didInvalidate = true; @@ -597,7 +709,7 @@ export class RequestGraph extends ContentGraph< // Find potential file nodes to be invalidated if this file name pattern matches let above = this.getNodeIdsConnectedTo( fileNameNodeId, - 'invalidated_by_create_above', + requestGraphEdgeTypes.invalidated_by_create_above, ).map(nodeId => { let node = nullthrows(this.getNode(nodeId)); invariant(node.type === 'file'); @@ -617,7 +729,7 @@ export class RequestGraph extends ContentGraph< if (isGlobMatch(filePath, fromProjectPathRelative(globNode.value))) { let connectedNodes = this.getNodeIdsConnectedTo( globeNodeId, - 'invalidated_by_create', + requestGraphEdgeTypes.invalidated_by_create, ); for (let connectedNode of connectedNodes) { didInvalidate = true; @@ -629,7 +741,7 @@ export class RequestGraph extends ContentGraph< let nodeId = this.getNodeIdByContentKey(filePath); for (let connectedNode of this.getNodeIdsConnectedTo( nodeId, - 'invalidated_by_delete', + requestGraphEdgeTypes.invalidated_by_delete, )) { didInvalidate = true; this.invalidateNode(connectedNode, FILE_DELETE); diff --git a/packages/core/core/src/applyRuntimes.js b/packages/core/core/src/applyRuntimes.js index 1bab6a64551..fcd2a9a6707 100644 --- a/packages/core/core/src/applyRuntimes.js +++ b/packages/core/core/src/applyRuntimes.js @@ -20,7 +20,7 @@ import invariant from 'assert'; import nullthrows from 'nullthrows'; import AssetGraph, {nodeFromAssetGroup} from './AssetGraph'; import BundleGraph from './public/BundleGraph'; -import InternalBundleGraph from './BundleGraph'; +import InternalBundleGraph, {bundleGraphEdgeTypes} from './BundleGraph'; import {NamedBundle} from './public/Bundle'; import {PluginLogger} from '@parcel/logger'; import {hashString} from '@parcel/hash'; @@ -218,7 +218,11 @@ export default async function applyRuntimes({ const bundleGraphNodeId = bundleGraph._graph.getNodeIdByContentKey( node.id, ); // the node id is not constant between graphs - bundleGraph._graph.addEdge(bundleNodeId, bundleGraphNodeId, 'contains'); + bundleGraph._graph.addEdge( + bundleNodeId, + bundleGraphNodeId, + bundleGraphEdgeTypes.contains, + ); } }, runtimesGraphRuntimeNodeId); diff --git a/packages/core/core/src/dumpGraphToGraphViz.js b/packages/core/core/src/dumpGraphToGraphViz.js index 05aaaaabb0a..65ec13025cd 100644 --- a/packages/core/core/src/dumpGraphToGraphViz.js +++ b/packages/core/core/src/dumpGraphToGraphViz.js @@ -2,6 +2,8 @@ import type {Graph} from '@parcel/graph'; import type {AssetGraphNode, BundleGraphNode, Environment} from './types'; +import {bundleGraphEdgeTypes} from './BundleGraph'; +import {requestGraphEdgeTypes} from './RequestTracker'; import path from 'path'; import {fromProjectPathRelative} from './projectPath'; @@ -32,6 +34,7 @@ export default async function dumpGraphToGraphViz( // $FlowFixMe graph: Graph | Graph, name: string, + edgeTypes?: typeof bundleGraphEdgeTypes | typeof requestGraphEdgeTypes, ): Promise { if ( process.env.PARCEL_BUILD_ENV === 'production' || @@ -129,9 +132,20 @@ export default async function dumpGraphToGraphViz( } n.set('label', label); } + + let edgeNames; + if (edgeTypes) { + edgeNames = Object.fromEntries( + Object.entries(edgeTypes).map(([k, v]) => [v, k]), + ); + } + for (let edge of graph.getAllEdges()) { let gEdge = g.addEdge(nodeId(edge.from), nodeId(edge.to)); - let color = edge.type != null ? TYPE_COLORS[edge.type] : null; + let color = null; + if (edge.type != 1 && edgeNames) { + color = TYPE_COLORS[edgeNames[edge.type]]; + } if (color != null) { gEdge.set('color', color); } diff --git a/packages/core/core/src/public/MutableBundleGraph.js b/packages/core/core/src/public/MutableBundleGraph.js index e90949ae3ae..e59a2d8ac9c 100644 --- a/packages/core/core/src/public/MutableBundleGraph.js +++ b/packages/core/core/src/public/MutableBundleGraph.js @@ -15,7 +15,7 @@ import invariant from 'assert'; import nullthrows from 'nullthrows'; import {hashString} from '@parcel/hash'; import BundleGraph from './BundleGraph'; -import InternalBundleGraph from '../BundleGraph'; +import InternalBundleGraph, {bundleGraphEdgeTypes} from '../BundleGraph'; import {Bundle, bundleToInternalBundle} from './Bundle'; import {assetFromValue, assetToAssetValue} from './Asset'; import {getBundleGroupId, getPublicId} from '../utils'; @@ -107,19 +107,23 @@ export default class MutableBundleGraph extends BundleGraph ); this.#graph._graph.addEdge(dependencyNodeId, bundleGroupNodeId); this.#graph._graph.replaceNodeIdsConnectedTo(bundleGroupNodeId, assetNodes); - this.#graph._graph.addEdge(dependencyNodeId, resolvedNodeId, 'references'); + this.#graph._graph.addEdge( + dependencyNodeId, + resolvedNodeId, + bundleGraphEdgeTypes.references, + ); this.#graph._graph.removeEdge(dependencyNodeId, resolvedNodeId); if (dependency.isEntry) { this.#graph._graph.addEdge( nullthrows(this.#graph._graph.rootNodeId), bundleGroupNodeId, - 'bundle', + bundleGraphEdgeTypes.bundle, ); } else { let inboundBundleNodeIds = this.#graph._graph.getNodeIdsConnectedTo( dependencyNodeId, - 'contains', + bundleGraphEdgeTypes.contains, ); for (let inboundBundleNodeId of inboundBundleNodeIds) { invariant( @@ -128,7 +132,7 @@ export default class MutableBundleGraph extends BundleGraph this.#graph._graph.addEdge( inboundBundleNodeId, bundleGroupNodeId, - 'bundle', + bundleGraphEdgeTypes.bundle, ); } } diff --git a/packages/core/core/src/requests/BundleGraphRequest.js b/packages/core/core/src/requests/BundleGraphRequest.js index dcca6df7a53..13da2f1dbac 100644 --- a/packages/core/core/src/requests/BundleGraphRequest.js +++ b/packages/core/core/src/requests/BundleGraphRequest.js @@ -18,7 +18,7 @@ import {PluginLogger} from '@parcel/logger'; import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; import AssetGraph from '../AssetGraph'; import BundleGraph from '../public/BundleGraph'; -import InternalBundleGraph from '../BundleGraph'; +import InternalBundleGraph, {bundleGraphEdgeTypes} from '../BundleGraph'; import MutableBundleGraph from '../public/MutableBundleGraph'; import {Bundle, NamedBundle} from '../public/Bundle'; import {report} from '../ReporterRunner'; @@ -200,8 +200,12 @@ class BundlerRunner { } let internalBundleGraph = InternalBundleGraph.fromAssetGraph(graph); - // $FlowFixMe - await dumpGraphToGraphViz(internalBundleGraph._graph, 'before_bundle'); + await dumpGraphToGraphViz( + // $FlowFixMe + internalBundleGraph._graph, + 'before_bundle', + bundleGraphEdgeTypes, + ); let mutableBundleGraph = new MutableBundleGraph( internalBundleGraph, this.options, @@ -223,8 +227,12 @@ class BundlerRunner { }), }); } finally { - // $FlowFixMe[incompatible-call] - await dumpGraphToGraphViz(internalBundleGraph._graph, 'after_bundle'); + await dumpGraphToGraphViz( + // $FlowFixMe[incompatible-call] + internalBundleGraph._graph, + 'after_bundle', + bundleGraphEdgeTypes, + ); } if (this.pluginOptions.mode === 'production') { @@ -242,8 +250,12 @@ class BundlerRunner { }), }); } finally { - // $FlowFixMe[incompatible-call] - await dumpGraphToGraphViz(internalBundleGraph._graph, 'after_optimize'); + await dumpGraphToGraphViz( + // $FlowFixMe[incompatible-call] + internalBundleGraph._graph, + 'after_optimize', + bundleGraphEdgeTypes, + ); } } @@ -273,8 +285,12 @@ class BundlerRunner { configs: this.configs, }); - // $FlowFixMe - await dumpGraphToGraphViz(internalBundleGraph._graph, 'after_runtimes'); + await dumpGraphToGraphViz( + // $FlowFixMe + internalBundleGraph._graph, + 'after_runtimes', + bundleGraphEdgeTypes, + ); // Store the serialized bundle graph in an in memory cache so that we avoid serializing it // many times to send to each worker, and in build mode, when writing to cache on shutdown. diff --git a/packages/core/core/src/requests/ParcelBuildRequest.js b/packages/core/core/src/requests/ParcelBuildRequest.js index 56b690afe78..ea5a2a00215 100644 --- a/packages/core/core/src/requests/ParcelBuildRequest.js +++ b/packages/core/core/src/requests/ParcelBuildRequest.js @@ -14,6 +14,7 @@ import createBundleGraphRequest from './BundleGraphRequest'; import createWriteBundlesRequest from './WriteBundlesRequest'; import {assertSignalNotAborted} from '../utils'; import dumpGraphToGraphViz from '../dumpGraphToGraphViz'; +import {bundleGraphEdgeTypes} from '../BundleGraph'; type ParcelBuildRequestInput = {| optionsRef: SharedReference, @@ -75,7 +76,7 @@ async function run({input, api, options}: RunInput) { let bundleGraph = await api.runRequest(bundleGraphRequest); // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381 (Windows only) - dumpGraphToGraphViz(bundleGraph._graph, 'BundleGraph'); + dumpGraphToGraphViz(bundleGraph._graph, 'BundleGraph', bundleGraphEdgeTypes); let writeBundlesRequest = createWriteBundlesRequest({ bundleGraph, diff --git a/packages/core/core/test/AssetGraph.test.js b/packages/core/core/test/AssetGraph.test.js index 36d27794b36..ce1ed9e500d 100644 --- a/packages/core/core/test/AssetGraph.test.js +++ b/packages/core/core/test/AssetGraph.test.js @@ -154,12 +154,12 @@ describe('AssetGraph', () => { { from: graph.rootNodeId, to: graph.getNodeIdByContentKey('entry_specifier:path/to/index1'), - type: null, + type: 1, }, { from: graph.rootNodeId, to: graph.getNodeIdByContentKey('entry_specifier:path/to/index2'), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey('entry_specifier:path/to/index1'), @@ -169,7 +169,7 @@ describe('AssetGraph', () => { packagePath: toProjectPath('/path/to/index1'), }).id, ), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey('entry_specifier:path/to/index2'), @@ -179,7 +179,7 @@ describe('AssetGraph', () => { packagePath: toProjectPath('/path/to/index2'), }).id, ), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey( @@ -196,7 +196,7 @@ describe('AssetGraph', () => { env: DEFAULT_ENV, }).id, ), - type: null, + type: 1, }, { from: graph.getNodeIdByContentKey( @@ -213,7 +213,7 @@ describe('AssetGraph', () => { env: DEFAULT_ENV, }).id, ), - type: null, + type: 1, }, ]); }); diff --git a/packages/core/graph/src/ContentGraph.js b/packages/core/graph/src/ContentGraph.js index 9cfdad0e651..e43da92cddc 100644 --- a/packages/core/graph/src/ContentGraph.js +++ b/packages/core/graph/src/ContentGraph.js @@ -4,16 +4,16 @@ import type {ContentKey, NodeId} from './types'; import Graph, {type GraphOpts} from './Graph'; import nullthrows from 'nullthrows'; -export type SerializedContentGraph = {| +export type SerializedContentGraph = {| ...GraphOpts, _contentKeyToNodeId: Map, _nodeIdToContentKey: Map, |}; -export default class ContentGraph< +export default class ContentGraph extends Graph< TNode, - TEdgeType: string | null = null, -> extends Graph { + TEdgeType, +> { _contentKeyToNodeId: Map; _nodeIdToContentKey: Map; diff --git a/packages/core/graph/src/Graph.js b/packages/core/graph/src/Graph.js index fe37bfa5023..d68ced59065 100644 --- a/packages/core/graph/src/Graph.js +++ b/packages/core/graph/src/Graph.js @@ -7,21 +7,22 @@ import type {TraversalActions, GraphVisitor} from '@parcel/types'; import assert from 'assert'; import nullthrows from 'nullthrows'; -export type GraphOpts = {| +type NullEdgeType = 1; +export type GraphOpts = {| nodes?: Map, - edges?: AdjacencyListMap, + edges?: AdjacencyListMap, rootNodeId?: ?NodeId, nextNodeId?: ?number, |}; export const ALL_EDGE_TYPES = '@@all_edge_types'; -export default class Graph { +export default class Graph { nodes: Map; - inboundEdges: AdjacencyList; - outboundEdges: AdjacencyList; + inboundEdges: AdjacencyList; + outboundEdges: AdjacencyList; rootNodeId: ?NodeId; - nextNodeId: number = 0; + nextNodeId: number = 1; constructor(opts: ?GraphOpts) { this.nodes = opts?.nodes || new Map(); @@ -71,7 +72,7 @@ export default class Graph { // Returns a list of all edges in the graph. This can be large, so iterating // the complete list can be costly in large graphs. Used when merging graphs. - getAllEdges(): Array> { + getAllEdges(): Array> { let edges = []; for (let [from, edgeList] of this.outboundEdges.getListMap()) { for (let [type, toNodes] of edgeList) { @@ -97,7 +98,7 @@ export default class Graph { return this.nodes.get(id); } - addEdge(from: NodeId, to: NodeId, type: TEdgeType | null = null): void { + addEdge(from: NodeId, to: NodeId, type: TEdgeType | NullEdgeType = 1): void { if (!this.getNode(from)) { throw new Error(`"from" node '${fromNodeId(from)}' not found`); } @@ -110,13 +111,17 @@ export default class Graph { this.inboundEdges.addEdge(to, from, type); } - hasEdge(from: NodeId, to: NodeId, type?: TEdgeType | null = null): boolean { + hasEdge( + from: NodeId, + to: NodeId, + type?: TEdgeType | NullEdgeType = 1, + ): boolean { return this.outboundEdges.hasEdge(from, to, type); } getNodeIdsConnectedTo( nodeId: NodeId, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): Array { this._assertHasNodeId(nodeId); @@ -149,7 +154,7 @@ export default class Graph { getNodeIdsConnectedFrom( nodeId: NodeId, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): Array { this._assertHasNodeId(nodeId); let outboundByType = this.outboundEdges.getEdgesByType(nodeId); @@ -206,7 +211,7 @@ export default class Graph { assert(wasRemoved); } - removeEdges(nodeId: NodeId, type: TEdgeType | null = null) { + removeEdges(nodeId: NodeId, type: TEdgeType | NullEdgeType = 1) { this._assertHasNodeId(nodeId); for (let to of this.outboundEdges.getEdges(nodeId, type)) { @@ -218,7 +223,7 @@ export default class Graph { removeEdge( from: NodeId, to: NodeId, - type: TEdgeType | null = null, + type: TEdgeType | NullEdgeType = 1, removeOrphans: boolean = true, ) { if (!this.outboundEdges.hasEdge(from, to, type)) { @@ -290,7 +295,7 @@ export default class Graph { replaceNode( fromNodeId: NodeId, toNodeId: NodeId, - type: TEdgeType | null = null, + type: TEdgeType | NullEdgeType = 1, ): void { this._assertHasNodeId(fromNodeId); for (let parent of this.inboundEdges.getEdges(fromNodeId, type)) { @@ -305,7 +310,7 @@ export default class Graph { fromNodeId: NodeId, toNodeIds: $ReadOnlyArray, replaceFilter?: null | (NodeId => boolean), - type?: TEdgeType | null = null, + type?: TEdgeType | NullEdgeType = 1, ): void { this._assertHasNodeId(fromNodeId); @@ -331,7 +336,7 @@ export default class Graph { traverse( visit: GraphVisitor, startNodeId: ?NodeId, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): ?TContext { return this.dfs({ visit, @@ -344,7 +349,7 @@ export default class Graph { filter: (NodeId, TraversalActions) => ?TValue, visit: GraphVisitor, startNodeId: ?NodeId, - type?: TEdgeType | null | Array, + type?: TEdgeType | Array, ): ?TContext { return this.traverse(mapVisitor(filter, visit), startNodeId, type); } @@ -352,7 +357,7 @@ export default class Graph { traverseAncestors( startNodeId: ?NodeId, visit: GraphVisitor, - type: TEdgeType | null | Array = null, + type: TEdgeType | NullEdgeType | Array = 1, ): ?TContext { return this.dfs({ visit, diff --git a/packages/core/graph/src/types.js b/packages/core/graph/src/types.js index 2e8e4d501e9..355f02d08a8 100644 --- a/packages/core/graph/src/types.js +++ b/packages/core/graph/src/types.js @@ -11,7 +11,7 @@ export function fromNodeId(x: NodeId): number { export type ContentKey = string; -export type Edge = {| +export type Edge = {| from: NodeId, to: NodeId, type: TEdgeType, diff --git a/packages/core/graph/test/Graph.test.js b/packages/core/graph/test/Graph.test.js index f311d01996b..bbecc3a28ec 100644 --- a/packages/core/graph/test/Graph.test.js +++ b/packages/core/graph/test/Graph.test.js @@ -87,7 +87,7 @@ describe('Graph', () => { let nodeB = graph.addNode('b'); let nodeC = graph.addNode('c'); graph.addEdge(nodeA, nodeB); - graph.addEdge(nodeA, nodeC, 'edgetype'); + graph.addEdge(nodeA, nodeC, 1); assert(graph.isOrphanedNode(nodeA)); assert(!graph.isOrphanedNode(nodeB)); assert(!graph.isOrphanedNode(nodeC)); @@ -114,9 +114,7 @@ describe('Graph', () => { assert(graph.nodes.has(nodeD)); assert(!graph.nodes.has(nodeB)); assert(!graph.nodes.has(nodeC)); - assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeD, type: null}, - ]); + assert.deepEqual(graph.getAllEdges(), [{from: nodeA, to: nodeD, type: 1}]); }); it('removing a node recursively deletes orphaned nodes', () => { @@ -157,8 +155,8 @@ describe('Graph', () => { assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeC, type: null}, - {from: nodeC, to: nodeF, type: null}, + {from: nodeA, to: nodeC, type: 1}, + {from: nodeC, to: nodeF, type: 1}, ]); }); @@ -202,8 +200,8 @@ describe('Graph', () => { assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeC, type: null}, - {from: nodeC, to: nodeF, type: null}, + {from: nodeA, to: nodeC, type: 1}, + {from: nodeC, to: nodeF, type: 1}, ]); }); @@ -237,11 +235,11 @@ describe('Graph', () => { assert.deepEqual(nodesBefore, getNodeIds()); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeB, type: null}, - {from: nodeB, to: nodeC, type: null}, - {from: nodeB, to: nodeD, type: null}, - {from: nodeD, to: nodeE, type: null}, - {from: nodeE, to: nodeB, type: null}, + {from: nodeA, to: nodeB, type: 1}, + {from: nodeB, to: nodeC, type: 1}, + {from: nodeB, to: nodeD, type: 1}, + {from: nodeD, to: nodeE, type: 1}, + {from: nodeE, to: nodeB, type: 1}, ]); }); @@ -280,8 +278,8 @@ describe('Graph', () => { assert(!graph.hasNode(nodeC)); assert(graph.hasNode(nodeD)); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeB, type: null}, - {from: nodeA, to: nodeD, type: null}, + {from: nodeA, to: nodeB, type: 1}, + {from: nodeA, to: nodeD, type: 1}, ]); }); @@ -292,10 +290,10 @@ describe('Graph', () => { let nodeC = graph.addNode('c'); let nodeD = graph.addNode('d'); - graph.addEdge(nodeA, nodeB, 'edgetype'); + graph.addEdge(nodeA, nodeB, 2); graph.addEdge(nodeA, nodeD); graph.addEdge(nodeB, nodeC); - graph.addEdge(nodeB, nodeD, 'edgetype'); + graph.addEdge(nodeB, nodeD, 2); graph.setRootNodeId(nodeA); @@ -305,7 +303,7 @@ describe('Graph', () => { visited.push(nodeId); }, null, // use root as startNode - 'edgetype', + 2, ); assert.deepEqual(visited, [nodeA, nodeB, nodeD]); From 2013dfff74468ee8a3a1dbed6742db32dd24032a Mon Sep 17 00:00:00 2001 From: Toby de Havilland <59738910+toby-wollit@users.noreply.github.com> Date: Thu, 16 Sep 2021 11:33:33 +0100 Subject: [PATCH 4/7] Reorder resolveOptions() env priority (#6904) --- packages/core/core/src/resolveOptions.js | 4 ++-- packages/core/integration-tests/test/javascript.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/core/core/src/resolveOptions.js b/packages/core/core/src/resolveOptions.js index b0992beba1d..1ce2e208571 100644 --- a/packages/core/core/src/resolveOptions.js +++ b/packages/core/core/src/resolveOptions.js @@ -108,14 +108,14 @@ export default async function resolveOptions( ), shouldPatchConsole: initialOptions.shouldPatchConsole ?? false, env: { - ...process.env, - ...initialOptions.env, ...(await loadDotEnv( initialOptions.env ?? {}, inputFS, path.join(projectRoot, 'index'), projectRoot, )), + ...process.env, + ...initialOptions.env, }, mode, shouldAutoInstall: initialOptions.shouldAutoInstall ?? false, diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index b9189a79169..e5f3e25ede9 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -2940,6 +2940,16 @@ describe('javascript', function() { assert.equal(output, 'productiontest'); }); + it('should overwrite environment variables from a file if passed', async function() { + let b = await bundle( + path.join(__dirname, '/integration/env-file/index.js'), + {env: {BAR: 'baz'}}, + ); + + let output = await run(b); + assert.equal(output, 'barbaz'); + }); + it('should error on process.env mutations', async function() { let filePath = path.join(__dirname, '/integration/env-mutate/index.js'); await assert.rejects(bundle(filePath), { From b6faa0c819d562726ac8708f7f91ff0cb65b8311 Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Sun, 19 Sep 2021 00:46:05 +0100 Subject: [PATCH 5/7] Don't fail when HTML tags are implied (#6752) --- flow-libs/posthtml-parser.js.flow | 5 ++- flow-libs/posthtml-render.js.flow | 7 ++-- packages/core/integration-tests/test/html.js | 32 +++++++++++++++++++ .../test/integration/html-invalid/index.html | 14 ++++++++ .../html-optional-closing-tags/index.html | 9 ++++++ packages/core/test-utils/package.json | 4 +-- packages/core/test-utils/src/utils.js | 2 +- packages/optimizers/htmlnano/package.json | 2 +- packages/packagers/html/package.json | 2 +- packages/transformers/html/package.json | 6 ++-- .../transformers/html/src/HTMLTransformer.js | 4 +-- packages/transformers/posthtml/package.json | 6 ++-- .../posthtml/src/PostHTMLTransformer.js | 4 +-- packages/transformers/svg/package.json | 6 ++-- .../transformers/svg/src/SVGTransformer.js | 4 +-- yarn.lock | 17 +++++++--- 16 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/html-invalid/index.html create mode 100644 packages/core/integration-tests/test/integration/html-optional-closing-tags/index.html diff --git a/flow-libs/posthtml-parser.js.flow b/flow-libs/posthtml-parser.js.flow index ae5f4c5d24c..32ae1c9c942 100644 --- a/flow-libs/posthtml-parser.js.flow +++ b/flow-libs/posthtml-parser.js.flow @@ -22,5 +22,8 @@ declare module 'posthtml-parser' { } ) => PostHTMLNode; - declare module.exports: typeof parser; + declare module.exports: { + parser: typeof parser; + ... + } } diff --git a/flow-libs/posthtml-render.js.flow b/flow-libs/posthtml-render.js.flow index be6ab7f4d6e..ad4289c6415 100644 --- a/flow-libs/posthtml-render.js.flow +++ b/flow-libs/posthtml-render.js.flow @@ -12,7 +12,7 @@ declare module 'posthtml-render' { ... }; - declare var parser: ( + declare var render: ( tree: PostHTMLNode, options?: { singleTags?: Array, @@ -21,5 +21,8 @@ declare module 'posthtml-render' { } ) => string; - declare module.exports: typeof parser; + declare module.exports: { + render: typeof render; + ... + } } diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index 990a8344088..e1fa04cd7f4 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -467,6 +467,38 @@ describe('html', function() { assert.equal(html.length, 0); }); + it('should work with an invalid html file', async function() { + let inputFile = path.join( + __dirname, + '/integration/html-invalid/index.html', + ); + await bundle(inputFile, { + defaultTargetOptions: { + shouldOptimize: false, + }, + }); + + let outputFile = path.join(distDir, 'index.html'); + let html = await outputFS.readFile(outputFile, 'utf8'); + assert(html.includes('This is a paragraph')); + }); + + it("should work with html that doesn't include optional closing tags", async function() { + let inputFile = path.join( + __dirname, + '/integration/html-optional-closing-tags/index.html', + ); + await bundle(inputFile, { + defaultTargetOptions: { + shouldOptimize: false, + }, + }); + + let outputFile = path.join(distDir, 'index.html'); + let html = await outputFS.readFile(outputFile, 'utf8'); + assert(html.includes('Paragraph 1')); + }); + it('should read .htmlnanorc.json and minify HTML in production mode', async function() { await bundle( path.join(__dirname, '/integration/htmlnano-config/index.html'), diff --git a/packages/core/integration-tests/test/integration/html-invalid/index.html b/packages/core/integration-tests/test/integration/html-invalid/index.html new file mode 100644 index 00000000000..60e7ff060bb --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-invalid/index.html @@ -0,0 +1,14 @@ + + + + + Invalid HTML file + + + + +

This is a paragraph.

  • This is a list.

+ + + + diff --git a/packages/core/integration-tests/test/integration/html-optional-closing-tags/index.html b/packages/core/integration-tests/test/integration/html-optional-closing-tags/index.html new file mode 100644 index 00000000000..0c6cd109d23 --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-optional-closing-tags/index.html @@ -0,0 +1,9 @@ + + +Title + +

Paragraph 1 + +


+ +

Paragraph 2 diff --git a/packages/core/test-utils/package.json b/packages/core/test-utils/package.json index 8121e6194b2..41746b34ffb 100644 --- a/packages/core/test-utils/package.json +++ b/packages/core/test-utils/package.json @@ -21,8 +21,8 @@ "chalk": "^4.1.0", "ncp": "^2.0.0", "nullthrows": "^1.1.1", - "posthtml": "^0.16.4", - "posthtml-parser": "^0.9.0", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", "resolve": "^1.12.0", "ws": "^7.0.0" } diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index 2177941ff20..e513992b8b0 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -24,7 +24,7 @@ import path from 'path'; import url from 'url'; import WebSocket from 'ws'; import nullthrows from 'nullthrows'; -import postHtmlParse from 'posthtml-parser'; +import {parser as postHtmlParse} from 'posthtml-parser'; import postHtml from 'posthtml'; import EventEmitter from 'events'; diff --git a/packages/optimizers/htmlnano/package.json b/packages/optimizers/htmlnano/package.json index 6fd2a73bd24..6c738f9ff61 100644 --- a/packages/optimizers/htmlnano/package.json +++ b/packages/optimizers/htmlnano/package.json @@ -23,7 +23,7 @@ "@parcel/plugin": "2.0.0-rc.0", "htmlnano": "^1.0.1", "nullthrows": "^1.1.1", - "posthtml": "^0.16.4", + "posthtml": "^0.16.5", "svgo": "^2.4.0" } } diff --git a/packages/packagers/html/package.json b/packages/packagers/html/package.json index 6123c6495fe..3ad37a5bf89 100644 --- a/packages/packagers/html/package.json +++ b/packages/packagers/html/package.json @@ -24,6 +24,6 @@ "@parcel/types": "2.0.0-rc.0", "@parcel/utils": "2.0.0-rc.0", "nullthrows": "^1.1.1", - "posthtml": "^0.16.4" + "posthtml": "^0.16.5" } } diff --git a/packages/transformers/html/package.json b/packages/transformers/html/package.json index a80b37e1773..b1eb1ad5fd5 100644 --- a/packages/transformers/html/package.json +++ b/packages/transformers/html/package.json @@ -23,9 +23,9 @@ "@parcel/hash": "2.0.0-rc.0", "@parcel/plugin": "2.0.0-rc.0", "nullthrows": "^1.1.1", - "posthtml": "^0.16.4", - "posthtml-parser": "^0.9.0", - "posthtml-render": "^2.0.6", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", "semver": "^5.4.1" } } diff --git a/packages/transformers/html/src/HTMLTransformer.js b/packages/transformers/html/src/HTMLTransformer.js index 13b85e80dce..db7bf863f25 100644 --- a/packages/transformers/html/src/HTMLTransformer.js +++ b/packages/transformers/html/src/HTMLTransformer.js @@ -1,9 +1,9 @@ // @flow import {Transformer} from '@parcel/plugin'; -import parse from 'posthtml-parser'; +import {parser as parse} from 'posthtml-parser'; import nullthrows from 'nullthrows'; -import render from 'posthtml-render'; +import {render} from 'posthtml-render'; import semver from 'semver'; import collectDependencies from './dependencies'; import extractInlineAssets from './inline'; diff --git a/packages/transformers/posthtml/package.json b/packages/transformers/posthtml/package.json index 64f138a57ae..b9180495d18 100644 --- a/packages/transformers/posthtml/package.json +++ b/packages/transformers/posthtml/package.json @@ -23,9 +23,9 @@ "@parcel/plugin": "2.0.0-rc.0", "@parcel/utils": "2.0.0-rc.0", "nullthrows": "^1.1.1", - "posthtml": "^0.16.4", - "posthtml-parser": "^0.9.0", - "posthtml-render": "^2.0.6", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", "semver": "^5.4.1" } } diff --git a/packages/transformers/posthtml/src/PostHTMLTransformer.js b/packages/transformers/posthtml/src/PostHTMLTransformer.js index c3767d1c175..49d3b3f7606 100644 --- a/packages/transformers/posthtml/src/PostHTMLTransformer.js +++ b/packages/transformers/posthtml/src/PostHTMLTransformer.js @@ -4,8 +4,8 @@ import {Transformer} from '@parcel/plugin'; import path from 'path'; import posthtml from 'posthtml'; -import parse from 'posthtml-parser'; -import render from 'posthtml-render'; +import {parser as parse} from 'posthtml-parser'; +import {render} from 'posthtml-render'; import nullthrows from 'nullthrows'; import semver from 'semver'; import {relativePath} from '@parcel/utils'; diff --git a/packages/transformers/svg/package.json b/packages/transformers/svg/package.json index 86db0487877..6d83419813f 100644 --- a/packages/transformers/svg/package.json +++ b/packages/transformers/svg/package.json @@ -23,9 +23,9 @@ "@parcel/hash": "2.0.0-rc.0", "@parcel/plugin": "2.0.0-rc.0", "nullthrows": "^1.1.1", - "posthtml": "^0.16.4", - "posthtml-parser": "^0.9.0", - "posthtml-render": "^2.0.6", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", "semver": "^5.4.1" } } diff --git a/packages/transformers/svg/src/SVGTransformer.js b/packages/transformers/svg/src/SVGTransformer.js index 21667f797de..2ad54bb13a3 100644 --- a/packages/transformers/svg/src/SVGTransformer.js +++ b/packages/transformers/svg/src/SVGTransformer.js @@ -3,8 +3,8 @@ import {Transformer} from '@parcel/plugin'; import nullthrows from 'nullthrows'; import semver from 'semver'; -import parse from 'posthtml-parser'; -import render from 'posthtml-render'; +import {parser as parse} from 'posthtml-parser'; +import {render} from 'posthtml-render'; import collectDependencies from './dependencies'; import extractInlineAssets from './inline'; diff --git a/yarn.lock b/yarn.lock index 24cfacb8237..a38503cc958 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5029,6 +5029,13 @@ domhandler@^4.0.0, domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" +domhandler@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" + integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== + dependencies: + domelementtype "^2.2.0" + domutils@^1.5.1, domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -7046,12 +7053,12 @@ htmlparser2@^6.0.0: entities "^2.0.0" htmlparser2@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.1.1.tgz#ef251d16e5b40818ba162aa24bc051c297eb3f76" - integrity sha512-hZb0lfG0hbhR/hB879zbBr8Opv0Be9Zp+JYHgqTw5epF++aotu/zmMTPLy/60iJyR1MaD/3pYRp7xYteXsZMEA== + version "7.1.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.1.2.tgz#587923d38f03bc89e03076e00cba2c7473f37f7c" + integrity sha512-d6cqsbJba2nRdg8WW2okyD4ceonFHn9jLFxhwlNcLhQWcFPdxXeJulgOLjLKtAK9T6ahd+GQNZwG9fjmGW7lyg== dependencies: domelementtype "^2.0.1" - domhandler "^4.0.0" + domhandler "^4.2.2" domutils "^2.8.0" entities "^3.0.1" @@ -10546,7 +10553,7 @@ posthtml-obfuscate@^0.1.5: resolved "https://registry.yarnpkg.com/posthtml-obfuscate/-/posthtml-obfuscate-0.1.5.tgz#d65f6642c96349002d33a2208845b2f7517d0fc8" integrity sha1-1l9mQsljSQAtM6IgiEWy91F9D8g= -posthtml-parser@^0.10.0: +posthtml-parser@^0.10.0, posthtml-parser@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.1.tgz#63c41931a9339cc2c32aba14f06286d98f107abf" integrity sha512-i7w2QEHqiGtsvNNPty0Mt/+ERch7wkgnFh3+JnBI2VgDbGlBqKW9eDVd3ENUhE1ujGFe3e3E/odf7eKhvLUyDg== From aaec5bae96bebe3d90046a1a182303b68336dcec Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Mon, 20 Sep 2021 23:42:35 +0200 Subject: [PATCH 6/7] Only use error overlay if there's a document (#6960) --- packages/runtimes/hmr/src/loaders/hmr-runtime.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/runtimes/hmr/src/loaders/hmr-runtime.js b/packages/runtimes/hmr/src/loaders/hmr-runtime.js index 53e2793f9a3..4b8da0d14d1 100644 --- a/packages/runtimes/hmr/src/loaders/hmr-runtime.js +++ b/packages/runtimes/hmr/src/loaders/hmr-runtime.js @@ -95,7 +95,9 @@ if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') { if (data.type === 'update') { // Remove error overlay if there is one - removeErrorOverlay(); + if (typeof document !== 'undefined') { + removeErrorOverlay(); + } let assets = data.assets.filter(asset => asset.envHash === HMR_ENV_HASH); @@ -143,11 +145,13 @@ if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') { ); } - // Render the fancy html overlay - removeErrorOverlay(); - var overlay = createErrorOverlay(data.diagnostics.html); - // $FlowFixMe - document.body.appendChild(overlay); + if (typeof document !== 'undefined') { + // Render the fancy html overlay + removeErrorOverlay(); + var overlay = createErrorOverlay(data.diagnostics.html); + // $FlowFixMe + document.body.appendChild(overlay); + } } }; ws.onerror = function(e) { From 1b980caf31e324fd2285d4301067191e4ad99243 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 20 Sep 2021 17:50:56 -0700 Subject: [PATCH 7/7] Upgrade Flow to 0.160.1 (#6964) Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> --- .flowconfig | 2 +- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.flowconfig b/.flowconfig index 5f8e969f2bd..522d3c0d306 100644 --- a/.flowconfig +++ b/.flowconfig @@ -36,4 +36,4 @@ untyped-import untyped-type-import [version] -0.158.0 +0.160.1 diff --git a/package.json b/package.json index e2e43da8ed5..892dab33b71 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "cross-env": "^7.0.0", "doctoc": "^1.4.0", "eslint": "^7.20.0", - "flow-bin": "0.158.0", + "flow-bin": "0.160.1", "glob": "^7.1.6", "gulp": "^4.0.2", "gulp-babel": "^8.0.0", diff --git a/yarn.lock b/yarn.lock index a38503cc958..c4176549c41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6090,10 +6090,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== -flow-bin@0.158.0: - version "0.158.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.158.0.tgz#0a09763d41eb8ec7135ced6a3b9f8fa370a393d8" - integrity sha512-Gk5md8XTwk/M+J5M+rFyS1LJfFen6ldY60jM9+meWixlKf4b0vwdoUO8R7oo471pze+GY+blrnskUeqLDxFJfg== +flow-bin@0.160.1: + version "0.160.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.160.1.tgz#ae24ad6def1f05ae37789b6cc332b58975d29de0" + integrity sha512-LvQ9lB/vwW+lPjYIyACcGQCSLvL9f9hOM9jJJtfHQRrIgIShWqjvyv5V24M57HSxh0+6dBbVDYhUiZjjeArf7A== flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: version "1.1.1"