mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +03:00
fix(es/module): Support top-level await in dynamic imports (#4277)
This commit is contained in:
parent
9feabcd145
commit
720244fff9
@ -6,8 +6,8 @@ exports.getPackage = getPackage;
|
||||
var swcHelpers = require("@swc/helpers");
|
||||
var _path = require("path");
|
||||
async function getPackage() {
|
||||
const pkg = await Promise.resolve().then(function() {
|
||||
return swcHelpers.interopRequireWildcard(require((0, _path).join(process.cwd(), 'package.json')));
|
||||
const pkg = await Promise.resolve(`${(0, _path).join(process.cwd(), 'package.json')}`).then(function(s) {
|
||||
return swcHelpers.interopRequireWildcard(require(s));
|
||||
});
|
||||
return pkg.default || pkg;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ exports.getPackage = getPackage;
|
||||
var swcHelpers = require("@swc/helpers");
|
||||
var _path = require("path");
|
||||
async function getPackage() {
|
||||
const pkg = await Promise.resolve().then(function() {
|
||||
return swcHelpers.interopRequireWildcard(require((0, _path).join(process.cwd(), 'package.json')));
|
||||
const pkg = await Promise.resolve(`${(0, _path).join(process.cwd(), 'package.json')}`).then(function(s) {
|
||||
return swcHelpers.interopRequireWildcard(require(s));
|
||||
});
|
||||
return pkg.default || pkg;
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ use anyhow::{bail, Error};
|
||||
use swc_atoms::js_word;
|
||||
use swc_common::{SyntaxContext, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{find_ids, private_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, Visit};
|
||||
use swc_ecma_utils::{contains_top_level_await, find_ids, private_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_fold_type, Fold};
|
||||
|
||||
use crate::{bundler::chunk::merge::Ctx, modules::Modules, Bundler, Load, ModuleId, Resolve};
|
||||
|
||||
@ -43,11 +43,7 @@ where
|
||||
};
|
||||
let injected_ctxt = self.injected_ctxt;
|
||||
|
||||
let is_async = {
|
||||
let mut v = TopLevelAwaitFinder { found: false };
|
||||
module.visit_with(&mut v);
|
||||
v.found
|
||||
};
|
||||
let is_async = module.iter().any(|m| contains_top_level_await(m.1));
|
||||
|
||||
let mut additional_items = vec![];
|
||||
|
||||
@ -182,24 +178,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct TopLevelAwaitFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl Visit for TopLevelAwaitFinder {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_function(&mut self, _: &Function) {}
|
||||
|
||||
fn visit_arrow_expr(&mut self, _: &ArrowExpr) {}
|
||||
|
||||
fn visit_class_member(&mut self, _: &ClassMember) {}
|
||||
|
||||
fn visit_await_expr(&mut self, _: &AwaitExpr) {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct ExportToReturn {
|
||||
return_props: Vec<PropOrSpread>,
|
||||
synthesized_ctxt: SyntaxContext,
|
||||
|
@ -11,8 +11,8 @@ use swc_ecma_transforms_base::{
|
||||
helpers::{inject_helpers, HELPERS},
|
||||
hygiene::hygiene,
|
||||
};
|
||||
use swc_ecma_utils::{find_ids, private_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Visit, VisitWith};
|
||||
use swc_ecma_utils::{contains_top_level_await, find_ids, private_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
|
||||
use crate::{hash::calc_hash, Bundle, BundleKind, Bundler, Load, ModuleType, Resolve};
|
||||
|
||||
@ -148,10 +148,7 @@ where
|
||||
return module;
|
||||
}
|
||||
|
||||
let mut top_level_await_finder = TopLevelAwaitFinder::default();
|
||||
module.visit_with(&mut top_level_await_finder);
|
||||
|
||||
let is_async = top_level_await_finder.found;
|
||||
let is_async = contains_top_level_await(&module);
|
||||
|
||||
// Properties of returned object
|
||||
let mut props = vec![];
|
||||
@ -365,21 +362,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TopLevelAwaitFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl Visit for TopLevelAwaitFinder {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_stmts(&mut self, _: &[Stmt]) {}
|
||||
|
||||
fn visit_await_expr(&mut self, _: &AwaitExpr) {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Import renamer. This pass changes import path.
|
||||
struct Renamer<'a, R>
|
||||
where
|
||||
|
@ -1062,13 +1062,55 @@ impl ModulePass for CommonJs {
|
||||
/// ```
|
||||
pub(super) fn handle_dynamic_import(
|
||||
span: Span,
|
||||
args: Vec<ExprOrSpread>,
|
||||
mut args: Vec<ExprOrSpread>,
|
||||
es_module_interop: bool,
|
||||
) -> Expr {
|
||||
// there's a evalution order problem here
|
||||
let (resolve_arg, then_arg, require_arg) = if let Expr::Lit(Lit::Str(_)) = &*args[0].expr {
|
||||
(Vec::new(), Vec::new(), args)
|
||||
} else {
|
||||
let arg = private_ident!("s");
|
||||
let rest = args.split_off(1);
|
||||
let import = args.into_iter().next().unwrap();
|
||||
(
|
||||
vec![ExprOrSpread {
|
||||
spread: None,
|
||||
expr: if import.expr.is_tpl() {
|
||||
import.expr
|
||||
} else {
|
||||
Box::new(Expr::Tpl(Tpl {
|
||||
span: DUMMY_SP,
|
||||
exprs: vec![import.expr],
|
||||
quasis: vec![
|
||||
TplElement {
|
||||
span: DUMMY_SP,
|
||||
tail: true,
|
||||
cooked: None,
|
||||
raw: "".into(),
|
||||
},
|
||||
TplElement {
|
||||
span: DUMMY_SP,
|
||||
tail: true,
|
||||
cooked: None,
|
||||
raw: "".into(),
|
||||
},
|
||||
],
|
||||
}))
|
||||
},
|
||||
}],
|
||||
vec![arg.clone().into()],
|
||||
{
|
||||
let mut require_arg = vec![arg.as_arg()];
|
||||
require_arg.extend(rest);
|
||||
require_arg
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
let resolve_call = CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: member_expr!(DUMMY_SP, Promise.resolve).as_callee(),
|
||||
args: Default::default(),
|
||||
args: resolve_arg,
|
||||
type_args: Default::default(),
|
||||
};
|
||||
// Promise.resolve().then
|
||||
@ -1083,7 +1125,7 @@ pub(super) fn handle_dynamic_import(
|
||||
ident: None,
|
||||
function: Function {
|
||||
span: DUMMY_SP,
|
||||
params: vec![],
|
||||
params: then_arg,
|
||||
is_generator: false,
|
||||
is_async: false,
|
||||
type_params: Default::default(),
|
||||
@ -1097,7 +1139,7 @@ pub(super) fn handle_dynamic_import(
|
||||
let mut expr = Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: quote_ident!("require").as_callee(),
|
||||
args,
|
||||
args: require_arg,
|
||||
type_args: Default::default(),
|
||||
}));
|
||||
|
||||
|
@ -571,8 +571,8 @@ impl Scope {
|
||||
// TODO: import assertion
|
||||
&& args.len() == 1 =>
|
||||
{
|
||||
let expr = args.pop().unwrap().expr.fold_with(folder);
|
||||
let expr = match &*expr {
|
||||
let mut expr = args.pop().unwrap().expr.fold_with(folder);
|
||||
let expr = match &mut *expr {
|
||||
Expr::Lit(Lit::Str(s)) => {
|
||||
let src = folder.resolver().resolve(s.value.clone());
|
||||
|
||||
@ -582,15 +582,11 @@ impl Scope {
|
||||
..s.clone()
|
||||
})))
|
||||
}
|
||||
_ => expr,
|
||||
};
|
||||
|
||||
let expr = match *expr {
|
||||
Expr::Ident(ident) => match Self::fold_ident(folder, ident) {
|
||||
Expr::Ident(ident) => Box::new(match Self::fold_ident(folder, ident.take()) {
|
||||
Ok(expr) => expr,
|
||||
Err(ident) => Expr::Ident(ident),
|
||||
},
|
||||
expr => expr,
|
||||
}),
|
||||
_ => expr,
|
||||
};
|
||||
|
||||
folder.make_dynamic_import(span, vec![expr.as_arg()])
|
||||
|
@ -4411,8 +4411,8 @@ test!(
|
||||
",
|
||||
r#""use strict";
|
||||
var _bar = require("bar");
|
||||
Promise.resolve().then(function() {
|
||||
return _interopRequireWildcard(require(_bar.foo));
|
||||
Promise.resolve(`${_bar.foo}`).then(function(s) {
|
||||
return _interopRequireWildcard(require(s));
|
||||
});
|
||||
"#
|
||||
);
|
||||
@ -4429,8 +4429,8 @@ test!(
|
||||
",
|
||||
r#""use strict";
|
||||
var _bar = _interopRequireDefault(require("bar"));
|
||||
Promise.resolve().then(function() {
|
||||
return _interopRequireWildcard(require(_bar.default));
|
||||
Promise.resolve(`${_bar.default}`).then(function(s) {
|
||||
return _interopRequireWildcard(require(s));
|
||||
});
|
||||
"#
|
||||
);
|
||||
@ -4447,8 +4447,8 @@ test!(
|
||||
",
|
||||
r#""use strict";
|
||||
var _bar = require("bar");
|
||||
Promise.resolve().then(function() {
|
||||
return _interopRequireWildcard(require(`world/${(0, _bar).foo(baz)}.js`));
|
||||
Promise.resolve(`world/${(0, _bar).foo(baz)}.js`).then(function(s) {
|
||||
return _interopRequireWildcard(require(s));
|
||||
});
|
||||
"#
|
||||
);
|
||||
@ -5393,6 +5393,21 @@ test!(
|
||||
"
|
||||
);
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| tr(Config {
|
||||
..Default::default()
|
||||
}),
|
||||
issue_4253,
|
||||
"let pipeline = await import(await resolve(file))",
|
||||
"
|
||||
\"use strict\";
|
||||
let pipeline = await Promise.resolve(`${await resolve(file)}`).then(function(s) {
|
||||
return _interopRequireWildcard(require(s));
|
||||
});
|
||||
"
|
||||
);
|
||||
|
||||
#[testing::fixture("tests/fixture/commonjs/**/input.js")]
|
||||
fn fixture(input: PathBuf) {
|
||||
let dir = input.parent().unwrap().to_path_buf();
|
||||
|
@ -2375,6 +2375,48 @@ where
|
||||
v.bindings
|
||||
}
|
||||
|
||||
pub struct TopLevelAwait {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl Visit for TopLevelAwait {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_stmts(&mut self, _: &[Stmt]) {}
|
||||
|
||||
fn visit_param(&mut self, _: &Param) {}
|
||||
|
||||
fn visit_function(&mut self, _: &Function) {}
|
||||
|
||||
fn visit_arrow_expr(&mut self, _: &ArrowExpr) {}
|
||||
|
||||
fn visit_class_member(&mut self, prop: &ClassMember) {
|
||||
match prop {
|
||||
ClassMember::ClassProp(ClassProp {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
})
|
||||
| ClassMember::Method(ClassMethod {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
}) => computed.visit_children_with(self),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_await_expr(&mut self, _: &AwaitExpr) {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_top_level_await<V: VisitWith<TopLevelAwait>>(t: &V) -> bool {
|
||||
let mut finder = TopLevelAwait { found: false };
|
||||
|
||||
t.visit_with(&mut finder);
|
||||
|
||||
finder.found
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use swc_common::{input::StringInput, BytePos};
|
||||
|
Loading…
Reference in New Issue
Block a user