Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/bundler/LinkerContext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2571,7 +2571,10 @@ impl<'a> LinkerContext<'a> {
} else {
Ref::NONE
},
is_wrapper_async: flags.is_async_or_has_async_dependency && wrapper_ref.is_valid(),
// A `__commonJS` wrapper returns `module.exports`, never a promise.
is_wrapper_async: flags.wrap == WrapKind::Esm
&& flags.is_async_or_has_async_dependency
&& wrapper_ref.is_valid(),
wrapper_ref,

was_unwrapped_require: was_unwrapped_require
Expand Down
77 changes: 77 additions & 0 deletions test/bundler/bundler_cjs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,83 @@ describe("bundler", () => {
},
});

// ============================================================================
// `import()` of a bundled CommonJS file that the linker marks async
//
// The linker marks a file async when a module with top-level await is on its
// chain of static imports, also when tree shaking removes that import. The
// `__commonJS` wrapper of the file still returns `module.exports`, not a
// promise, so `import()` builds the namespace as for any other CommonJS file.
// ============================================================================

// Tree shaking removes this package when nothing reads its exports.
const unusedAsyncPackage = {
"/node_modules/async-pkg/package.json": `{ "name": "async-pkg", "main": "index.js", "sideEffects": false }`,
"/node_modules/async-pkg/index.js": `await 0;\nexport const unused = 1;`,
};

// `await import()`
itBundled("cjs/__toESM_dynamic_import_of_file_marked_async", {
files: {
"/entry.js": `const ns = await import("./c.js");\nconsole.log(ns.default.t, ns.t);`,
"/c.js": `import { unused } from "async-pkg";\nmodule.exports = { t: 5 };`,
...unusedAsyncPackage,
},
run: {
stdout: "5 5",
},
});

// `import().then()`
itBundled("cjs/__toESM_dynamic_import_then_of_file_marked_async", {
files: {
"/entry.js": `import("./c.js").then(ns => console.log(ns.default.t));`,
"/c.js": `import { unused } from "async-pkg";\nmodule.exports = { t: 5 };`,
...unusedAsyncPackage,
},
run: {
stdout: "5",
},
});

// The promise is for the namespace, not for `module.exports`.
itBundled("cjs/__toESM_dynamic_import_of_function_marked_async", {
files: {
"/entry.js": `const ns = await import("./c.js");\nconsole.log(typeof ns, typeof ns.default, ns.default());`,
"/c.js": `import { unused } from "async-pkg";\nmodule.exports = function () { return 5; };`,
...unusedAsyncPackage,
},
run: {
stdout: "object function 5",
},
});

// The file runs in a microtask, after the code that follows `import()`.
itBundled("cjs/__toESM_dynamic_import_order_of_file_marked_async", {
files: {
"/entry.js": `console.log("before");\nconst promise = import("./c.js");\nconsole.log("after");\nconsole.log((await promise).default.t);`,
"/c.js": `import { unused } from "async-pkg";\nconsole.log("c runs");\nmodule.exports = { t: 5 };`,
...unusedAsyncPackage,
},
run: {
stdout: "before\nafter\nc runs\n5",
},
});

// `export *` of a module with top-level await marks the file async too.
// The namespace has the names of that module. `t` is a literal, so its value
// does not depend on `init_async()`, which the wrapper of `c.js` does not await.
itBundled("cjs/__toESM_dynamic_import_of_file_with_export_star_marked_async", {
files: {
"/entry.js": `const ns = await import("./c.js");\nconsole.log(JSON.stringify(ns));`,
"/c.js": `export * from "./async.js";\nexports.a = 1;\nObject.keys(exports);`,
"/async.js": `await 0;\nexport const t = 2;`,
},
run: {
stdout: `{"default":{"t":2,"a":1},"t":2,"a":1}`,
},
});

const externalImportLog = /* js */ `
import d, { named } from "ext";
console.log(typeof d, named);
Comment thread
robobun marked this conversation as resolved.
Resolved
Expand Down
Loading