Skip to content

Commit

Permalink
Reapply "fix:dynamic import as namespace import (#1171)" (#1208)
Browse files Browse the repository at this point in the history
This reverts commit 6e69d85.
  • Loading branch information
stormslowly committed May 27, 2024
1 parent 6e69d85 commit a9df111
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 34 deletions.
4 changes: 1 addition & 3 deletions crates/mako/src/generate/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,7 @@ pub fn transform_js_generate(transform_js_param: TransformJsParam) -> Result<()>
let mut meta_url_replacer = MetaUrlReplacer {};
ast.ast.visit_mut_with(&mut meta_url_replacer);

let mut dynamic_import = DynamicImport {
context: context.clone(),
};
let mut dynamic_import = DynamicImport::new(context.clone(), dep_map);
ast.ast.visit_mut_with(&mut dynamic_import);

// replace require to __mako_require__
Expand Down
4 changes: 1 addition & 3 deletions crates/mako/src/plugins/bundless_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,7 @@ fn transform_js_generate(
};
ast.ast.visit_mut_with(&mut dep_replacer);

let mut dynamic_import = DynamicImport {
context: context.clone(),
};
let mut dynamic_import = DynamicImport::new(context.clone(), dep_map);
ast.ast.visit_mut_with(&mut dynamic_import);

ast.ast
Expand Down
2 changes: 1 addition & 1 deletion crates/mako/src/plugins/context_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl VisitMut for ContextModuleVisitor {
.as_callee();
// TODO: allow use await in args
// eg: import(`./i18n${await xxx()}`)
expr.args = vec![quote_ident!("m")
expr.args = vec![member_expr!(DUMMY_SP, m.default)
.as_call(DUMMY_SP, expr.args.clone())
.as_expr()
.to_owned()
Expand Down
100 changes: 82 additions & 18 deletions crates/mako/src/visitors/dynamic_import.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,74 @@
use std::sync::Arc;

use mako_core::swc_common::DUMMY_SP;
use mako_core::swc_ecma_ast::{ArrayLit, Expr, ExprOrSpread, Lit};
use mako_core::swc_ecma_ast::{ArrayLit, Expr, ExprOrSpread, Lit, MemberExpr};
use mako_core::swc_ecma_visit::{VisitMut, VisitMutWith};

use crate::ast::utils::{
id, is_dynamic_import, member_call, member_prop, promise_all, require_ensure,
use swc_core::ecma::ast::{Ident, Module, Stmt, VarDeclKind};
use swc_core::ecma::utils::{
member_expr, private_ident, quote_ident, quote_str, ExprFactory, IsDirective,
};

use crate::ast::utils::{is_dynamic_import, member_call, member_prop, promise_all, require_ensure};
use crate::compiler::Context;
use crate::generate::chunk::ChunkId;
use crate::visitors::dep_replacer::DependenciesToReplace;

pub struct DynamicImport {
pub struct DynamicImport<'a> {
pub context: Arc<Context>,
interop: Ident,
changed: bool,
dep_to_replace: &'a DependenciesToReplace,
}

impl<'a> DynamicImport<'a> {
pub fn new(context: Arc<Context>, dep_map: &'a DependenciesToReplace) -> Self {
let interop = private_ident!("interop");

Self {
context,
interop,
changed: false,
dep_to_replace: dep_map,
}
}
}

impl VisitMut for DynamicImport {
impl<'a> VisitMut for DynamicImport<'a> {
fn visit_mut_module(&mut self, n: &mut Module) {
n.visit_mut_children_with(self);

if self.changed {
let insert_at = n
.body
.iter()
.position(|module_item| {
!module_item
.as_stmt()
.map_or(false, |stmt| stmt.is_directive())
})
.unwrap();

let (id, _) = self
.dep_to_replace
.resolved
.get("@swc/helpers/_/_interop_require_wildcard")
.unwrap();

let require_interop = quote_ident!("__mako_require__")
.as_call(DUMMY_SP, vec![quote_str!(id.clone()).as_arg()]);

let stmt: Stmt = Expr::Member(MemberExpr {
span: DUMMY_SP,
obj: require_interop.into(),
prop: quote_ident!("_").into(),
})
.into_var_decl(VarDeclKind::Var, self.interop.clone().into())
.into();

n.body.insert(insert_at, stmt.into());
}
}

fn visit_mut_expr(&mut self, expr: &mut Expr) {
if let Expr::Call(call_expr) = expr {
if is_dynamic_import(call_expr) {
Expand Down Expand Up @@ -59,6 +113,7 @@ impl VisitMut for DynamicImport {
chunk_ids
};

self.changed = true;
// build new expr
// e.g.
// Promise.all([ require.ensure("id") ]).then(require.bind(require, "id"))
Expand All @@ -80,26 +135,24 @@ impl VisitMut for DynamicImport {
elems: to_ensure_elems,
})),
});
let require_call = member_call(
Expr::Ident(id("__mako_require__")),
member_prop("bind"),

let require_call = member_expr!(DUMMY_SP, __mako_require__.dr).as_call(
DUMMY_SP,
vec![
ExprOrSpread {
spread: None,
expr: Box::new(Expr::Ident(id("__mako_require__"))),
},
self.interop.clone().as_arg(),
ExprOrSpread {
spread: None,
expr: Box::new(Expr::Lit(Lit::Str(resolved_source.into()))),
},
],
);

member_call(
load_promise,
member_prop("then"),
vec![ExprOrSpread {
spread: None,
expr: Box::new(require_call),
expr: require_call.into(),
}],
)
};
Expand All @@ -112,22 +165,26 @@ impl VisitMut for DynamicImport {

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use mako_core::swc_common::GLOBALS;
use mako_core::swc_ecma_visit::VisitMutWith;

use super::DynamicImport;
use crate::ast::tests::TestUtils;
use crate::generate::chunk::{Chunk, ChunkType};
use crate::visitors::dep_replacer::DependenciesToReplace;

// TODO: add nested chunk test
#[test]
fn test_dynamic_import() {
assert_eq!(
run(r#"import("foo");"#),
r#"
var interop = __mako_require__("hashed_helper")._;
Promise.all([
__mako_require__.ensure("foo")
]).then(__mako_require__.bind(__mako_require__, "foo"));
]).then(__mako_require__.dr(interop, "foo"));
"#
.trim()
);
Expand All @@ -142,10 +199,17 @@ Promise.all([
cg.add_chunk(foo);
}
let ast = test_utils.ast.js_mut();

let dep_to_replace = DependenciesToReplace {
resolved: maplit::hashmap! {
"@swc/helpers/_/_interop_require_wildcard".to_string() =>
("hashed_helper".to_string(), "dummy".into())
},
missing: HashMap::new(),
};

GLOBALS.set(&test_utils.context.meta.script.globals, || {
let mut visitor = DynamicImport {
context: test_utils.context.clone(),
};
let mut visitor = DynamicImport::new(test_utils.context.clone(), &dep_to_replace);
ast.ast.visit_mut_with(&mut visitor);
});
let code = test_utils.js_ast_to_code();
Expand Down
5 changes: 5 additions & 0 deletions crates/mako/templates/app_runtime.stpl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ function createRuntime(makoModules, entryModuleId, global) {
});
};
requireModule.d = Object.defineProperty.bind(Object);
requireModule.dr = function(interop, request) {
return function(){
return interop(requireModule(request));
}
};

<% if has_dynamic_chunks || has_hmr { %>
/* mako/runtime/ensure chunk */
Expand Down
4 changes: 2 additions & 2 deletions e2e/fixtures/javascript.require-dynamic/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ assert.match(

assert.match(
asyncContent,
moduleReg("src/i18n\\?context&glob=\\*\\*/\\*.json&async", "'./zh-CN.json': ()=>Promise.all([\n.*__mako_require__.ensure(\"src/i18n/zh-CN.json\")\n.*]).then(__mako_require__.bind(__mako_require__, \"src/i18n/zh-CN.json\"))", true),
moduleReg("src/i18n\\?context&glob=\\*\\*/\\*.json&async", "'./zh-CN.json': ()=>Promise.all([\n.*__mako_require__.ensure(\"src/i18n/zh-CN.json\")\n.*]).then(__mako_require__.dr(interop, \"src/i18n/zh-CN.json\"))", true),
"should generate context module with correct map in async chunk",
);

Expand All @@ -49,7 +49,7 @@ assert.match(

assert.match(
asyncContent,
moduleReg("src/i18n\\?context&glob=\\*\\*/\\*.json&async", "'./en-US.json': ()=>Promise.all([\n.*__mako_require__.ensure(\"src/i18n/en-US.json\")\n.*]).then(__mako_require__.bind(__mako_require__, \"src/i18n/en-US.json\"))", true),
moduleReg("src/i18n\\?context&glob=\\*\\*/\\*.json&async", "'./en-US.json': ()=>Promise.all([\n.*__mako_require__.ensure(\"src/i18n/en-US.json\")\n.*]).then(__mako_require__.dr(interop, \"src/i18n/en-US.json\"))", true),
"should generate context module with correct map in async chunk",
);

Expand Down
8 changes: 5 additions & 3 deletions e2e/fixtures/javascript.require-dynamic/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ function loadLang(lang) {

function loadLangExt(lang, ext) {
// nested dynamic require + with then callback
return import(`./i18n/${lang}.${(require(`./ext/${ext}`)).default}`).then(m => m);
return import(`./i18n/${lang}.${(require(`./ext/${ext}`)).default}`)

.then(m => m);
}

function loadFile(file) {
Expand All @@ -15,7 +17,7 @@ function loadFile2(file) {
return require('./fake.js/' + file);
}

console.log(loadLang('zh-CN'));
console.log(loadLangExt('zh-CN', 'json'));
loadLang('zh-CN').then(console.log);
loadLangExt('zh-CN', 'json').then(console.log);
console.log(loadFile('/zh-CN.json'));
console.log(loadFile2('a.js'));
16 changes: 16 additions & 0 deletions e2e/fixtures/runtime.dynamic_import_interop/expect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const assert = require("assert");
const {
parseBuildResult,
moduleReg,
injectSimpleJest,
} = require("../../../scripts/test-utils");
const { files } = parseBuildResult(__dirname);

injectSimpleJest();

const index = files["index.js"];

expect(index).toContain(
'var interop = __mako_require__("@swc/helpers/_/_interop_require_wildcard")._;',
);
expect(index).toContain('then(__mako_require__.dr(interop, "src/cjs.js"))');
5 changes: 5 additions & 0 deletions e2e/fixtures/runtime.dynamic_import_interop/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
it("should interop cjs module with default", async () => {
let cjs = await import("./src/cjs");

expect(cjs).toEqual({ default: { foo: 42 }, foo: 42 });
});
10 changes: 10 additions & 0 deletions e2e/fixtures/runtime.dynamic_import_interop/mako.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"optimization": {
"skipModules": false,
"concatenateModules": false
},
"entry": {
"index": "./index.js"
},
"moduleIdStrategy": "named"
}
4 changes: 4 additions & 0 deletions e2e/fixtures/runtime.dynamic_import_interop/src/cjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
foo: 42,
default: "ddd",
};
4 changes: 0 additions & 4 deletions packages/mako/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@

/* auto-generated by NAPI-RS */

export interface TransformOutput {
code: string;
map?: string;
}
export interface JsHooks {
load?: (filePath: string) => Promise<{ content: string; type: 'css' | 'js' }>;
generateEnd?: (data: {
Expand Down

0 comments on commit a9df111

Please sign in to comment.