diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index a619025adf32..1c39cfcfae17 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -1830,3 +1830,4 @@ export interface ThreadsafeNodeFS { mkdirp: (name: string) => Promise | string | void removeDirAll: (name: string) => Promise | string | void } + diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index e8173a5c66a3..867d46902e69 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -345,15 +345,13 @@ if(typeof {global} !== "undefined") return resolve(); fn get_module_import_type<'a>(&self, external_type: &'a ExternalType) -> &'a str { match external_type.as_str() { "module-import" => { - let external_type = self - .dependency_meta - .external_type - .as_ref() - .expect("should get \"module\" or \"import\" external type from dependency"); - - match external_type { - ExternalTypeEnum::Import => "import", - ExternalTypeEnum::Module => "module", + if let Some(external_type) = self.dependency_meta.external_type.as_ref() { + match external_type { + ExternalTypeEnum::Import => "import", + ExternalTypeEnum::Module => "module", + } + } else { + "module" } } import_or_module => import_or_module, @@ -479,10 +477,7 @@ impl Module for ExternalModule { build_result.build_meta.has_top_level_await = true; build_result.build_meta.exports_type = BuildMetaExportsType::Namespace; } - r#type => panic!( - "Unhandled external type: {} in \"module-import\" type", - r#type - ), + _ => {} }, _ => build_result.build_meta.exports_type = BuildMetaExportsType::Dynamic, } diff --git a/tests/webpack-test/configCases/externals/module-import/a.js b/tests/webpack-test/configCases/externals/module-import/a.js new file mode 100644 index 000000000000..97b356b1b212 --- /dev/null +++ b/tests/webpack-test/configCases/externals/module-import/a.js @@ -0,0 +1,6 @@ +import external0 from "external0"; // module +const external1 = require("external1"); // module +const external2 = require("external2"); // node-commonjs +const external3 = import("external3"); // import + +console.log(external0, external1, external2, external3); diff --git a/tests/webpack-test/configCases/externals/module-import/index.js b/tests/webpack-test/configCases/externals/module-import/index.js new file mode 100644 index 000000000000..4036fafe9d5d --- /dev/null +++ b/tests/webpack-test/configCases/externals/module-import/index.js @@ -0,0 +1,10 @@ +const fs = require("fs"); +const path = require("path"); + +it("module-import should correctly get fallback type", function() { + const content = fs.readFileSync(path.resolve(__dirname, "a.js"), "utf-8"); + expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external0__ from "external0";`); // module + expect(content).toContain(`import * as __WEBPACK_EXTERNAL_MODULE_external1__ from "external1";`); // module + expect(content).toContain(`module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("external2");`); // node-commonjs + expect(content).toContain(`module.exports = import("external3");`); // import +}); diff --git a/tests/webpack-test/configCases/externals/module-import/test.config.js b/tests/webpack-test/configCases/externals/module-import/test.config.js new file mode 100644 index 000000000000..93fd44fb16bf --- /dev/null +++ b/tests/webpack-test/configCases/externals/module-import/test.config.js @@ -0,0 +1,3 @@ +module.exports = { + findBundle: (i, options) => ["main.js"] +}; diff --git a/tests/webpack-test/configCases/externals/module-import/webpack.config.js b/tests/webpack-test/configCases/externals/module-import/webpack.config.js new file mode 100644 index 000000000000..3758c82bf741 --- /dev/null +++ b/tests/webpack-test/configCases/externals/module-import/webpack.config.js @@ -0,0 +1,41 @@ +/** @type {import("../../../../types").Configuration} */ +module.exports = { + target: ["web", "es2020"], + node: { + __dirname: false, + __filename: false + }, + output: { + module: true, + filename: "[name].js" + }, + entry: { + a: "./a", + main: "./index" + }, + optimization: { + concatenateModules: true + }, + experiments: { + outputModule: true + }, + externalsType: "module-import", + externals: [ + function ( + { context, request, contextInfo, getResolve, dependencyType }, + callback + ) { + if (request === "external2") { + return callback(null, "node-commonjs external2"); + } + callback(); + }, + { + external0: "external0", + external1: "external1", + external3: "external3", + fs: "commonjs fs", + path: "commonjs path" + } + ] +}; diff --git a/website/docs/en/config/externals.mdx b/website/docs/en/config/externals.mdx index 6876d387bb89..01cf05ad5f95 100644 --- a/website/docs/en/config/externals.mdx +++ b/website/docs/en/config/externals.mdx @@ -514,6 +514,24 @@ async function foo() { Note that there will be an `import` or `import()` statement in the output bundle. +When a module is not imported via `import` or `import()`, Rspack will use `"module"` externals type as fallback. If you want to use a different type of externals as fallback, you can specify it with a function in the `externals` option. For example: + +```js title="rspack.config.js" +module.exports = { + externalsType: "module-import", + externals: [ + function ( + { request, dependencyType }, + callback + ) { + if (dependencyType === "commonjs") { + return callback(null, `node-commonjs ${request}`); + } + callback(); + }, + ] +``` + ### externalsType['node-commonjs'] Specify the default type of externals as `'node-commonjs'`. Rspack will import [`createRequire`](https://nodejs.org/api/module.html#module_module_createrequire_filename) from `'module'` to construct a require function for loading externals used in a module. diff --git a/website/docs/zh/config/externals.mdx b/website/docs/zh/config/externals.mdx index 3d29ab242bb3..84618ac55541 100644 --- a/website/docs/zh/config/externals.mdx +++ b/website/docs/zh/config/externals.mdx @@ -513,6 +513,24 @@ async function foo() { 请注意,在输出产物中将有 `import` 或 `import()` 语句。 +当一个模块没有通过 `import` 或 `import()` 导入时,Rspack 将使用 `"module"` externals type 作为回退。如果你想使用不同类型的 externals 作为回退,你可以在 `externals` 选项中指定一个函数。例如: + +```js title="rspack.config.js" +module.exports = { + externalsType: "module-import", + externals: [ + function ( + { request, dependencyType }, + callback + ) { + if (dependencyType === "commonjs") { + return callback(null, `node-commonjs ${request}`); + } + callback(); + }, + ] +``` + ### externalsType['node-commonjs'] 将 externals 类型设置为 `'node-commonjs'`,Rspack 将从 `module` 中导入 [`createRequire`](https://nodejs.org/api/module.html#module_module_createrequire_filename) 来构造一个 require 函数,用于加载模块中使用的外部对象。