Skip to content

Commit

Permalink
feat(externals): support 'commonjs-import' type (#8414)
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework authored Nov 13, 2024
1 parent 0e01f8c commit 92ce991
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 33 deletions.
7 changes: 7 additions & 0 deletions crates/rspack_core/src/external_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ fn resolve_external_type<'a>(
dependency_meta: &'a DependencyMeta,
) -> &'a str {
match external_type {
"commonjs-import" => {
if let Some(ExternalTypeEnum::Import) = dependency_meta.external_type.as_ref() {
"import"
} else {
"commonjs"
}
}
"module-import" => {
if let Some(external_type) = dependency_meta.external_type.as_ref() {
match external_type {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import e1 from 'external1'
const e2 = import('external2')

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const fs = require("fs");
const path = require("path");
const readCase = (name)=> fs.readFileSync(path.resolve(__dirname, `${name}.js`), "utf-8");
const caseContent = readCase("case");

it("dynamic import should be preserved, others should be in commonjs external", function () {
expect(caseContent).toContain(`import("external2-alias")`)
expect(caseContent).toContain(`require("external1-alias")`)
expect(caseContent).not.toContain(`require("external2-alias")`)
expect(caseContent).toContain(`const e2 = Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, `)
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @type {import("@rspack/core").Configuration} */
module.exports = [
{
target: "node",
entry: {
"index": "./index.js",
"case": "./case.js",
},
externalsType: "commonjs-import",
output: {
module: false,
filename: "[name].js",
},
externals: {
external1: "external1-alias",
external2: "external2-alias",
},
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import("../../../../dist").TConfigCaseConfig} */
module.exports = {
findBundle: (i, options) => {
return ["index.js"];
}
};
22 changes: 11 additions & 11 deletions packages/rspack/etc/core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2002,10 +2002,10 @@ export type ExternalsPresets = {
};

// @public
export type ExternalsType = "var" | "module" | "assign" | "this" | "window" | "self" | "global" | "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd" | "amd-require" | "umd" | "umd2" | "jsonp" | "system" | "promise" | "import" | "module-import" | "script" | "node-commonjs";
export type ExternalsType = "var" | "module" | "assign" | "this" | "window" | "self" | "global" | "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd" | "amd-require" | "umd" | "umd2" | "jsonp" | "system" | "promise" | "import" | "module-import" | "script" | "node-commonjs" | "commonjs-import";

// @public (undocumented)
export const externalsType: z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs"]>;
export const externalsType: z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs", "commonjs-import"]>;

// @public (undocumented)
type ExtractCommentsBanner = string | boolean;
Expand Down Expand Up @@ -6319,7 +6319,7 @@ export const rspackOptions: z.ZodObject<{
contextInfo?: {
issuer: string;
} | undefined;
}>, z.ZodFunction<z.ZodTuple<[z.ZodOptional<z.ZodType<Error, z.ZodTypeDef, Error>>, z.ZodOptional<z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodBoolean]>, z.ZodArray<z.ZodString, "many">]>, ZodRspackCrossChecker<t.ExternalItemUmdValue | t.ExternalItemObjectValue>]>>, z.ZodOptional<z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs"]>>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction<z.ZodTuple<[z.ZodObject<{
}>, z.ZodFunction<z.ZodTuple<[z.ZodOptional<z.ZodType<Error, z.ZodTypeDef, Error>>, z.ZodOptional<z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodBoolean]>, z.ZodArray<z.ZodString, "many">]>, ZodRspackCrossChecker<t.ExternalItemUmdValue | t.ExternalItemObjectValue>]>>, z.ZodOptional<z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs", "commonjs-import"]>>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction<z.ZodTuple<[z.ZodObject<{
context: z.ZodOptional<z.ZodString>;
dependencyType: z.ZodOptional<z.ZodString>;
request: z.ZodOptional<z.ZodString>;
Expand Down Expand Up @@ -6369,7 +6369,7 @@ export const rspackOptions: z.ZodObject<{
contextInfo?: {
issuer: string;
} | undefined;
}>, z.ZodFunction<z.ZodTuple<[z.ZodOptional<z.ZodType<Error, z.ZodTypeDef, Error>>, z.ZodOptional<z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodBoolean]>, z.ZodArray<z.ZodString, "many">]>, ZodRspackCrossChecker<t.ExternalItemUmdValue | t.ExternalItemObjectValue>]>>, z.ZodOptional<z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs"]>>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction<z.ZodTuple<[z.ZodObject<{
}>, z.ZodFunction<z.ZodTuple<[z.ZodOptional<z.ZodType<Error, z.ZodTypeDef, Error>>, z.ZodOptional<z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodBoolean]>, z.ZodArray<z.ZodString, "many">]>, ZodRspackCrossChecker<t.ExternalItemUmdValue | t.ExternalItemObjectValue>]>>, z.ZodOptional<z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs", "commonjs-import"]>>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction<z.ZodTuple<[z.ZodObject<{
context: z.ZodOptional<z.ZodString>;
dependencyType: z.ZodOptional<z.ZodString>;
request: z.ZodOptional<z.ZodString>;
Expand All @@ -6395,7 +6395,7 @@ export const rspackOptions: z.ZodObject<{
issuer: string;
} | undefined;
}>], z.ZodUnknown>, z.ZodPromise<z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodBoolean]>, z.ZodArray<z.ZodString, "many">]>, ZodRspackCrossChecker<t.ExternalItemUmdValue | t.ExternalItemObjectValue>]>>>]>]>>;
externalsType: z.ZodOptional<z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs"]>>;
externalsType: z.ZodOptional<z.ZodEnum<["var", "module", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "commonjs-static", "amd", "amd-require", "umd", "umd2", "jsonp", "system", "promise", "import", "module-import", "script", "node-commonjs", "commonjs-import"]>>;
externalsPresets: z.ZodOptional<z.ZodObject<{
node: z.ZodOptional<z.ZodBoolean>;
web: z.ZodOptional<z.ZodBoolean>;
Expand Down Expand Up @@ -8652,7 +8652,7 @@ export const rspackOptions: z.ZodObject<{
contextInfo?: {
issuer: string;
} | undefined;
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
request?: string | undefined;
context?: string | undefined;
dependencyType?: string | undefined;
Expand All @@ -8666,15 +8666,15 @@ export const rspackOptions: z.ZodObject<{
contextInfo?: {
issuer: string;
} | undefined;
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
request?: string | undefined;
context?: string | undefined;
dependencyType?: string | undefined;
contextInfo?: {
issuer: string;
} | undefined;
}, ...args: unknown[]) => Promise<string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue>))[] | undefined;
externalsType?: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | undefined;
externalsType?: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined;
externalsPresets?: {
node?: boolean | undefined;
web?: boolean | undefined;
Expand Down Expand Up @@ -9257,7 +9257,7 @@ export const rspackOptions: z.ZodObject<{
contextInfo?: {
issuer: string;
} | undefined;
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
request?: string | undefined;
context?: string | undefined;
dependencyType?: string | undefined;
Expand All @@ -9271,15 +9271,15 @@ export const rspackOptions: z.ZodObject<{
contextInfo?: {
issuer: string;
} | undefined;
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
}, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: {
request?: string | undefined;
context?: string | undefined;
dependencyType?: string | undefined;
contextInfo?: {
issuer: string;
} | undefined;
}, ...args: unknown[]) => Promise<string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue>))[] | undefined;
externalsType?: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | undefined;
externalsType?: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined;
externalsPresets?: {
node?: boolean | undefined;
web?: boolean | undefined;
Expand Down
3 changes: 2 additions & 1 deletion packages/rspack/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,8 @@ export type ExternalsType =
| "import"
| "module-import"
| "script"
| "node-commonjs";
| "node-commonjs"
| "commonjs-import";
//#endregion

//#region Externals
Expand Down
3 changes: 2 additions & 1 deletion packages/rspack/src/config/zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,8 @@ export const externalsType = z.enum([
"import",
"module-import",
"script",
"node-commonjs"
"node-commonjs",
"commonjs-import"
]) satisfies z.ZodType<t.ExternalsType>;
//#endregion

Expand Down
79 changes: 69 additions & 10 deletions website/docs/en/config/externals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ For example, to include [jQuery](https://jquery.com/) from a CDN instead of bund
module.exports = {
//...
externals: {
jquery: 'jQuery',
jquery: 'jquery',
},
};
```
Expand Down Expand Up @@ -292,6 +292,7 @@ Supported types:
- [`'module'`](#externalstypemodule)
- [`'import'`](#externalstypeimport) - uses `import()` to load a native EcmaScript module (async module)
- [`'module-import'`](#externalstypemodule-import)
- [`'commonjs-import'`](#externalstypecommonjs-import)
- `'jsonp'`
- [`'node-commonjs'`](#externalstypenode-commonjs)
- [`'promise'`](#externalstypepromise) - same as `'var'` but awaits the result (async module)
Expand Down Expand Up @@ -414,7 +415,7 @@ Specify the default type of externals as `'import'`. Rspack will generate code l

```javascript
async function foo() {
const jq = await import('jQuery');
const jq = await import('jquery');
jq('.my-element').animate(/* ... */);
}
```
Expand All @@ -432,16 +433,16 @@ Will generate into something like

```javascript
var __webpack_modules__ = {
jQuery: module => {
module.exports = import('jQuery');
jquery: module => {
module.exports = import('jquery');
},
};

// webpack runtime...

async function foo() {
const jq = await Promise.resolve(/* import() */).then(
__webpack_require__.bind(__webpack_require__, 'jQuery'),
__webpack_require__.bind(__webpack_require__, 'jquery'),
);
jq('.my-element').animate(/* ... */);
}
Expand All @@ -461,15 +462,16 @@ Make sure to enable [`experiments.outputModule`](/config/#experimentsoutputmodul
import { attempt } from 'lodash';

async function foo() {
const jq = await import('jQuery');
const jq = await import('jquery');
attempt(() => jq('.my-element').animate(/* ... */));
}
```

```js title="rspack.config.js"
module.exports = {
externalsType: 'import',
externalsType: 'module-import',
externals: {
lodash: 'lodash',
jquery: 'jquery',
},
};
Expand All @@ -482,16 +484,16 @@ import * as __WEBPACK_EXTERNAL_MODULE_lodash__ from 'lodash';
const lodash = __WEBPACK_EXTERNAL_MODULE_jquery__;

var __webpack_modules__ = {
jQuery: module => {
module.exports = import('jQuery');
jquery: module => {
module.exports = import('jquery');
},
};

// webpack runtime...

async function foo() {
const jq = await Promise.resolve(/* import() */).then(
__webpack_require__.bind(__webpack_require__, 'jQuery'),
__webpack_require__.bind(__webpack_require__, 'jquery'),
);
(0, lodash.attempt)(() => jq('.my-element').animate(/* ... */));
}
Expand All @@ -517,6 +519,63 @@ module.exports = {
]
```
### externalsType['commonjs-import']
Specify the default type of externals as `'commonjs-import'`. This combines [`'commonjs'`](#externalstypecommonjs) and [`'import'`](#externalstypeimport). Rspack will automatically detect the type of import syntax, setting dynamic import to `'import'` and leaving others to `'commonjs'`.
This is useful when building a Node.js application that target Node.js version higher than `13.2.0`, which supports both [`import()` expressions](https://nodejs.org/api/esm.html#import-expressions) and `require()`.
:::note
`commonjs-import` type is only available of Rspack, and not applicable for webpack.
:::
**Example**
```javascript
import { attempt } from 'lodash';

async function foo() {
const jq = await import('jquery');
attempt(() => jq('.my-element').animate(/* ... */));
}
```
```js title="rspack.config.js"
module.exports = {
externalsType: 'commonjs-import',
externals: {
lodash: 'lodash',
jquery: 'jquery',
},
};
```
Will generate into something like
```javascript
var __webpack_modules__ = {
lodash: function (module) {
module.exports = require('lodash');
},
jquery: function (module) {
module.exports = import('jquery');
},
};

// webpack runtime...

async function foo() {
const jq = await Promise.resolve(/* import() */).then(
__webpack_require__.bind(__webpack_require__, 'jquery'),
);
(0, lodash__WEBPACK_IMPORTED_MODULE_0__.attempt)(() =>
jq('.my-element').animate(/* ... */),
);
}
```
Note that there will be an `import()` statement in the output bundle.
### 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.
Expand Down
Loading

2 comments on commit 92ce991

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-11-13 0e01f8c) Current Change
10000_big_production-mode + exec 44.9 s ± 1.17 s 44.3 s ± 590 ms -1.31 %
10000_development-mode + exec 1.81 s ± 45 ms 1.79 s ± 28 ms -1.08 %
10000_development-mode_hmr + exec 644 ms ± 7.8 ms 643 ms ± 5 ms -0.19 %
10000_production-mode + exec 2.43 s ± 49 ms 2.42 s ± 28 ms -0.28 %
arco-pro_development-mode + exec 1.77 s ± 77 ms 1.77 s ± 58 ms -0.36 %
arco-pro_development-mode_hmr + exec 431 ms ± 2 ms 430 ms ± 1.6 ms -0.14 %
arco-pro_production-mode + exec 3.17 s ± 70 ms 3.18 s ± 85 ms +0.16 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.23 s ± 79 ms 3.22 s ± 75 ms -0.24 %
threejs_development-mode_10x + exec 1.58 s ± 15 ms 1.58 s ± 18 ms -0.23 %
threejs_development-mode_10x_hmr + exec 778 ms ± 6.8 ms 775 ms ± 13 ms -0.38 %
threejs_production-mode_10x + exec 4.95 s ± 35 ms 4.96 s ± 38 ms +0.21 %

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ✅ success
_selftest ✅ success
rspress ✅ success
rslib ✅ success
rsbuild ✅ success
examples ✅ success
devserver ✅ success

Please sign in to comment.