From f7829c4964e4e378560f79e2d1f56e0c390703de Mon Sep 17 00:00:00 2001 From: "gaoyuan.1226" Date: Thu, 20 Jun 2024 17:06:04 +0800 Subject: [PATCH 1/5] feat: support apply environment html config --- packages/core/src/initPlugins.ts | 33 ++++++++++---- packages/core/src/plugins/html.ts | 43 +++++++++++-------- packages/core/src/plugins/manifest.ts | 4 +- packages/core/src/plugins/minimize.ts | 3 +- packages/core/src/rspack/HtmlBasicPlugin.ts | 5 +++ .../tests/__snapshots__/builder.test.ts.snap | 1 + .../tests/__snapshots__/html.test.ts.snap | 9 ++++ .../__snapshots__/inlineChunk.test.ts.snap | 2 + packages/shared/src/types/hooks.ts | 2 + packages/shared/src/types/plugin.ts | 2 +- packages/shared/src/utils.ts | 8 +++- website/docs/en/plugins/dev/hooks.mdx | 2 + website/docs/zh/plugins/dev/hooks.mdx | 4 ++ 13 files changed, 87 insertions(+), 31 deletions(-) diff --git a/packages/core/src/initPlugins.ts b/packages/core/src/initPlugins.ts index fceb0978b4..f79a4ec61c 100644 --- a/packages/core/src/initPlugins.ts +++ b/packages/core/src/initPlugins.ts @@ -8,6 +8,7 @@ import type { TransformFn, TransformHandler, } from '@rsbuild/shared'; +import { isHtmlDisabled } from '@rsbuild/shared'; import type { Compiler } from '@rspack/core'; import { LOADER_PATH } from './constants'; import { createPublicContext } from './createContext'; @@ -16,7 +17,7 @@ import type { InternalContext, NormalizedConfig } from './types'; export function getHTMLPathByEntry( entryName: string, - config: NormalizedConfig, + config: NormalizedEnvironmentConfig, ) { const filename = config.html.outputStructure === 'flat' @@ -97,14 +98,30 @@ export function getPluginAPI({ throw new Error('`getRsbuildConfig` get an invalid type param.'); }) as GetRsbuildConfig; - const getHTMLPaths = () => { - return Object.keys(context.entry).reduce>( - (prev, key) => { - prev[key] = getHTMLPathByEntry(key, getNormalizedConfig()); + const getHTMLPaths = (options?: { environment: string }) => { + const getEnvironmentHTMLPaths = (environment: string) => { + const config = getNormalizedConfig({ environment }); + + if (isHtmlDisabled(config, config.output.target)) { + return {}; + } + return Object.keys(context.environments[environment].entry).reduce< + Record + >((prev, key) => { + prev[key] = getHTMLPathByEntry(key, config); return prev; - }, - {}, - ); + }, {}); + }; + + if (options?.environment) { + return getEnvironmentHTMLPaths(options?.environment); + } + return Object.keys(context.environments).reduce((prev, environment) => { + return { + ...getEnvironmentHTMLPaths(environment), + prev, + }; + }, {}); }; const exposed: Array<{ id: string | symbol; api: any }> = []; diff --git a/packages/core/src/plugins/html.ts b/packages/core/src/plugins/html.ts index 31b120b96b..2902d04e7a 100644 --- a/packages/core/src/plugins/html.ts +++ b/packages/core/src/plugins/html.ts @@ -12,7 +12,7 @@ import type { HTMLPluginOptions, HtmlConfig, ModifyHTMLTagsFn, - NormalizedConfig, + NormalizedEnvironmentConfig, RsbuildPluginAPI, } from '@rsbuild/shared'; import type { EntryDescription } from '@rspack/core'; @@ -28,7 +28,7 @@ import { parseMinifyOptions } from './minimize'; function applyRemoveConsole( options: MinifyJSOptions, - config: NormalizedConfig, + config: NormalizedEnvironmentConfig, ) { const { removeConsole } = config.performance; const compressOptions = @@ -50,7 +50,7 @@ function applyRemoveConsole( return options; } -function getTerserMinifyOptions(config: NormalizedConfig) { +function getTerserMinifyOptions(config: NormalizedEnvironmentConfig) { const options: MinifyJSOptions = { mangle: { safari10: true, @@ -70,7 +70,7 @@ function getTerserMinifyOptions(config: NormalizedConfig) { export async function getHtmlMinifyOptions( isProd: boolean, - config: NormalizedConfig, + config: NormalizedEnvironmentConfig, ) { if ( !isProd || @@ -102,7 +102,10 @@ export async function getHtmlMinifyOptions( : htmlMinifyDefaultOptions; } -export function getTitle(entryName: string, config: NormalizedConfig) { +export function getTitle( + entryName: string, + config: NormalizedEnvironmentConfig, +) { return reduceConfigsMergeContext({ initial: '', config: config.html.title, @@ -110,7 +113,10 @@ export function getTitle(entryName: string, config: NormalizedConfig) { }); } -export function getInject(entryName: string, config: NormalizedConfig) { +export function getInject( + entryName: string, + config: NormalizedEnvironmentConfig, +) { return reduceConfigsMergeContext({ initial: 'head', config: config.html.inject, @@ -122,7 +128,7 @@ const existTemplatePath: string[] = []; export async function getTemplate( entryName: string, - config: NormalizedConfig, + config: NormalizedEnvironmentConfig, rootPath: string, ): Promise<{ templatePath: string; templateContent?: string }> { const DEFAULT_TEMPLATE = path.resolve(STATIC_PATH, 'template.html'); @@ -201,7 +207,7 @@ export function getMetaTags( function getTemplateParameters( entryName: string, - config: NormalizedConfig, + config: NormalizedEnvironmentConfig, assetPrefix: string, ): HTMLPluginOptions['templateParameters'] { return (compilation, assets, assetTags, pluginOptions) => { @@ -252,8 +258,11 @@ function getChunks( return chunks; } -const getTagConfig = (api: RsbuildPluginAPI): TagConfig | undefined => { - const config = api.getNormalizedConfig(); +const getTagConfig = ( + api: RsbuildPluginAPI, + environment: string, +): TagConfig | undefined => { + const config = api.getNormalizedConfig({ environment }); const tags = castArray(config.html.tags).filter(Boolean); // skip if options is empty. @@ -274,8 +283,8 @@ export const pluginHtml = (modifyTagsFn?: ModifyHTMLTagsFn): RsbuildPlugin => ({ setup(api) { api.modifyBundlerChain( - async (chain, { HtmlPlugin, isProd, CHAIN_ID, target }) => { - const config = api.getNormalizedConfig(); + async (chain, { HtmlPlugin, isProd, CHAIN_ID, target, environment }) => { + const config = api.getNormalizedConfig({ environment }); // if html is disabled or target is server, skip html plugin if (isHtmlDisabled(config, target)) { @@ -286,7 +295,7 @@ export const pluginHtml = (modifyTagsFn?: ModifyHTMLTagsFn): RsbuildPlugin => ({ const assetPrefix = getPublicPathFromChain(chain, false); const entries = chain.entryPoints.entries() || {}; const entryNames = Object.keys(entries); - const htmlPaths = api.getHTMLPaths(); + const htmlPaths = api.getHTMLPaths({ environment }); const htmlInfoMap: Record = {}; const finalOptions = await Promise.all( @@ -338,7 +347,7 @@ export const pluginHtml = (modifyTagsFn?: ModifyHTMLTagsFn): RsbuildPlugin => ({ htmlInfo.templateContent = templateContent; } - const tagConfig = getTagConfig(api); + const tagConfig = getTagConfig(api, environment); if (tagConfig) { htmlInfo.tagConfig = tagConfig; } @@ -379,7 +388,7 @@ export const pluginHtml = (modifyTagsFn?: ModifyHTMLTagsFn): RsbuildPlugin => ({ chain .plugin(CHAIN_ID.PLUGIN.HTML_BASIC) - .use(HtmlBasicPlugin, [htmlInfoMap, modifyTagsFn]); + .use(HtmlBasicPlugin, [htmlInfoMap, environment, modifyTagsFn]); if (config.html) { const { appIcon, crossorigin } = config.html; @@ -411,8 +420,8 @@ export const pluginHtml = (modifyTagsFn?: ModifyHTMLTagsFn): RsbuildPlugin => ({ api.modifyHTMLTags({ // ensure `crossorigin` and `nonce` can be applied to all tags order: 'post', - handler: ({ headTags, bodyTags }) => { - const config = api.getNormalizedConfig(); + handler: ({ headTags, bodyTags }, { environment }) => { + const config = api.getNormalizedConfig({ environment }); const { crossorigin } = config.html; const allTags = [...headTags, ...bodyTags]; diff --git a/packages/core/src/plugins/manifest.ts b/packages/core/src/plugins/manifest.ts index 76286859cd..d0fe2517e3 100644 --- a/packages/core/src/plugins/manifest.ts +++ b/packages/core/src/plugins/manifest.ts @@ -143,7 +143,7 @@ export const pluginManifest = (): RsbuildPlugin => ({ name: 'rsbuild:manifest', setup(api) { - api.modifyBundlerChain(async (chain, { CHAIN_ID }) => { + api.modifyBundlerChain(async (chain, { CHAIN_ID, environment }) => { const { output: { manifest }, } = api.getNormalizedConfig(); @@ -156,7 +156,7 @@ export const pluginManifest = (): RsbuildPlugin => ({ typeof manifest === 'string' ? manifest : 'manifest.json'; const { RspackManifestPlugin } = await import('rspack-manifest-plugin'); - const htmlPaths = api.getHTMLPaths(); + const htmlPaths = api.getHTMLPaths({ environment }); chain.plugin(CHAIN_ID.PLUGIN.MANIFEST).use(RspackManifestPlugin, [ { diff --git a/packages/core/src/plugins/minimize.ts b/packages/core/src/plugins/minimize.ts index 62c9956c2b..563bbe7718 100644 --- a/packages/core/src/plugins/minimize.ts +++ b/packages/core/src/plugins/minimize.ts @@ -2,6 +2,7 @@ import { CHAIN_ID, type HTMLPluginOptions, type NormalizedConfig, + type NormalizedEnvironmentConfig, deepmerge, isObject, } from '@rsbuild/shared'; @@ -58,7 +59,7 @@ export const getSwcMinimizerOptions = ( }; export const parseMinifyOptions = ( - config: NormalizedConfig, + config: NormalizedEnvironmentConfig, isProd = true, ): { minifyJs: boolean; diff --git a/packages/core/src/rspack/HtmlBasicPlugin.ts b/packages/core/src/rspack/HtmlBasicPlugin.ts index c478053398..52e0cd4d78 100644 --- a/packages/core/src/rspack/HtmlBasicPlugin.ts +++ b/packages/core/src/rspack/HtmlBasicPlugin.ts @@ -236,15 +236,19 @@ const addFavicon = (headTags: HtmlTagObject[], favicon?: string) => { export class HtmlBasicPlugin { readonly name: string; + readonly environment: string; + readonly options: HtmlBasicPluginOptions; readonly modifyTagsFn?: ModifyHTMLTagsFn; constructor( options: HtmlBasicPluginOptions, + environment: string, modifyTagsFn?: ModifyHTMLTagsFn, ) { this.name = 'HtmlBasicPlugin'; + this.environment = environment; this.options = options; this.modifyTagsFn = modifyTagsFn; } @@ -280,6 +284,7 @@ export class HtmlBasicPlugin { compilation, assetPrefix: data.publicPath, filename: data.outputName, + environment: this.environment, }) : tags; diff --git a/packages/core/tests/__snapshots__/builder.test.ts.snap b/packages/core/tests/__snapshots__/builder.test.ts.snap index 096fcf7f6b..9f9bcfb5b7 100644 --- a/packages/core/tests/__snapshots__/builder.test.ts.snap +++ b/packages/core/tests/__snapshots__/builder.test.ts.snap @@ -410,6 +410,7 @@ exports[`should use rspack as default bundler > apply rspack correctly 1`] = ` "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": [Function], "name": "HtmlBasicPlugin", "options": { diff --git a/packages/core/tests/__snapshots__/html.test.ts.snap b/packages/core/tests/__snapshots__/html.test.ts.snap index cc47ef9981..3fa631f2c7 100644 --- a/packages/core/tests/__snapshots__/html.test.ts.snap +++ b/packages/core/tests/__snapshots__/html.test.ts.snap @@ -116,6 +116,7 @@ exports[`plugin-html > should allow to configure html.tags 1`] = ` "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": undefined, "name": "HtmlBasicPlugin", "options": { @@ -192,6 +193,7 @@ exports[`plugin-html > should allow to modify plugin options by tools.htmlPlugin "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": undefined, "name": "HtmlBasicPlugin", "options": { @@ -264,6 +266,7 @@ exports[`plugin-html > should allow to set favicon by html.favicon option 1`] = "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": undefined, "name": "HtmlBasicPlugin", "options": { @@ -335,6 +338,7 @@ exports[`plugin-html > should allow to set inject by html.inject option 1`] = ` "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": undefined, "name": "HtmlBasicPlugin", "options": { @@ -444,6 +448,7 @@ exports[`plugin-html > should enable minify in production 1`] = ` "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": undefined, "name": "HtmlBasicPlugin", "options": { @@ -515,6 +520,7 @@ exports[`plugin-html > should register html plugin correctly 1`] = ` "version": 5, }, HtmlBasicPlugin { + "environment": "web", "modifyTagsFn": undefined, "name": "HtmlBasicPlugin", "options": { @@ -586,6 +592,7 @@ exports[`plugin-html > should stop injecting