Skip to content
Merged
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: 5 additions & 0 deletions .changeset/odd-lies-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rsbuild/plugin-babel': patch
---

feat(plugin-babel): add include and exclude option
8 changes: 6 additions & 2 deletions e2e/cases/babel/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ rspackOnlyTest('babel exclude', async ({ page }) => {
const rsbuild = await build({
cwd: __dirname,
runServer: true,
rsbuildConfig: {
source: {
exclude: [/aa/],
},
},
plugins: [
pluginBabel({
babelLoaderOptions: (_, { addPlugins, addExcludes }) => {
babelLoaderOptions: (_, { addPlugins }) => {
addPlugins([require('./plugins/myBabelPlugin')]);
addExcludes(/aa/);
},
}),
],
Expand Down
8 changes: 7 additions & 1 deletion e2e/cases/vue/jsx-basic/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@ import { pluginVueJsx } from '@rsbuild/plugin-vue-jsx';
import { pluginBabel } from '@rsbuild/plugin-babel';

export default defineConfig({
plugins: [pluginVue(), pluginVueJsx(), pluginBabel()],
plugins: [
pluginVue(),
pluginVueJsx(),
pluginBabel({
include: /\.(jsx|tsx)$/,
}),
],
});
19 changes: 8 additions & 11 deletions packages/plugin-babel/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ import type {
BabelConfigUtils,
PresetEnvOptions,
PresetReactOptions,
BabelPluginOptions,
BabelTransformOptions,
PluginBabelOptions,
} from './types';
import type { PluginOptions as BabelPluginOptions } from '@babel/core';

export const BABEL_JS_RULE = 'babel-js';

const normalizeToPosixPath = (p: string | undefined) =>
upath
Expand Down Expand Up @@ -126,6 +129,7 @@ export const getBabelUtils = (
): BabelConfigUtils => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => {};

return {
addPlugins: (plugins: BabelPlugin[]) => addPlugins(plugins, config),
addPresets: (presets: BabelPlugin[]) => addPresets(presets, config),
Expand All @@ -137,24 +141,17 @@ export const getBabelUtils = (
// It can be overridden by `extraBabelUtils`.
addIncludes: noop,
addExcludes: noop,
// Compat `presetEnvOptions` and `presetReactOptions` in Eden.
// Compat `presetEnvOptions` and `presetReactOptions` in Modern.js
modifyPresetEnvOptions: (options: PresetEnvOptions) =>
modifyPresetOptions('@babel/preset-env', options, config.presets || []),
modifyPresetReactOptions: (options: PresetReactOptions) =>
modifyPresetOptions('@babel/preset-react', options, config.presets || []),
};
};

export type BabelConfig =
| BabelTransformOptions
| ((
config: BabelTransformOptions,
utils: BabelConfigUtils,
) => BabelTransformOptions | void);

export const applyUserBabelConfig = (
defaultOptions: BabelTransformOptions,
userBabelConfig?: BabelConfig | BabelConfig[],
userBabelConfig?: PluginBabelOptions['babelLoaderOptions'],
extraBabelUtils?: Partial<BabelConfigUtils>,
): BabelTransformOptions => {
if (userBabelConfig) {
Expand Down Expand Up @@ -190,7 +187,7 @@ export const modifyBabelLoaderOptions = ({
CHAIN_ID: ChainIdentifier;
modifier: (config: BabelTransformOptions) => BabelTransformOptions;
}) => {
const ruleIds = [CHAIN_ID.RULE.JS, CHAIN_ID.RULE.JS_DATA_URI];
const ruleIds = [CHAIN_ID.RULE.JS, CHAIN_ID.RULE.JS_DATA_URI, BABEL_JS_RULE];

ruleIds.forEach((ruleId) => {
if (chain.module.rules.has(ruleId)) {
Expand Down
91 changes: 45 additions & 46 deletions packages/plugin-babel/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import type { RsbuildPlugin } from '@rsbuild/core';
import { cloneDeep, SCRIPT_REGEX } from '@rsbuild/shared';
import { applyUserBabelConfig, type BabelConfig } from './helper';
import { castArray, cloneDeep, SCRIPT_REGEX } from '@rsbuild/shared';
import { applyUserBabelConfig, BABEL_JS_RULE } from './helper';
import type { PluginBabelOptions } from './types';

/**
Expand All @@ -25,27 +25,6 @@ export const pluginBabel = (
setup(api) {
api.modifyBundlerChain(async (chain, { CHAIN_ID, isProd }) => {
const getBabelOptions = () => {
// 1. Create babel utils function about include/exclude,
const includes: Array<string | RegExp> = [];
const excludes: Array<string | RegExp> = [];

const babelUtils = {
addIncludes(items: string | RegExp | Array<string | RegExp>) {
if (Array.isArray(items)) {
includes.push(...items);
} else {
includes.push(items);
}
},
addExcludes(items: string | RegExp | Array<string | RegExp>) {
if (Array.isArray(items)) {
excludes.push(...items);
} else {
excludes.push(items);
}
},
};

const baseConfig = {
plugins: [],
presets: [
Expand All @@ -60,42 +39,62 @@ export const pluginBabel = (
const userBabelConfig = applyUserBabelConfig(
cloneDeep(baseConfig),
options.babelLoaderOptions,
babelUtils,
);

const babelOptions: BabelConfig = {
return {
babelrc: false,
configFile: false,
compact: isProd,
...userBabelConfig,
};

return {
babelOptions,
includes,
excludes,
};
};

const { babelOptions, includes = [], excludes = [] } = getBabelOptions();
const babelOptions = getBabelOptions();
const babelLoader = path.resolve(
__dirname,
'../compiled/babel-loader/index.js',
);
const { include, exclude } = options;

// already set source.include / exclude in plugin-swc
const rule = chain.module.rule(CHAIN_ID.RULE.JS);
if (include || exclude) {
const rule = chain.module.rule(BABEL_JS_RULE);

includes.forEach((condition) => {
rule.include.add(condition);
});
if (include) {
castArray(include).forEach((condition) => {
rule.include.add(condition);
});
}
if (exclude) {
castArray(exclude).forEach((condition) => {
rule.exclude.add(condition);
});
}

excludes.forEach((condition) => {
rule.exclude.add(condition);
});
const swcRule = chain.module.rules
.get(CHAIN_ID.RULE.JS)
.use(CHAIN_ID.USE.SWC);
const swcLoader = swcRule.get('loader');
const swcOptions = swcRule.get('options');

rule
.test(SCRIPT_REGEX)
.use(CHAIN_ID.USE.BABEL)
.after(CHAIN_ID.USE.SWC)
.loader(path.resolve(__dirname, '../compiled/babel-loader/index.js'))
.options(babelOptions);
rule
.test(SCRIPT_REGEX)
.use(CHAIN_ID.USE.SWC)
.loader(swcLoader)
.options(swcOptions)
.end()
.use(CHAIN_ID.USE.BABEL)
.loader(babelLoader)
.options(babelOptions);
} else {
// already set source.include / exclude in plugin-swc
const rule = chain.module.rule(CHAIN_ID.RULE.JS);
rule
.test(SCRIPT_REGEX)
.use(CHAIN_ID.USE.BABEL)
.after(CHAIN_ID.USE.SWC)
.loader(babelLoader)
.options(babelOptions);
}
});
},
});
11 changes: 7 additions & 4 deletions packages/plugin-babel/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { ChainedConfigWithUtils } from '@rsbuild/shared';
import type {
PluginItem as BabelPlugin,
PluginOptions as BabelPluginOptions,
TransformOptions as BabelTransformOptions,
} from '@babel/core';

export { BabelPlugin, BabelPluginOptions, BabelTransformOptions };
export type { BabelPlugin, BabelTransformOptions };

export type PresetEnvTargets = string | string[] | Record<string, string>;
export type PresetEnvBuiltIns = 'usage' | 'entry' | false;
Expand Down Expand Up @@ -51,6 +50,8 @@ export type PresetReactOptions =
| AutomaticRuntimePresetReactOptions
| ClassicRuntimePresetReactOptions;

export type RuleCondition = string | RegExp | (string | RegExp);

export type BabelConfigUtils = {
addPlugins: (plugins: BabelPlugin[]) => void;
addPresets: (presets: BabelPlugin[]) => void;
Expand All @@ -62,15 +63,17 @@ export type BabelConfigUtils = {
* use `source.include` instead
* @deprecated
*/
addIncludes: (includes: string | RegExp | (string | RegExp)[]) => void;
addIncludes: (includes: RuleCondition[]) => void;
/**
* use `source.exclude` instead
* @deprecated
*/
addExcludes: (excludes: string | RegExp | (string | RegExp)[]) => void;
addExcludes: (excludes: RuleCondition[]) => void;
};

export type PluginBabelOptions = {
include?: RuleCondition;
exclude?: RuleCondition;
babelLoaderOptions?: ChainedConfigWithUtils<
BabelTransformOptions,
BabelConfigUtils
Expand Down
41 changes: 0 additions & 41 deletions packages/plugin-babel/tests/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,46 +1,5 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`plugins/babel > babel-loader addIncludes & addExcludes should works 1`] = `
{
"module": {
"rules": [
{
"exclude": [
"src/example",
],
"include": [
/\\\\/node_modules\\\\/query-string\\\\//,
],
"test": /\\\\\\.\\(js\\|jsx\\|mjs\\|cjs\\|ts\\|tsx\\|mts\\|cts\\)\\$/,
"use": [
{
"loader": "<ROOT>/packages/plugin-babel/compiled/babel-loader/index.js",
"options": {
"babelrc": false,
"compact": false,
"configFile": false,
"plugins": [],
"presets": [
[
"<ROOT>/node_modules/<PNPM_INNER>/@babel/preset-typescript/lib/index.js",
{
"allExtensions": true,
"allowDeclareFields": true,
"allowNamespaces": true,
"isTSX": true,
"optimizeConstEnums": true,
},
],
],
},
},
],
},
],
},
}
`;

exports[`plugins/babel > babel-loader should works with builtin:swc-loader 1`] = `
{
"exclude": [
Expand Down
34 changes: 7 additions & 27 deletions packages/plugin-babel/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@ import { SCRIPT_REGEX } from '@rsbuild/shared';
describe('plugins/babel', () => {
it('babel-loader should works with builtin:swc-loader', async () => {
const rsbuild = await createStubRsbuild({
rsbuildConfig: {},
rsbuildConfig: {
source: {
include: [/\/node_modules\/query-string\//],
exclude: ['src/example'],
},
},
});

rsbuild.addPlugins([
pluginBabel({
babelLoaderOptions: (_config, { addExcludes, addIncludes }) => {
addIncludes(/\/node_modules\/query-string\//);
addExcludes('src/example');
},
}),
]);
rsbuild.addPlugins([pluginBabel()]);

const config = await rsbuild.unwrapConfig();

Expand Down Expand Up @@ -61,22 +59,4 @@ describe('plugins/babel', () => {

expect(bundlerConfigs[0]).toMatchSnapshot();
});

it('babel-loader addIncludes & addExcludes should works', async () => {
const rsbuild = await createStubRsbuild({
plugins: [
pluginBabel({
babelLoaderOptions: (_config, { addExcludes, addIncludes }) => {
addIncludes(/\/node_modules\/query-string\//);
addExcludes('src/example');
},
}),
],
rsbuildConfig: {},
});

const bundlerConfigs = await rsbuild.initConfigs();

expect(bundlerConfigs[0]).toMatchSnapshot();
});
});