diff --git a/e2e/cases/async-plugin/index.test.ts b/e2e/cases/async-plugin/index.test.ts new file mode 100644 index 0000000000..5797d9abb5 --- /dev/null +++ b/e2e/cases/async-plugin/index.test.ts @@ -0,0 +1,42 @@ +import { expect } from '@playwright/test'; +import { build, gotoPage, rspackOnlyTest } from '@e2e/helper'; +import type { RsbuildPlugin } from '@rsbuild/core'; + +const asyncPlugin = async (): Promise => { + await new Promise((resolve) => { + setTimeout(resolve); + }); + + return { + name: 'async-plugin', + setup(api) { + api.modifyRsbuildConfig((config, { mergeRsbuildConfig }) => { + return mergeRsbuildConfig(config, { + source: { + define: { + ENABLE_TEST: JSON.stringify(true), + }, + }, + }); + }); + }, + }; +}; + +rspackOnlyTest( + 'should allow to register async plugin in plugins field', + async ({ page }) => { + const rsbuild = await build({ + cwd: __dirname, + runServer: true, + plugins: [asyncPlugin()], + }); + + await gotoPage(page, rsbuild); + + const testEl = page.locator('#test-el'); + await expect(testEl).toHaveText('aaaaa'); + + await rsbuild.close(); + }, +); diff --git a/e2e/cases/async-plugin/src/index.js b/e2e/cases/async-plugin/src/index.js new file mode 100644 index 0000000000..547c2e44b0 --- /dev/null +++ b/e2e/cases/async-plugin/src/index.js @@ -0,0 +1,12 @@ +if (ENABLE_TEST === true) { + const test = document.createElement('div'); + test.id = 'test-el'; + test.innerHTML = 'aaaaa'; + document.body.appendChild(test); +} + +const testEl = document.createElement('div'); +testEl.id = 'test'; +testEl.innerHTML = 'Hello Rsbuild!'; + +document.body.appendChild(testEl); diff --git a/e2e/scripts/shared.ts b/e2e/scripts/shared.ts index e57ff7c6d3..bab88d8a52 100644 --- a/e2e/scripts/shared.ts +++ b/e2e/scripts/shared.ts @@ -8,6 +8,7 @@ import { pluginSwc } from '@rsbuild/plugin-swc'; import type { RsbuildConfig, RsbuildPlugin, + RsbuildPlugins, CreateRsbuildOptions, } from '@rsbuild/core'; import type { Page } from 'playwright'; @@ -33,31 +34,28 @@ const noop = async () => {}; export const createRsbuild = async ( rsbuildOptions: CreateRsbuildOptions, - plugins: RsbuildPlugin[] = [], + plugins: RsbuildPlugins = [], ) => { const { createRsbuild } = await import('@rsbuild/core'); + rsbuildOptions.rsbuildConfig ||= {}; + rsbuildOptions.rsbuildConfig.plugins = [ + ...(rsbuildOptions.rsbuildConfig.plugins || []), + ...(plugins || []), + ]; + if (process.env.PROVIDE_TYPE === 'rspack') { const rsbuild = await createRsbuild(rsbuildOptions); - if (plugins) { - rsbuild.addPlugins(plugins); - } - return rsbuild; } const { webpackProvider } = await import('@rsbuild/webpack'); - rsbuildOptions.rsbuildConfig ||= {}; rsbuildOptions.rsbuildConfig.provider = webpackProvider; const rsbuild = await createRsbuild(rsbuildOptions); - if (plugins) { - rsbuild.addPlugins(plugins); - } - const swc = pluginSwc(); if (!rsbuild.isPluginExists(swc.name)) { rsbuild.addPlugins([swc]); @@ -177,7 +175,7 @@ export async function build({ runServer = false, ...options }: CreateRsbuildOptions & { - plugins?: RsbuildPlugin[]; + plugins?: RsbuildPlugins; runServer?: boolean; }) { process.env.NODE_ENV = 'production'; diff --git a/packages/core/src/createRsbuild.ts b/packages/core/src/createRsbuild.ts index 0a2d0acc8a..dd5c9e3a03 100644 --- a/packages/core/src/createRsbuild.ts +++ b/packages/core/src/createRsbuild.ts @@ -78,7 +78,8 @@ export async function createRsbuild( }; if (rsbuildConfig.plugins) { - rsbuild.addPlugins(rsbuildConfig.plugins); + const plugins = await Promise.all(rsbuildConfig.plugins); + rsbuild.addPlugins(plugins); } return rsbuild; diff --git a/packages/core/src/pluginManager.ts b/packages/core/src/pluginManager.ts index 968285aa76..f804b0f46a 100644 --- a/packages/core/src/pluginManager.ts +++ b/packages/core/src/pluginManager.ts @@ -1,8 +1,8 @@ import { color, debug, logger, isFunction } from '@rsbuild/shared'; import type { + Falsy, PluginManager, RsbuildPlugin, - RsbuildPlugins, RsbuildPluginAPI, BundlerPluginInstance, } from '@rsbuild/shared'; @@ -54,7 +54,7 @@ export function createPluginManager(): PluginManager { let plugins: RsbuildPlugin[] = []; const addPlugins = ( - newPlugins: RsbuildPlugins, + newPlugins: Array, options?: { before?: string }, ) => { const { before } = options || {}; diff --git a/packages/document/docs/en/config/plugins.mdx b/packages/document/docs/en/config/plugins.mdx index 0be4a902f1..b888e467ae 100644 --- a/packages/document/docs/en/config/plugins.mdx +++ b/packages/document/docs/en/config/plugins.mdx @@ -1,10 +1,25 @@ # plugins -Used to register Rsbuild plugins. Please check the [Plugin List](/plugins/list/index) to discover available plugins. +Used to register Rsbuild plugins. + +Async plugin (promise) in the plugins array will be resolved, and falsy values will be ignored. + +- **Type:** + +```ts +type Falsy = false | null | undefined; + +type RsbuildPlugins = ( + | RsbuildPlugin + | Falsy + | Promise +)[]; +``` -- **Type:** `RsbuildPlugin[]` - **Default:** `undefined` +> Please check out the [Plugin List](/plugins/list/index) page to discover all available plugins. + ## Example For example, register the Stylus plugin in Rsbuild. diff --git a/packages/document/docs/zh/config/plugins.mdx b/packages/document/docs/zh/config/plugins.mdx index 334bd19118..8c9cba02a9 100644 --- a/packages/document/docs/zh/config/plugins.mdx +++ b/packages/document/docs/zh/config/plugins.mdx @@ -1,10 +1,25 @@ # plugins -用于注册 Rsbuild 插件,请查看[插件列表](/plugins/list/index) 来发现可用的插件。 +用于注册 Rsbuild 插件。 + +插件数组中的异步插件(promise)会自动被 resolve,falsy value 会被忽略。 + +- **类型:** + +```ts +type Falsy = false | null | undefined; + +type RsbuildPlugins = ( + | RsbuildPlugin + | Falsy + | Promise +)[]; +``` -- **类型:** `RsbuildPlugin[]` - **默认值:** `undefined` +> 请查看[插件列表](/plugins/list/index)页面来发现所有可用的插件。 + ## 示例 比如注册 Rsbuild 的 Stylus 插件。 @@ -64,6 +79,12 @@ export default defineConfig({ }); ``` +## 异步插件 + +```ts +import { RsbuildPlugin } from '@rsbuild/core'; +``` + ## Rspack 插件 `plugins` 选项用于注册 Rsbuild 插件,如果你需要注册 Rspack 或 Webpack 插件,请使用 [tools.rspack](/config/tools/rspack)。 diff --git a/packages/shared/src/types/plugin.ts b/packages/shared/src/types/plugin.ts index e69cc359fb..44758aa6ed 100644 --- a/packages/shared/src/types/plugin.ts +++ b/packages/shared/src/types/plugin.ts @@ -73,7 +73,10 @@ export type ModifyWebpackConfigFn = ( export type PluginManager = { readonly plugins: RsbuildPlugin[]; - addPlugins: (plugins: RsbuildPlugins, options?: { before?: string }) => void; + addPlugins: ( + plugins: Array, + options?: { before?: string }, + ) => void; removePlugins: (pluginNames: string[]) => void; isPluginExists: (pluginName: string) => boolean; /** The plugin API. */ @@ -108,7 +111,11 @@ export type RsbuildPlugin = { remove?: string[]; }; -export type RsbuildPlugins = (RsbuildPlugin | Falsy)[]; +export type RsbuildPlugins = ( + | RsbuildPlugin + | Falsy + | Promise +)[]; type PluginsFn = T extends undefined ? () => Promise