diff --git a/packages/core/core/src/requests/PathRequest.js b/packages/core/core/src/requests/PathRequest.js index 347fbe12468..6bb95cc21be 100644 --- a/packages/core/core/src/requests/PathRequest.js +++ b/packages/core/core/src/requests/PathRequest.js @@ -67,6 +67,12 @@ async function run({input, api, options}: RunOpts) { }); let result: ResolverResult = await resolverRunner.resolve(input.dependency); + if (result.invalidateOnEnvChange) { + for (let env of result.invalidateOnEnvChange) { + api.invalidateOnEnvChange(env); + } + } + if (result.invalidateOnFileCreate) { for (let file of result.invalidateOnFileCreate) { api.invalidateOnFileCreate( @@ -105,6 +111,7 @@ type ResolverResult = {| assetGroup: ?AssetGroup, invalidateOnFileCreate?: Array, invalidateOnFileChange?: Array, + invalidateOnEnvChange?: Array, diagnostics?: Array, |}; @@ -185,6 +192,7 @@ export class ResolverRunner { let diagnostics: Array = []; let invalidateOnFileCreate = []; let invalidateOnFileChange = []; + let invalidateOnEnvChange = []; for (let resolver of resolvers) { try { let result = await resolver.plugin.resolve({ @@ -208,6 +216,10 @@ export class ResolverRunner { dependency.priority = Priority[result.priority]; } + if (result.invalidateOnEnvChange) { + invalidateOnEnvChange.push(...result.invalidateOnEnvChange); + } + if (result.invalidateOnFileCreate) { invalidateOnFileCreate.push(...result.invalidateOnFileCreate); } @@ -221,6 +233,7 @@ export class ResolverRunner { assetGroup: null, invalidateOnFileCreate, invalidateOnFileChange, + invalidateOnEnvChange, }; } @@ -251,6 +264,7 @@ export class ResolverRunner { }, invalidateOnFileCreate, invalidateOnFileChange, + invalidateOnEnvChange, }; } @@ -286,6 +300,7 @@ export class ResolverRunner { assetGroup: null, invalidateOnFileCreate, invalidateOnFileChange, + invalidateOnEnvChange, }; } @@ -308,6 +323,7 @@ export class ResolverRunner { assetGroup: null, invalidateOnFileCreate, invalidateOnFileChange, + invalidateOnEnvChange, diagnostics, }; } diff --git a/packages/core/integration-tests/test/integration/env-unused-require/index.js b/packages/core/integration-tests/test/integration/env-unused-require/index.js new file mode 100644 index 00000000000..1c84632ac0c --- /dev/null +++ b/packages/core/integration-tests/test/integration/env-unused-require/index.js @@ -0,0 +1,7 @@ +module.exports = function () { + if(process.env.ABC === 'a') { + return require("./unused.js"); + } else { + return "ok"; + } +}; diff --git a/packages/core/integration-tests/test/integration/env-unused-require/unused.js b/packages/core/integration-tests/test/integration/env-unused-require/unused.js new file mode 100644 index 00000000000..266db37eae0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/env-unused-require/unused.js @@ -0,0 +1 @@ +module.exports = "unused"; diff --git a/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/.parcelrc b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/.parcelrc new file mode 100644 index 00000000000..6e7fa4a9bde --- /dev/null +++ b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/.parcelrc @@ -0,0 +1,4 @@ +{ + "extends": "@parcel/config-default", + "resolvers": ["parcel-resolver-can-invalidateonenvchange"] +} diff --git a/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/index.js b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/index.js new file mode 100644 index 00000000000..69b7c3258ab --- /dev/null +++ b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/index.js @@ -0,0 +1 @@ +const willBeReplaced = true; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/node_modules/parcel-resolver-can-invalidateonenvchange/index.js b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/node_modules/parcel-resolver-can-invalidateonenvchange/index.js new file mode 100644 index 00000000000..ade8fcd2fd7 --- /dev/null +++ b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/node_modules/parcel-resolver-can-invalidateonenvchange/index.js @@ -0,0 +1,27 @@ +// @flow + +const {Resolver} = require('@parcel/plugin'); +const path = require('path'); +const {default: NodeResolver} = require('@parcel/node-resolver-core'); + +module.exports = new Resolver({ + async resolve({dependency, options, specifier,logger}) { + let mainFields = ['source', 'browser', 'module', 'main']; + const replacedCode = options.env.replacedCode; + const resolver = new NodeResolver({ + fs: options.inputFS, + projectRoot: options.projectRoot, + extensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'css', 'styl', 'vue'], + mainFields, + }); + let result = await resolver.resolve({ + filename: specifier, + specifierType: dependency.specifierType, + parent: dependency.sourcePath, + env: dependency.env, + }); + result.code = replacedCode; + result.invalidateOnEnvChange = ['replacedCode']; + return result; + }, +}); diff --git a/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/node_modules/parcel-resolver-can-invalidateonenvchange/package.json b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/node_modules/parcel-resolver-can-invalidateonenvchange/package.json new file mode 100644 index 00000000000..005c6096b8f --- /dev/null +++ b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/node_modules/parcel-resolver-can-invalidateonenvchange/package.json @@ -0,0 +1,7 @@ +{ + "name": "parcel-resolver-can-invalidateonenvchange", + "version": "1.0.0", + "private": true, + "main": "index.js" + } + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/package.json b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/package.json new file mode 100644 index 00000000000..65d2634be87 --- /dev/null +++ b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/package.json @@ -0,0 +1,4 @@ +{ + "name": "test-resolver-invalidateonenevchange", + "private": true +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/yarn.lock b/packages/core/integration-tests/test/integration/resolver-can-invalidateonenvchange/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/a.js b/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/a.js new file mode 100644 index 00000000000..5e60fdbb15c --- /dev/null +++ b/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/a.js @@ -0,0 +1,3 @@ +const v = require("./b.js"); + +output = v; diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/b.js b/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/b.js new file mode 100644 index 00000000000..1e38fdcafe2 --- /dev/null +++ b/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/b.js @@ -0,0 +1,7 @@ +const value = require("./c.js"); + +const obj = { + value, +}; + +exports = module.exports = obj.value; diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/c.js b/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/c.js new file mode 100644 index 00000000000..3481de8569a --- /dev/null +++ b/packages/core/integration-tests/test/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/c.js @@ -0,0 +1 @@ +module.exports = 1234; diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index 66b87c020d0..d4c887a82fe 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -347,6 +347,28 @@ describe('javascript', function () { assert(!contents.includes('import')); }); + it('should ignore unused requires after process.env inlining', async function () { + let b = await bundle( + path.join(__dirname, '/integration/env-unused-require/index.js'), + { + env: {ABC: 'XYZ'}, + }, + ); + + assertBundles(b, [ + { + type: 'js', + assets: ['index.js'], + }, + ]); + + let contents = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); + assert(!contents.includes('unused')); + + let output = await run(b); + assert.strictEqual(output(), 'ok'); + }); + it('should produce a basic JS bundle with object rest spread support', async function () { let b = await bundle( path.join( diff --git a/packages/core/integration-tests/test/plugin.js b/packages/core/integration-tests/test/plugin.js index 26256535e64..5b86ca5fbe9 100644 --- a/packages/core/integration-tests/test/plugin.js +++ b/packages/core/integration-tests/test/plugin.js @@ -190,4 +190,24 @@ parcel-transformer-b`, assert.equal(await run(b), 2); }); + + it('should allow resolvers to invalidateOnEnvChange', async () => { + async function assertAsset(replacedCode) { + let b = await bundle( + path.join( + __dirname, + '/integration/resolver-can-invalidateonenvchange/index.js', + ), + { + shouldDisableCache: false, + inputFS: overlayFS, + env: {replacedCode}, + }, + ); + let code = await b.getBundles()[0].getEntryAssets()[0].getCode(); + assert(code.indexOf(replacedCode) !== -1); + } + await assertAsset('const replaced = 1;'); + await assertAsset('const replaced = 2;'); + }); }); diff --git a/packages/core/integration-tests/test/scope-hoisting.js b/packages/core/integration-tests/test/scope-hoisting.js index f9b2fe8a6ef..2ba42550169 100644 --- a/packages/core/integration-tests/test/scope-hoisting.js +++ b/packages/core/integration-tests/test/scope-hoisting.js @@ -3709,8 +3709,6 @@ describe('scope hoisting', function () { ), ); - // console.log(await outputFS.readFile(b.getBundles()[0].filePath, 'utf8')); - let output = await run(b); assert.equal(output, 1); }); @@ -3775,6 +3773,18 @@ describe('scope hoisting', function () { assert.deepEqual(output, {foo: 2}); }); + it('should support referencing a require in object literal shorthands when wrapped', async function () { + let b = await bundle( + path.join( + __dirname, + '/integration/scope-hoisting/commonjs/wrap-module-obj-literal-require/a.js', + ), + ); + + let output = await run(b); + assert.strictEqual(output, 1234); + }); + it('should support typeof require when wrapped', async function () { // https://github.com/parcel-bundler/parcel/issues/5883 let b = await bundle( diff --git a/packages/core/types/index.js b/packages/core/types/index.js index 24eec5812ce..d665a9c3941 100644 --- a/packages/core/types/index.js +++ b/packages/core/types/index.js @@ -1502,6 +1502,8 @@ export type ResolveResult = {| +invalidateOnFileCreate?: Array, /** A list of files that should invalidate the resolution if modified or deleted. */ +invalidateOnFileChange?: Array, + /** Invalidates the resolution when the given environment variable changes.*/ + +invalidateOnEnvChange?: Array, |}; /** diff --git a/packages/optimizers/image/package.json b/packages/optimizers/image/package.json index 882a546888d..50623eb3a23 100644 --- a/packages/optimizers/image/package.json +++ b/packages/optimizers/image/package.json @@ -37,7 +37,7 @@ "@parcel/utils": "2.0.30", "@parcel/workers": "2.0.30", "detect-libc": "^1.0.3", - "self-published": "npm:@parcel/optimizer-image@2.6.1-nightly.2733" + "self-published": "npm:@parcel/optimizer-image@2.6.1-nightly.2736" }, "devDependencies": { "@napi-rs/cli": "^2.6.2", diff --git a/packages/transformers/js/core/src/decl_collector.rs b/packages/transformers/js/core/src/decl_collector.rs index 9201f11f78a..8bc321dc249 100644 --- a/packages/transformers/js/core/src/decl_collector.rs +++ b/packages/transformers/js/core/src/decl_collector.rs @@ -1,14 +1,12 @@ use std::collections::HashSet; -use swc_atoms::JsWord; -use swc_common::SyntaxContext; -use swc_ecmascript::ast; +use swc_ecmascript::ast::{self, Id}; use swc_ecmascript::visit::{Visit, VisitWith}; /// This pass collects all declarations in a module into a single HashSet of tuples /// containing identifier names and their associated syntax context (scope). /// This is used later to determine whether an identifier references a declared variable. -pub fn collect_decls(module: &ast::Module) -> HashSet<(JsWord, SyntaxContext)> { +pub fn collect_decls(module: &ast::Module) -> HashSet { let mut c = DeclCollector { decls: HashSet::new(), in_var: false, @@ -18,7 +16,7 @@ pub fn collect_decls(module: &ast::Module) -> HashSet<(JsWord, SyntaxContext)> { } struct DeclCollector { - decls: HashSet<(JsWord, SyntaxContext)>, + decls: HashSet, in_var: bool, } diff --git a/packages/transformers/js/core/src/dependency_collector.rs b/packages/transformers/js/core/src/dependency_collector.rs index b1d83f65650..9f9bd07deea 100644 --- a/packages/transformers/js/core/src/dependency_collector.rs +++ b/packages/transformers/js/core/src/dependency_collector.rs @@ -5,8 +5,8 @@ use std::path::Path; use serde::{Deserialize, Serialize}; use swc_atoms::JsWord; -use swc_common::{Mark, SourceMap, Span, SyntaxContext, DUMMY_SP}; -use swc_ecmascript::ast::{self, Callee, MemberProp}; +use swc_common::{Mark, SourceMap, Span, DUMMY_SP}; +use swc_ecmascript::ast::{self, Callee, Id, MemberProp}; use swc_ecmascript::visit::{Fold, FoldWith}; use crate::fold_member_expr_skip_prop; @@ -59,8 +59,9 @@ pub struct DependencyDescriptor { pub fn dependency_collector<'a>( source_map: &'a SourceMap, items: &'a mut Vec, - decls: &'a HashSet<(JsWord, SyntaxContext)>, + decls: &'a HashSet, ignore_mark: swc_common::Mark, + unresolved_mark: swc_common::Mark, config: &'a Config, diagnostics: &'a mut Vec, ) -> impl Fold + 'a { @@ -72,6 +73,7 @@ pub fn dependency_collector<'a>( require_node: None, decls, ignore_mark, + unresolved_mark, config, diagnostics, import_meta: None, @@ -84,8 +86,9 @@ struct DependencyCollector<'a> { in_try: bool, in_promise: bool, require_node: Option, - decls: &'a HashSet<(JsWord, SyntaxContext)>, + decls: &'a HashSet, ignore_mark: swc_common::Mark, + unresolved_mark: swc_common::Mark, config: &'a Config, diagnostics: &'a mut Vec, import_meta: Option, @@ -828,7 +831,7 @@ impl<'a> Fold for DependencyCollector<'a> { }; if is_require { - return ast::Expr::Ident(ast::Ident::new("undefined".into(), DUMMY_SP)); + return ast::Expr::Ident(get_undefined_ident(self.unresolved_mark)); } node.fold_children_with(self) @@ -1096,7 +1099,7 @@ impl<'a> DependencyCollector<'a> { fn match_new_url( &mut self, expr: &ast::Expr, - decls: &HashSet<(JsWord, SyntaxContext)>, + decls: &HashSet, ) -> Option<(JsWord, swc_common::Span)> { use ast::*; @@ -1139,6 +1142,7 @@ impl<'a> DependencyCollector<'a> { None } + #[allow(clippy::wrong_self_convention)] fn is_import_meta_url(&mut self, expr: &ast::Expr) -> bool { use ast::*; @@ -1175,6 +1179,7 @@ impl<'a> DependencyCollector<'a> { } } + #[allow(clippy::wrong_self_convention)] fn is_import_meta(&mut self, expr: &ast::Expr) -> bool { use ast::*; diff --git a/packages/transformers/js/core/src/env_replacer.rs b/packages/transformers/js/core/src/env_replacer.rs index 421370248ab..78ba22ba49e 100644 --- a/packages/transformers/js/core/src/env_replacer.rs +++ b/packages/transformers/js/core/src/env_replacer.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use std::vec; use swc_atoms::JsWord; -use swc_common::{SyntaxContext, DUMMY_SP}; +use swc_common::{Mark, DUMMY_SP}; use swc_ecmascript::ast; use swc_ecmascript::visit::{Fold, FoldWith}; @@ -13,10 +13,11 @@ pub struct EnvReplacer<'a> { pub replace_env: bool, pub is_browser: bool, pub env: &'a HashMap, - pub decls: &'a HashSet<(JsWord, SyntaxContext)>, + pub decls: &'a HashSet, pub used_env: &'a mut HashSet, pub source_map: &'a swc_common::SourceMap, pub diagnostics: &'a mut Vec, + pub unresolved_mark: Mark, } impl<'a> Fold for EnvReplacer<'a> { @@ -105,7 +106,7 @@ impl<'a> Fold for EnvReplacer<'a> { right: Box::new(if let Some(init) = &decl.init { *init.clone() } else { - Expr::Ident(Ident::new(js_word!("undefined"), DUMMY_SP)) + Expr::Ident(get_undefined_ident(self.unresolved_mark)) }), })) }) @@ -214,7 +215,7 @@ impl<'a> EnvReplacer<'a> { | "valueOf" => {} _ => { self.used_env.insert(sym.clone()); - return Some(Expr::Ident(Ident::new(js_word!("undefined"), DUMMY_SP))); + return Some(Expr::Ident(get_undefined_ident(self.unresolved_mark))); } }; } diff --git a/packages/transformers/js/core/src/fs.rs b/packages/transformers/js/core/src/fs.rs index 1c8816ba91d..3b97b9ece52 100644 --- a/packages/transformers/js/core/src/fs.rs +++ b/packages/transformers/js/core/src/fs.rs @@ -1,7 +1,7 @@ use crate::dependency_collector::{DependencyDescriptor, DependencyKind}; use crate::hoist::{Collect, Import}; use crate::id; -use crate::utils::{IdentId, SourceLocation}; +use crate::utils::SourceLocation; use data_encoding::{BASE64, HEXLOWER}; use std::collections::HashSet; use std::path::{Path, PathBuf}; @@ -13,7 +13,7 @@ use swc_ecmascript::visit::{Fold, FoldWith, VisitWith}; pub fn inline_fs<'a>( filename: &str, source_map: swc_common::sync::Lrc, - decls: HashSet, + decls: HashSet, global_mark: Mark, project_root: &'a str, deps: &'a mut Vec, diff --git a/packages/transformers/js/core/src/global_replacer.rs b/packages/transformers/js/core/src/global_replacer.rs index f2c5417e5f2..e249e6da2ba 100644 --- a/packages/transformers/js/core/src/global_replacer.rs +++ b/packages/transformers/js/core/src/global_replacer.rs @@ -4,7 +4,7 @@ use std::path::Path; use swc_atoms::JsWord; use swc_common::{Mark, SourceMap, SyntaxContext, DUMMY_SP}; -use swc_ecmascript::ast::{self, ComputedPropName}; +use swc_ecmascript::ast::{self, ComputedPropName, Id}; use swc_ecmascript::visit::{Fold, FoldWith}; use crate::dependency_collector::{DependencyDescriptor, DependencyKind}; @@ -17,7 +17,7 @@ pub struct GlobalReplacer<'a> { pub globals: HashMap, pub project_root: &'a Path, pub filename: &'a Path, - pub decls: &'a mut HashSet<(JsWord, SyntaxContext)>, + pub decls: &'a mut HashSet, pub scope_hoist: bool, } diff --git a/packages/transformers/js/core/src/hoist.rs b/packages/transformers/js/core/src/hoist.rs index af55e1b3e61..d29c6e1bf7f 100644 --- a/packages/transformers/js/core/src/hoist.rs +++ b/packages/transformers/js/core/src/hoist.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_export_name, match_export_name_ident, match_property_name}; +use crate::utils::{ + get_undefined_ident, match_export_name, match_export_name_ident, match_property_name, +}; use serde::{Deserialize, Serialize}; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; @@ -11,7 +13,7 @@ use swc_ecmascript::visit::{Fold, FoldWith, Visit, VisitWith}; use crate::id; use crate::utils::{ match_import, match_member_expr, match_require, Bailout, BailoutReason, CodeHighlight, - Diagnostic, DiagnosticSeverity, IdentId, SourceLocation, + Diagnostic, DiagnosticSeverity, SourceLocation, }; macro_rules! hash { @@ -25,9 +27,10 @@ macro_rules! hash { pub fn hoist( module: Module, module_id: &str, + unresolved_mark: Mark, collect: &Collect, ) -> Result<(Module, HoistResult, Vec), Vec> { - let mut hoist = Hoist::new(module_id, collect); + let mut hoist = Hoist::new(module_id, unresolved_mark, collect); let module = module.fold_with(&mut hoist); if !hoist.diagnostics.is_empty() { @@ -66,6 +69,7 @@ struct Hoist<'a> { dynamic_imports: HashMap, in_function_scope: bool, diagnostics: Vec, + unresolved_mark: Mark, } #[derive(Debug, Default, Serialize, Deserialize)] @@ -83,7 +87,7 @@ pub struct HoistResult { } impl<'a> Hoist<'a> { - fn new(module_id: &'a str, collect: &'a Collect) -> Self { + fn new(module_id: &'a str, unresolved_mark: Mark, collect: &'a Collect) -> Self { Hoist { module_id, collect, @@ -97,6 +101,7 @@ impl<'a> Hoist<'a> { dynamic_imports: HashMap::new(), in_function_scope: false, diagnostics: vec![], + unresolved_mark, } } @@ -672,7 +677,7 @@ impl<'a> Fold for Hoist<'a> { if !self.in_function_scope { // If ESM, replace `this` with `undefined`, otherwise with the CJS exports object. if self.collect.is_esm { - return Expr::Ident(Ident::new("undefined".into(), DUMMY_SP)); + return Expr::Ident(get_undefined_ident(self.unresolved_mark)); } else if !self.collect.should_wrap { self.self_references.insert("*".into()); return Expr::Ident(self.get_export_ident(this.span, &"*".into())); @@ -909,10 +914,6 @@ impl<'a> Fold for Hoist<'a> { } fn fold_prop(&mut self, node: Prop) -> Prop { - if self.collect.should_wrap { - return node.fold_children_with(self); - } - match node { Prop::Shorthand(ident) => Prop::KeyValue(KeyValueProp { key: PropName::Ident(Ident::new(ident.sym.clone(), DUMMY_SP)), @@ -1097,7 +1098,7 @@ pub struct Export { pub struct Collect { pub source_map: Lrc, - pub decls: HashSet, + pub decls: HashSet, pub ignore_mark: Mark, pub global_mark: Mark, pub static_cjs_exports: bool, @@ -1105,14 +1106,14 @@ pub struct Collect { pub is_esm: bool, pub should_wrap: bool, // local name -> descriptor - pub imports: HashMap, + pub imports: HashMap, // exported name -> descriptor pub exports: HashMap, // local name -> exported name - pub exports_locals: HashMap, + pub exports_locals: HashMap, pub exports_all: HashMap, - pub non_static_access: HashMap>, - pub non_const_bindings: HashMap>, + pub non_static_access: HashMap>, + pub non_const_bindings: HashMap>, pub non_static_requires: HashSet, pub wrapped_requires: HashSet, pub bailouts: Option>, @@ -1156,7 +1157,7 @@ pub struct CollectResult { impl Collect { pub fn new( source_map: Lrc, - decls: HashSet, + decls: HashSet, ignore_mark: Mark, global_mark: Mark, trace_bailouts: bool, @@ -2067,7 +2068,7 @@ impl Collect { } } -fn has_binding_identifier(node: &Pat, sym: &JsWord, decls: &HashSet) -> bool { +fn has_binding_identifier(node: &Pat, sym: &JsWord, decls: &HashSet) -> bool { match node { Pat::Ident(ident) => { if ident.id.sym == *sym && !decls.contains(&id!(ident.id)) { @@ -2155,7 +2156,7 @@ mod tests { module.visit_with(&mut collect); let (module, res) = { - let mut hoist = Hoist::new("abc", &collect); + let mut hoist = Hoist::new("abc", unresolved_mark, &collect); let module = module.fold_with(&mut hoist); (module, hoist.get_result()) }; diff --git a/packages/transformers/js/core/src/lib.rs b/packages/transformers/js/core/src/lib.rs index 0c16aa3cf13..945d5069041 100644 --- a/packages/transformers/js/core/src/lib.rs +++ b/packages/transformers/js/core/src/lib.rs @@ -310,7 +310,8 @@ pub fn transform(config: Config) -> Result { decls: &decls, used_env: &mut result.used_env, source_map: &source_map, - diagnostics: &mut diagnostics + diagnostics: &mut diagnostics, + unresolved_mark }, config.source_type != SourceType::Script ), @@ -388,7 +389,7 @@ pub fn transform(config: Config) -> Result { module.fold_with(&mut passes) }; - // Flush (JsWord, SyntaxContexts) into unique names and reresolve to + // Flush Id=(JsWord, SyntaxContexts) into unique names and reresolve to // set global_mark for all nodes, even generated ones. // - This changes the syntax context ids and therefore invalidates decls // - This will also remove any other other marks (like ignore_mark) @@ -412,6 +413,7 @@ pub fn transform(config: Config) -> Result { &mut result.dependencies, &decls, ignore_mark, + unresolved_mark, &config, &mut diagnostics, ), @@ -440,7 +442,7 @@ pub fn transform(config: Config) -> Result { } let module = if config.scope_hoist { - let res = hoist(module, config.module_id.as_str(), &collect); + let res = hoist(module, config.module_id.as_str(), unresolved_mark, &collect); match res { Ok((module, hoist_result, hoist_diagnostics)) => { result.hoist_result = Some(hoist_result); @@ -458,7 +460,7 @@ pub fn transform(config: Config) -> Result { result.symbol_result = Some(collect.into()); } - let (module, needs_helpers) = esm2cjs(module, versions); + let (module, needs_helpers) = esm2cjs(module, unresolved_mark, versions); result.needs_esm_helpers = needs_helpers; module }; diff --git a/packages/transformers/js/core/src/modules.rs b/packages/transformers/js/core/src/modules.rs index 27620202b49..ad38d5c783d 100644 --- a/packages/transformers/js/core/src/modules.rs +++ b/packages/transformers/js/core/src/modules.rs @@ -1,5 +1,5 @@ use crate::id; -use crate::utils::{match_export_name, match_export_name_ident, IdentId}; +use crate::utils::{get_undefined_ident, match_export_name, match_export_name_ident}; use inflector::Inflector; use std::collections::{HashMap, HashSet}; use swc_atoms::JsWord; @@ -10,7 +10,7 @@ use swc_ecmascript::visit::{Fold, FoldWith}; use crate::fold_member_expr_skip_prop; -pub fn esm2cjs(node: Module, versions: Option) -> (Module, bool) { +pub fn esm2cjs(node: Module, unresolved_mark: Mark, versions: Option) -> (Module, bool) { let mut fold = ESMFold { imports: HashMap::new(), require_names: HashMap::new(), @@ -21,6 +21,7 @@ pub fn esm2cjs(node: Module, versions: Option) -> (Module, bool) { in_export_decl: false, in_function_scope: false, mark: Mark::fresh(Mark::root()), + unresolved_mark, versions, }; @@ -30,7 +31,7 @@ pub fn esm2cjs(node: Module, versions: Option) -> (Module, bool) { struct ESMFold { // Map of imported identifier to (source, specifier) - imports: HashMap, + imports: HashMap, // Map of source to (require identifier, mark) require_names: HashMap, // Set of declared default interops, by source. @@ -43,6 +44,7 @@ struct ESMFold { in_export_decl: bool, in_function_scope: bool, mark: Mark, + unresolved_mark: Mark, versions: Option, } @@ -590,7 +592,7 @@ impl Fold for ESMFold { } Expr::This(_this) => { if !self.in_function_scope { - Expr::Ident(Ident::new(js_word!("undefined"), DUMMY_SP)) + Expr::Ident(get_undefined_ident(self.unresolved_mark)) } else { node } diff --git a/packages/transformers/js/core/src/node_replacer.rs b/packages/transformers/js/core/src/node_replacer.rs index 4055805f194..6c82d5af913 100644 --- a/packages/transformers/js/core/src/node_replacer.rs +++ b/packages/transformers/js/core/src/node_replacer.rs @@ -4,7 +4,7 @@ use std::path::Path; use swc_atoms::JsWord; use swc_common::{Mark, SourceMap, SyntaxContext, DUMMY_SP}; -use swc_ecmascript::ast::{self}; +use swc_ecmascript::ast::{self, Id}; use swc_ecmascript::visit::{Fold, FoldWith}; use crate::dependency_collector::{DependencyDescriptor, DependencyKind}; @@ -17,7 +17,7 @@ pub struct NodeReplacer<'a> { pub globals: HashMap, pub project_root: &'a Path, pub filename: &'a Path, - pub decls: &'a mut HashSet<(JsWord, SyntaxContext)>, + pub decls: &'a mut HashSet, pub scope_hoist: bool, pub has_node_replacements: &'a mut bool, } diff --git a/packages/transformers/js/core/src/typeof_replacer.rs b/packages/transformers/js/core/src/typeof_replacer.rs index b3ac418cb49..75c11840640 100644 --- a/packages/transformers/js/core/src/typeof_replacer.rs +++ b/packages/transformers/js/core/src/typeof_replacer.rs @@ -1,14 +1,13 @@ use std::collections::HashSet; use swc_atoms::js_word; -use swc_ecmascript::ast::{Expr, Lit, Str, UnaryOp}; +use swc_ecmascript::ast::{Expr, Id, Lit, Str, UnaryOp}; use swc_ecmascript::visit::{Fold, FoldWith}; use crate::id; -use crate::utils::IdentId; pub struct TypeofReplacer<'a> { - pub decls: &'a HashSet, + pub decls: &'a HashSet, } impl<'a> Fold for TypeofReplacer<'a> { diff --git a/packages/transformers/js/core/src/utils.rs b/packages/transformers/js/core/src/utils.rs index 8d65d20f3e9..4827a2db502 100644 --- a/packages/transformers/js/core/src/utils.rs +++ b/packages/transformers/js/core/src/utils.rs @@ -1,16 +1,13 @@ use std::cmp::Ordering; use std::collections::HashSet; +use crate::id; use serde::{Deserialize, Serialize}; use swc_atoms::JsWord; use swc_common::{Mark, Span, SyntaxContext, DUMMY_SP}; -use swc_ecmascript::ast; +use swc_ecmascript::ast::{self, Id}; -pub fn match_member_expr( - expr: &ast::MemberExpr, - idents: Vec<&str>, - decls: &HashSet<(JsWord, SyntaxContext)>, -) -> bool { +pub fn match_member_expr(expr: &ast::MemberExpr, idents: Vec<&str>, decls: &HashSet) -> bool { use ast::{Expr, Ident, Lit, MemberProp, Str}; let mut member = expr; @@ -35,10 +32,8 @@ pub fn match_member_expr( match &*member.obj { Expr::Member(m) => member = m, - Expr::Ident(Ident { ref sym, span, .. }) => { - return idents.len() == 1 - && sym == idents.pop().unwrap() - && !decls.contains(&(sym.clone(), span.ctxt())); + Expr::Ident(id) => { + return idents.len() == 1 && &id.sym == idents.pop().unwrap() && !decls.contains(&id!(id)); } _ => return false, } @@ -119,11 +114,7 @@ pub fn match_export_name_ident(name: &ast::ModuleExportName) -> &ast::Ident { } } -pub fn match_require( - node: &ast::Expr, - decls: &HashSet<(JsWord, SyntaxContext)>, - ignore_mark: Mark, -) -> Option { +pub fn match_require(node: &ast::Expr, decls: &HashSet, ignore_mark: Mark) -> Option { use ast::*; match node { @@ -201,6 +192,10 @@ pub fn create_global_decl_stmt( ) } +pub fn get_undefined_ident(unresolved_mark: Mark) -> ast::Ident { + ast::Ident::new(js_word!("undefined"), DUMMY_SP.apply_mark(unresolved_mark)) +} + #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct SourceLocation { pub start_line: usize, @@ -385,8 +380,6 @@ macro_rules! fold_member_expr_skip_prop { #[macro_export] macro_rules! id { ($ident: expr) => { - ($ident.sym.clone(), $ident.span.ctxt) + $ident.to_id() }; } - -pub type IdentId = (JsWord, SyntaxContext); diff --git a/packages/transformers/js/package.json b/packages/transformers/js/package.json index 7f8d950b6af..4d250877168 100644 --- a/packages/transformers/js/package.json +++ b/packages/transformers/js/package.json @@ -40,7 +40,7 @@ "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", - "self-published": "npm:@parcel/transformer-js@2.0.0-nightly.1110", + "self-published": "npm:@parcel/transformer-js@2.0.0-nightly.1113", "semver": "^5.7.1" }, "devDependencies": { diff --git a/packages/utils/fs-search/package.json b/packages/utils/fs-search/package.json index 33427e9af4d..b9fbc3154ba 100644 --- a/packages/utils/fs-search/package.json +++ b/packages/utils/fs-search/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "detect-libc": "^1.0.3", - "self-published": "npm:@parcel/fs-search@2.6.1-nightly.2733" + "self-published": "npm:@parcel/fs-search@2.6.1-nightly.2736" }, "devDependencies": { "@napi-rs/cli": "^2.6.2" diff --git a/packages/utils/hash/package.json b/packages/utils/hash/package.json index 014c8f55ee7..db4aeecec64 100644 --- a/packages/utils/hash/package.json +++ b/packages/utils/hash/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "detect-libc": "^1.0.3", - "self-published": "npm:@parcel/hash@2.6.1-nightly.2733", + "self-published": "npm:@parcel/hash@2.6.1-nightly.2736", "xxhash-wasm": "^0.4.2" }, "devDependencies": {