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 `