diff --git a/e2e/cases/environments/vue-react-plugins/index.test.ts b/e2e/cases/environments/vue-react-plugins/index.test.ts
new file mode 100644
index 0000000000..f5955e426b
--- /dev/null
+++ b/e2e/cases/environments/vue-react-plugins/index.test.ts
@@ -0,0 +1,24 @@
+import { build, rspackOnlyTest } from '@e2e/helper';
+import { expect } from '@playwright/test';
+
+rspackOnlyTest('should build basic Vue jsx correctly', async ({ page }) => {
+ const rsbuild = await build({
+ cwd: __dirname,
+ runServer: true,
+ });
+
+ const reactUrl = new URL(`http://localhost:${rsbuild.port}/react`);
+
+ await page.goto(reactUrl.href);
+
+ await expect(page.locator('#test')).toHaveText('Hello Rsbuild!');
+
+ const vueUrl = new URL(`http://localhost:${rsbuild.port}/vue`);
+
+ await page.goto(vueUrl.href);
+
+ const button1 = page.locator('#button1');
+ await expect(button1).toHaveText('A: 0');
+
+ await rsbuild.close();
+});
diff --git a/e2e/cases/environments/vue-react-plugins/rsbuild.config.ts b/e2e/cases/environments/vue-react-plugins/rsbuild.config.ts
new file mode 100644
index 0000000000..23ade6d7eb
--- /dev/null
+++ b/e2e/cases/environments/vue-react-plugins/rsbuild.config.ts
@@ -0,0 +1,32 @@
+import { defineConfig } from '@rsbuild/core';
+import { pluginBabel } from '@rsbuild/plugin-babel';
+import { pluginReact } from '@rsbuild/plugin-react';
+import { pluginVue } from '@rsbuild/plugin-vue';
+import { pluginVueJsx } from '@rsbuild/plugin-vue-jsx';
+
+export default defineConfig({
+ environments: {
+ react: {
+ plugins: [pluginReact()],
+ source: {
+ entry: {
+ react: './src/react/index.ts',
+ },
+ },
+ },
+ vue: {
+ plugins: [
+ pluginVue(),
+ pluginVueJsx(),
+ pluginBabel({
+ include: /\.(?:jsx|tsx)$/,
+ }),
+ ],
+ source: {
+ entry: {
+ vue: './src/vue/index.js',
+ },
+ },
+ },
+ },
+});
diff --git a/e2e/cases/environments/vue-react-plugins/src/react/App.tsx b/e2e/cases/environments/vue-react-plugins/src/react/App.tsx
new file mode 100644
index 0000000000..639af6a6e2
--- /dev/null
+++ b/e2e/cases/environments/vue-react-plugins/src/react/App.tsx
@@ -0,0 +1,3 @@
+const App = () =>
Hello Rsbuild!
;
+
+export default App;
diff --git a/e2e/cases/environments/vue-react-plugins/src/react/index.ts b/e2e/cases/environments/vue-react-plugins/src/react/index.ts
new file mode 100644
index 0000000000..5ceb026ccc
--- /dev/null
+++ b/e2e/cases/environments/vue-react-plugins/src/react/index.ts
@@ -0,0 +1,9 @@
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import App from './App';
+
+const container = document.getElementById('root');
+if (container) {
+ const root = createRoot(container);
+ root.render(React.createElement(App));
+}
diff --git a/e2e/cases/environments/vue-react-plugins/src/vue/A.jsx b/e2e/cases/environments/vue-react-plugins/src/vue/A.jsx
new file mode 100644
index 0000000000..22d6237152
--- /dev/null
+++ b/e2e/cases/environments/vue-react-plugins/src/vue/A.jsx
@@ -0,0 +1,14 @@
+import { defineComponent, ref } from 'vue';
+
+export default defineComponent({
+ name: 'Test',
+
+ setup() {
+ const count = ref(0);
+ return () => (
+
+ );
+ },
+});
diff --git a/e2e/cases/environments/vue-react-plugins/src/vue/index.js b/e2e/cases/environments/vue-react-plugins/src/vue/index.js
new file mode 100644
index 0000000000..6d3006e98c
--- /dev/null
+++ b/e2e/cases/environments/vue-react-plugins/src/vue/index.js
@@ -0,0 +1,6 @@
+import { createApp } from 'vue';
+import A from './A';
+
+console.log(A);
+
+createApp(A).mount('#root');
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 535dc0b980..4d429d55b3 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -48,6 +48,7 @@ export type {
DevConfig,
DistPathConfig,
EnvironmentContext,
+ EnvironmentConfig,
FilenameConfig,
HtmlConfig,
HtmlRspackPlugin,
diff --git a/packages/plugin-preact/src/index.ts b/packages/plugin-preact/src/index.ts
index 51a31cd586..48866b1f4f 100644
--- a/packages/plugin-preact/src/index.ts
+++ b/packages/plugin-preact/src/index.ts
@@ -1,4 +1,4 @@
-import type { RsbuildConfig, RsbuildPlugin, Rspack } from '@rsbuild/core';
+import type { EnvironmentConfig, RsbuildPlugin, Rspack } from '@rsbuild/core';
export type PluginPreactOptions = {
/**
@@ -18,14 +18,14 @@ export const pluginPreact = (
setup(api) {
const { reactAliasesEnabled = true } = options;
- api.modifyRsbuildConfig((userConfig, { mergeRsbuildConfig }) => {
+ api.modifyEnvironmentConfig((userConfig, { mergeEnvironmentConfig }) => {
const reactOptions: Rspack.SwcLoaderTransformConfig['react'] = {
development: process.env.NODE_ENV === 'development',
runtime: 'automatic',
importSource: 'preact',
};
- const extraConfig: RsbuildConfig = {
+ const extraConfig: EnvironmentConfig = {
tools: {
swc: {
jsc: {
@@ -52,7 +52,7 @@ export const pluginPreact = (
};
}
- return mergeRsbuildConfig(extraConfig, userConfig);
+ return mergeEnvironmentConfig(extraConfig, userConfig);
});
},
});
diff --git a/packages/plugin-rem/src/index.ts b/packages/plugin-rem/src/index.ts
index 2495f8340d..3340f75696 100644
--- a/packages/plugin-rem/src/index.ts
+++ b/packages/plugin-rem/src/index.ts
@@ -61,9 +61,9 @@ export const pluginRem = (
});
};
- api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig }) => {
+ api.modifyEnvironmentConfig(async (config, { mergeEnvironmentConfig }) => {
const remPlugin = await getPostCSSPlugin();
- return mergeRsbuildConfig(config, {
+ return mergeEnvironmentConfig(config, {
tools: {
postcss(_, { addPlugins }) {
addPlugins(remPlugin);
diff --git a/packages/plugin-source-build/src/plugin.ts b/packages/plugin-source-build/src/plugin.ts
index 849ac250a3..07feff6e71 100644
--- a/packages/plugin-source-build/src/plugin.ts
+++ b/packages/plugin-source-build/src/plugin.ts
@@ -58,15 +58,17 @@ export function pluginSourceBuild(
setup(api) {
const projectRootPath = api.context.rootPath;
- let projects: Project[] = [];
-
- api.modifyRsbuildConfig(async (config) => {
- projects = await getDependentProjects(projectName || projectRootPath, {
- cwd: projectRootPath,
- recursive: true,
- filter: filterByField(sourceField, true),
- extraMonorepoStrategies,
- });
+ let projects: Project[] | undefined;
+
+ api.modifyEnvironmentConfig(async (config) => {
+ projects =
+ projects ||
+ (await getDependentProjects(projectName || projectRootPath, {
+ cwd: projectRootPath,
+ recursive: true,
+ filter: filterByField(sourceField, true),
+ extraMonorepoStrategies,
+ }));
const includes = await getSourceInclude({
projects,
@@ -105,7 +107,7 @@ export function pluginSourceBuild(
const references = new Set();
- for (const project of projects) {
+ for (const project of projects || []) {
const filePath = path.join(project.dir, 'tsconfig.json');
if (fs.existsSync(filePath)) {
references.add(filePath);
diff --git a/packages/plugin-styled-components/src/index.ts b/packages/plugin-styled-components/src/index.ts
index 43c09c7eda..96340bd4c9 100644
--- a/packages/plugin-styled-components/src/index.ts
+++ b/packages/plugin-styled-components/src/index.ts
@@ -57,39 +57,40 @@ export const pluginStyledComponents = (
});
};
- api.modifyRsbuildConfig({
- order: 'post',
- handler: (userConfig, { mergeRsbuildConfig }) => {
- const targets = userConfig.environments
- ? Object.values(userConfig.environments).map(
- (e) => e.output?.target || userConfig.output?.target || 'web',
- )
- : [userConfig.output?.target || 'web'];
- const useSSR = isServerTarget(targets);
- const mergedOptions = getMergedOptions(useSSR);
- if (!mergedOptions) {
- return userConfig;
- }
+ api.modifyEnvironmentConfig((userConfig, { mergeEnvironmentConfig }) => {
+ const rsbuildConfig = api.getRsbuildConfig();
- const extraConfig: RsbuildConfig = {
- tools: {
- swc: {
- jsc: {
- experimental: {
- plugins: [
- [
- require.resolve('@swc/plugin-styled-components'),
- mergedOptions,
- ],
+ const targets = rsbuildConfig.environments
+ ? Object.values(rsbuildConfig.environments).map(
+ (e) => e.output?.target || userConfig.output?.target || 'web',
+ )
+ : [userConfig.output?.target || 'web'];
+
+ const useSSR = isServerTarget(targets);
+
+ const mergedOptions = getMergedOptions(useSSR);
+ if (!mergedOptions) {
+ return userConfig;
+ }
+
+ const extraConfig: RsbuildConfig = {
+ tools: {
+ swc: {
+ jsc: {
+ experimental: {
+ plugins: [
+ [
+ require.resolve('@swc/plugin-styled-components'),
+ mergedOptions,
],
- },
+ ],
},
},
},
- };
+ },
+ };
- return mergeRsbuildConfig(extraConfig, userConfig);
- },
+ return mergeEnvironmentConfig(extraConfig, userConfig);
});
},
});
diff --git a/packages/plugin-vue/src/index.ts b/packages/plugin-vue/src/index.ts
index bf4739bb45..9ae0b38017 100644
--- a/packages/plugin-vue/src/index.ts
+++ b/packages/plugin-vue/src/index.ts
@@ -1,4 +1,4 @@
-import type { RsbuildConfig, RsbuildPlugin } from '@rsbuild/core';
+import type { EnvironmentConfig, RsbuildPlugin } from '@rsbuild/core';
import { type VueLoaderOptions, VueLoaderPlugin } from 'vue-loader';
import { applySplitChunksRule } from './splitChunks';
@@ -37,8 +37,8 @@ export function pluginVue(options: PluginVueOptions = {}): RsbuildPlugin {
const VUE_REGEXP = /\.vue$/;
const CSS_MODULES_REGEX = /\.modules?\.\w+$/i;
- api.modifyRsbuildConfig((config, { mergeRsbuildConfig }) => {
- const extraConfig: RsbuildConfig = {
+ api.modifyEnvironmentConfig((config, { mergeEnvironmentConfig }) => {
+ const extraConfig: EnvironmentConfig = {
source: {
define: {
// https://link.vuejs.org/feature-flags
@@ -49,10 +49,7 @@ export function pluginVue(options: PluginVueOptions = {}): RsbuildPlugin {
},
};
- const merged = mergeRsbuildConfig(extraConfig, config);
-
- merged.output ||= {};
- merged.output.cssModules ||= {};
+ const merged = mergeEnvironmentConfig(extraConfig, config);
// Support `