From b287898ff77c9154174e343f25bcb333371eaeb7 Mon Sep 17 00:00:00 2001 From: gaoyuan Date: Tue, 2 Jan 2024 10:49:39 +0800 Subject: [PATCH] fix(uni-builder): compat builder plugin api & type (#5174) --- packages/builder/uni-builder/package.json | 1 + .../builder/uni-builder/src/rspack/index.ts | 28 +++--- .../src/shared/compatLegacyPlugin.ts | 88 +++++++++++++++++++ packages/builder/uni-builder/src/types.ts | 66 ++++++++++++++ .../builder/uni-builder/src/webpack/index.ts | 22 ++--- packages/builder/uni-builder/tests/helper.ts | 9 +- .../builder/uni-builder/tests/legacy.test.ts | 47 ++++++++++ pnpm-lock.yaml | 3 + 8 files changed, 234 insertions(+), 30 deletions(-) create mode 100644 packages/builder/uni-builder/src/shared/compatLegacyPlugin.ts create mode 100644 packages/builder/uni-builder/tests/legacy.test.ts diff --git a/packages/builder/uni-builder/package.json b/packages/builder/uni-builder/package.json index fb85442200f5..7a51c3483430 100644 --- a/packages/builder/uni-builder/package.json +++ b/packages/builder/uni-builder/package.json @@ -73,6 +73,7 @@ "webpack-subresource-integrity": "5.1.0" }, "devDependencies": { + "@modern-js/builder-plugin-node-polyfill": "workspace:*", "@rsbuild/plugin-swc": "0.2.13", "@scripts/build": "workspace:*", "@scripts/vitest-config": "workspace:*", diff --git a/packages/builder/uni-builder/src/rspack/index.ts b/packages/builder/uni-builder/src/rspack/index.ts index 962fa0ca8511..32ef816cefb3 100644 --- a/packages/builder/uni-builder/src/rspack/index.ts +++ b/packages/builder/uni-builder/src/rspack/index.ts @@ -8,12 +8,11 @@ import type { UniBuilderConfig, CreateUniBuilderOptions, CreateBuilderCommonOptions, + OverridesUniBuilderInstance, } from '../types'; import { parseCommonConfig } from '../shared/parseCommonConfig'; -import type { - StartDevServerOptions, - UniBuilderStartServerResult, -} from '../shared/devServer'; +import { compatLegacyPlugin } from '../shared/compatLegacyPlugin'; +import type { StartDevServerOptions } from '../shared/devServer'; export async function parseConfig( uniBuilderConfig: UniBuilderConfig, @@ -56,16 +55,11 @@ export async function parseConfig( }; } -export type UniBuilderInstance = Omit & { - /** - * should be used in conjunction with the upper-layer framework: - * - * missing route.json (required in modern server) - */ - startDevServer: ( - options: StartDevServerOptions, - ) => Promise; -}; +export type UniBuilderInstance = Omit< + RsbuildInstance, + keyof OverridesUniBuilderInstance +> & + OverridesUniBuilderInstance; export async function createRspackBuilder( options: CreateUniBuilderOptions, @@ -86,6 +80,12 @@ export async function createRspackBuilder( return { ...rsbuild, + addPlugins: (plugins, options) => { + const warpedPlugins = plugins.map(plugin => { + return compatLegacyPlugin(plugin, { cwd }); + }); + rsbuild.addPlugins(warpedPlugins, options); + }, startDevServer: async (options: StartDevServerOptions = {}) => { const { startDevServer } = await import('../shared/devServer'); diff --git a/packages/builder/uni-builder/src/shared/compatLegacyPlugin.ts b/packages/builder/uni-builder/src/shared/compatLegacyPlugin.ts new file mode 100644 index 000000000000..3fa97c79f450 --- /dev/null +++ b/packages/builder/uni-builder/src/shared/compatLegacyPlugin.ts @@ -0,0 +1,88 @@ +import type { + UniBuilderPlugin, + UniBuilderPluginAPI, + UniBuilderContext, +} from '../types'; +import type { RsbuildPlugin } from '@rsbuild/core'; +import { logger } from '@rsbuild/shared'; +import { join } from 'path'; + +function addDeprecatedWarning( + pluginName: string, + name: string, + newName?: string, +) { + logger.warn( + `Plugin(${pluginName})'s api '${name}' is deprecated${ + newName ? `, please use '${newName}' instead.` : '.' + }`, + ); +} +export function compatLegacyPlugin( + plugin: UniBuilderPlugin, + extraInfo: { + cwd: string; + }, +): RsbuildPlugin { + return { + ...plugin, + setup: api => { + const builderContext = new Proxy(api.context, { + get(target, prop: keyof UniBuilderContext) { + switch (prop) { + case 'target': + addDeprecatedWarning( + plugin.name, + 'context.target', + 'context.targets', + ); + return target.targets; + case 'srcPath': + addDeprecatedWarning(plugin.name, 'context.srcPath'); + return join(extraInfo.cwd, 'src'); + case 'framework': + addDeprecatedWarning(plugin.name, 'context.framework'); + return ''; + default: { + if (prop in target) { + return target[prop]; + } else { + return undefined; + } + } + } + }, + set(_target, prop: keyof UniBuilderContext) { + logger.error( + `Context is readonly, you can not assign to the "context.${prop}" prop.`, + ); + return true; + }, + }) as UniBuilderContext; + + const legacyAPI: UniBuilderPluginAPI = { + ...api, + context: builderContext, + getBuilderConfig: () => { + addDeprecatedWarning( + plugin.name, + 'getBuilderConfig', + 'getRsbuildConfig', + ); + return api.getRsbuildConfig(); + }, + modifyBuilderConfig: fn => { + api.modifyRsbuildConfig((config, { mergeRsbuildConfig }) => { + addDeprecatedWarning( + plugin.name, + 'modifyBuilderConfig', + 'modifyRsbuildConfig', + ); + return fn(config, { mergeBuilderConfig: mergeRsbuildConfig }); + }); + }, + }; + return plugin.setup(legacyAPI); + }, + }; +} diff --git a/packages/builder/uni-builder/src/types.ts b/packages/builder/uni-builder/src/types.ts index 71c880fe3403..aeb144cb1d9e 100644 --- a/packages/builder/uni-builder/src/types.ts +++ b/packages/builder/uni-builder/src/types.ts @@ -10,6 +10,8 @@ import type { DevConfig, RequestHandler, RsbuildEntry, + PromiseOrNot, + RsbuildPluginAPI, } from '@rsbuild/shared'; import type { RsbuildConfig } from '@rsbuild/core'; import type { PluginAssetsRetryOptions } from '@rsbuild/plugin-assets-retry'; @@ -24,6 +26,10 @@ import type { PluginCheckSyntaxOptions } from '@rsbuild/plugin-check-syntax'; import type { PluginPugOptions } from '@rsbuild/plugin-pug'; import type { PluginBabelOptions } from '@rsbuild/plugin-babel'; import type { AliasOption } from '@modern-js/utils'; +import type { + StartDevServerOptions, + UniBuilderStartServerResult, +} from './shared/devServer'; export type CreateBuilderCommonOptions = { entry?: RsbuildEntry; @@ -265,6 +271,64 @@ export type SriOptions = { hashLoading?: 'eager' | 'lazy'; }; +export type OverridesUniBuilderInstance = { + addPlugins: ( + plugins: UniBuilderPlugin[], + options?: { + before?: string; + }, + ) => void; + /** + * should be used in conjunction with the upper-layer framework: + * + * missing route.json (required in modern server) + */ + startDevServer: ( + options: StartDevServerOptions, + ) => Promise; +}; + +export type UniBuilderContext = RsbuildPluginAPI['context'] & { + target: RsbuildPluginAPI['context']['targets']; + framework: string; + srcPath: string; + entry: Record; +}; + +export type UniBuilderPluginAPI = { + [key in keyof RsbuildPluginAPI]: RsbuildPluginAPI[key]; +} & { + /** The following APIs only type incompatibility */ + onBeforeCreateCompiler: (fn: any) => void; + onAfterCreateCompiler: (fn: any) => void; + onBeforeBuild: (fn: any) => void; + modifyBundlerChain: (fn: any) => void; + getNormalizedConfig: () => any; + + /** The following APIs need to be compatible */ + context: UniBuilderContext; + getBuilderConfig: () => Readonly; + modifyBuilderConfig: ( + fn: ( + config: any, + utils: { + mergeBuilderConfig: (...configs: T[]) => T; + }, + ) => PromiseOrNot, + ) => void; +}; + +/** + * compat legacy modern.js builder plugin + */ +export type UniBuilderPlugin = { + name: string; + setup: (api: UniBuilderPluginAPI) => PromiseOrNot; + pre?: string[]; + post?: string[]; + remove?: string[]; +}; + export type UniBuilderConfig = { dev?: RsbuildConfig['dev']; html?: RsbuildConfig['html']; @@ -273,4 +337,6 @@ export type UniBuilderConfig = { security?: RsbuildConfig['security']; tools?: RsbuildConfig['tools']; source?: Omit, 'alias'>; + // plugins is a new field, should avoid adding modern plugin by mistake + plugins?: RsbuildConfig['plugins']; } & UniBuilderExtraConfig; diff --git a/packages/builder/uni-builder/src/webpack/index.ts b/packages/builder/uni-builder/src/webpack/index.ts index 66f901c3a467..d2fe33a8a2cb 100644 --- a/packages/builder/uni-builder/src/webpack/index.ts +++ b/packages/builder/uni-builder/src/webpack/index.ts @@ -9,15 +9,14 @@ import type { UniBuilderConfig, CreateUniBuilderOptions, CreateBuilderCommonOptions, + OverridesUniBuilderInstance, } from '../types'; import { parseCommonConfig } from '../shared/parseCommonConfig'; +import { compatLegacyPlugin } from '../shared/compatLegacyPlugin'; import { pluginModuleScopes } from './plugins/moduleScopes'; import { pluginBabel } from './plugins/babel'; import { pluginReact } from './plugins/react'; -import type { - StartDevServerOptions, - UniBuilderStartServerResult, -} from '../shared/devServer'; +import type { StartDevServerOptions } from '../shared/devServer'; export async function parseConfig( uniBuilderConfig: UniBuilderConfig, @@ -82,12 +81,9 @@ export async function parseConfig( export type UniBuilderWebpackInstance = Omit< RsbuildInstance>, - 'startDevServer' -> & { - startDevServer: ( - options: StartDevServerOptions, - ) => Promise; -}; + keyof OverridesUniBuilderInstance +> & + OverridesUniBuilderInstance; export async function createWebpackBuilder( options: CreateUniBuilderOptions, @@ -121,6 +117,12 @@ export async function createWebpackBuilder( return { ...rsbuild, + addPlugins: (plugins, options) => { + const warpedPlugins = plugins.map(plugin => { + return compatLegacyPlugin(plugin, { cwd }); + }); + rsbuild.addPlugins(warpedPlugins, options); + }, startDevServer: async (options: StartDevServerOptions = {}) => { const { startDevServer } = await import('../shared/devServer'); diff --git a/packages/builder/uni-builder/tests/helper.ts b/packages/builder/uni-builder/tests/helper.ts index 4fed483fecb5..f9511dff6d67 100644 --- a/packages/builder/uni-builder/tests/helper.ts +++ b/packages/builder/uni-builder/tests/helper.ts @@ -1,8 +1,5 @@ -import type { - RsbuildInstance, - RspackConfig, - RspackRule, -} from '@rsbuild/shared'; +import type { RspackConfig, RspackRule } from '@rsbuild/shared'; +import type { UniBuilderInstance } from '../src'; export function matchRules({ config, @@ -28,7 +25,7 @@ export function matchRules({ }); } -export const unwrapConfig = async (rsbuild: RsbuildInstance) => { +export const unwrapConfig = async (rsbuild: UniBuilderInstance) => { const configs = await rsbuild.initConfigs(); return configs[0]; }; diff --git a/packages/builder/uni-builder/tests/legacy.test.ts b/packages/builder/uni-builder/tests/legacy.test.ts new file mode 100644 index 000000000000..8423fddc6e9a --- /dev/null +++ b/packages/builder/uni-builder/tests/legacy.test.ts @@ -0,0 +1,47 @@ +import { describe, it, expect } from 'vitest'; +import { builderPluginNodePolyfill } from '@modern-js/builder-plugin-node-polyfill'; +import { createUniBuilder } from '../src'; + +describe('uni-builder legacy plugins', () => { + it('legacy plugin should works well', async () => { + const rsbuild = await createUniBuilder({ + bundlerType: 'rspack', + config: {}, + cwd: '', + }); + + rsbuild.addPlugins([ + // plugin type check should passed + builderPluginNodePolyfill(), + { + name: 'builder-plugin-test', + setup: api => { + api.modifyBuilderConfig((config, { mergeBuilderConfig }) => { + const builderConfig = api.getBuilderConfig(); + + expect(api.context.target).toBe(api.context.targets); + + expect(builderConfig.source).toBeDefined(); + + return mergeBuilderConfig(config, { + tools: { + bundlerChain: (chain: any) => { + chain.devtool(false); + }, + }, + }); + }); + }, + }, + ]); + + const { + origin: { bundlerConfigs }, + } = await rsbuild.inspectConfig(); + + expect(bundlerConfigs[0].devtool).toBeFalsy(); + expect( + Object.keys(bundlerConfigs[0].resolve!.fallback!).length, + ).toBeGreaterThan(1); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08596ddbaecf..7f75c409ffc6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -865,6 +865,9 @@ importers: specifier: 5.1.0 version: 5.1.0(html-webpack-plugin@5.5.3)(webpack@5.89.0) devDependencies: + '@modern-js/builder-plugin-node-polyfill': + specifier: workspace:* + version: link:../plugin-node-polyfill '@rsbuild/plugin-swc': specifier: 0.2.13 version: 0.2.13