From e74f7e5278332156fe6821c4426b408087895b8a Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Wed, 20 May 2026 16:32:06 +0800 Subject: [PATCH 1/5] feat!: refine bundler options --- .../bundler-vite/src/resolveViteConfig.ts | 21 +++++++++++-- packages/bundler-vite/src/types.ts | 30 +++++++++++++++++++ packages/bundler-vite/src/viteBundler.ts | 2 ++ .../src/resolveWebpackConfig.ts | 8 ++--- packages/bundler-webpack/src/types.ts | 6 +++- .../bundler-webpack/src/webpackBundler.ts | 2 ++ packages/core/src/types/bundler.ts | 10 +++++++ packages/core/src/types/helpers.ts | 14 +++++++++ 8 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 packages/core/src/types/helpers.ts diff --git a/packages/bundler-vite/src/resolveViteConfig.ts b/packages/bundler-vite/src/resolveViteConfig.ts index 63f979519a..1bcee8e80c 100644 --- a/packages/bundler-vite/src/resolveViteConfig.ts +++ b/packages/bundler-vite/src/resolveViteConfig.ts @@ -22,8 +22,9 @@ export const resolveViteConfig = ({ options: ViteBundlerOptions isBuild: boolean isServer: boolean -}): InlineConfig => - mergeConfig( +}): InlineConfig => { + // generate base vite config + let viteConfig = mergeConfig( { clearScreen: false, configFile: false, @@ -43,3 +44,19 @@ export const resolveViteConfig = ({ // some vite options would not take effect inside a plugin, so we still need to merge them here in addition to userConfigPlugin options.viteOptions ?? {}, ) + + // allow modifying vite config via `configureVite` + const configureViteResult = options.configureVite?.( + viteConfig, + isServer, + isBuild, + mergeConfig, + ) + + // if `configureVite` returns a configuration object, use it as the new vite config + if (configureViteResult) { + viteConfig = configureViteResult + } + + return viteConfig +} diff --git a/packages/bundler-vite/src/types.ts b/packages/bundler-vite/src/types.ts index dde557c177..72c5a85fde 100644 --- a/packages/bundler-vite/src/types.ts +++ b/packages/bundler-vite/src/types.ts @@ -6,6 +6,36 @@ import type { InlineConfig } from 'vite' * Options for bundler-vite */ export interface ViteBundlerOptions extends BundlerOptions { + /** + * Vite options + */ + /** + * Vite options + */ viteOptions?: InlineConfig + /** + * Options for @vitejs/plugin-vue + */ + /** + * Options for @vitejs/plugin-vue + */ vuePluginOptions?: VuePluginOptions + /** + * Modify Vite config + * + * @param config - Vite config + * @param isServer - Whether it is server bundle + * @param isBuild - Whether in build mode + * @param mergeConfig - Vite's mergeConfig function, in case you want to use it to merge config + * @returns New Vite config + */ + configureVite?: ( + config: InlineConfig, + isServer: boolean, + isBuild: boolean, + mergeConfig: ( + defaultConfig: InlineConfig, + overrideConfig: InlineConfig, + ) => InlineConfig, + ) => InlineConfig | undefined } diff --git a/packages/bundler-vite/src/viteBundler.ts b/packages/bundler-vite/src/viteBundler.ts index d856918a7d..096cfb5e2e 100644 --- a/packages/bundler-vite/src/viteBundler.ts +++ b/packages/bundler-vite/src/viteBundler.ts @@ -1,4 +1,5 @@ import type { Bundler } from '@vuepress/core' +import { mergeConfig } from 'vite' import { build } from './build/index.js' import { dev } from './dev.js' @@ -8,4 +9,5 @@ export const viteBundler = (options: ViteBundlerOptions = {}): Bundler => ({ name: '@vuepress/bundler-vite', dev: async (app) => dev(options, app), build: async (app) => build(options, app), + mergeConfig: mergeConfig as Bundler['mergeConfig'], }) diff --git a/packages/bundler-webpack/src/resolveWebpackConfig.ts b/packages/bundler-webpack/src/resolveWebpackConfig.ts index a77970f605..618b6c4a0e 100644 --- a/packages/bundler-webpack/src/resolveWebpackConfig.ts +++ b/packages/bundler-webpack/src/resolveWebpackConfig.ts @@ -19,19 +19,19 @@ export const resolveWebpackConfig = ({ options.chainWebpack?.(config, isServer, isBuild) // generate webpack config from webpack-v5-chain - const webpackConfig = config.toConfig() + let webpackConfig = config.toConfig() // allow modifying webpack config via `configureWebpack` const configureWebpackResult = options.configureWebpack?.( webpackConfig, isServer, isBuild, + merge, ) - // if `configureWebpack` returns a configuration object, - // use webpack-merge to merge it + // if `configureWebpack` returns a configuration object, use this object as the new webpack config if (configureWebpackResult) { - return merge(webpackConfig, configureWebpackResult) + webpackConfig = configureWebpackResult } return webpackConfig diff --git a/packages/bundler-webpack/src/types.ts b/packages/bundler-webpack/src/types.ts index de2779bb61..2505c180e2 100644 --- a/packages/bundler-webpack/src/types.ts +++ b/packages/bundler-webpack/src/types.ts @@ -25,7 +25,11 @@ export interface WebpackBundlerOptions extends BundlerOptions { config: WebpackConfiguration, isServer: boolean, isBuild: boolean, - ) => WebpackConfiguration | void + mergeConfig: ( + firstConfiguration: Config, + ...configurations: Config[] + ) => Config, + ) => WebpackConfiguration | undefined /** * use webpack-v5-chain to set webpack config diff --git a/packages/bundler-webpack/src/webpackBundler.ts b/packages/bundler-webpack/src/webpackBundler.ts index 2019711e45..b132ccbef5 100644 --- a/packages/bundler-webpack/src/webpackBundler.ts +++ b/packages/bundler-webpack/src/webpackBundler.ts @@ -1,4 +1,5 @@ import type { Bundler } from '@vuepress/core' +import { merge } from 'webpack-merge' import { build } from './build/index.js' import { dev } from './dev/index.js' @@ -10,4 +11,5 @@ export const webpackBundler = ( name: '@vuepress/bundler-webpack', dev: async (app) => dev(options, app), build: async (app) => build(options, app), + mergeConfig: merge, }) diff --git a/packages/core/src/types/bundler.ts b/packages/core/src/types/bundler.ts index 0f8e64fa78..4f8255cf91 100644 --- a/packages/core/src/types/bundler.ts +++ b/packages/core/src/types/bundler.ts @@ -1,4 +1,5 @@ import type { App } from './app/index.js' +import type { DeepPartial } from './helpers.js' /** * Vuepress bundler @@ -22,6 +23,15 @@ export interface Bundler { * Method to run vuepress app in build mode, generating static pages and assets */ build: (app: App) => Promise + + /** + * Merge helper for current bundler. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + mergeConfig: = Record>( + currentConfig: Config, + newConfig: DeepPartial, + ) => Config } export type BundlerOptions = Record diff --git a/packages/core/src/types/helpers.ts b/packages/core/src/types/helpers.ts new file mode 100644 index 0000000000..098ac789d6 --- /dev/null +++ b/packages/core/src/types/helpers.ts @@ -0,0 +1,14 @@ +type DeepPartialArray = DeepPartial[] + +type DeepPartialObject = { + [P in keyof T]?: DeepPartial +} + +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +export type DeepPartial = T extends Function + ? T + : T extends (infer U)[] + ? DeepPartialArray + : T extends object + ? DeepPartialObject + : T | undefined From 523f2f976e28edd76decb5c804adf907af8d80aa Mon Sep 17 00:00:00 2001 From: "Mr.Hope" Date: Thu, 21 May 2026 09:35:52 +0800 Subject: [PATCH 2/5] feat: add type field --- packages/bundler-vite/src/viteBundler.ts | 1 + packages/bundler-webpack/src/webpackBundler.ts | 1 + packages/core/src/app/resolveAppMarkdown.ts | 2 +- packages/core/src/types/bundler.ts | 5 +++++ packages/core/tests/app/resolveAppOptions.spec.ts | 4 ++-- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/bundler-vite/src/viteBundler.ts b/packages/bundler-vite/src/viteBundler.ts index 096cfb5e2e..63b9363572 100644 --- a/packages/bundler-vite/src/viteBundler.ts +++ b/packages/bundler-vite/src/viteBundler.ts @@ -7,6 +7,7 @@ import type { ViteBundlerOptions } from './types.js' export const viteBundler = (options: ViteBundlerOptions = {}): Bundler => ({ name: '@vuepress/bundler-vite', + type: 'vite', dev: async (app) => dev(options, app), build: async (app) => build(options, app), mergeConfig: mergeConfig as Bundler['mergeConfig'], diff --git a/packages/bundler-webpack/src/webpackBundler.ts b/packages/bundler-webpack/src/webpackBundler.ts index b132ccbef5..f8583ca08d 100644 --- a/packages/bundler-webpack/src/webpackBundler.ts +++ b/packages/bundler-webpack/src/webpackBundler.ts @@ -9,6 +9,7 @@ export const webpackBundler = ( options: WebpackBundlerOptions = {}, ): Bundler => ({ name: '@vuepress/bundler-webpack', + type: 'webpack', dev: async (app) => dev(options, app), build: async (app) => build(options, app), mergeConfig: merge, diff --git a/packages/core/src/app/resolveAppMarkdown.ts b/packages/core/src/app/resolveAppMarkdown.ts index f0446b8239..534509baa0 100644 --- a/packages/core/src/app/resolveAppMarkdown.ts +++ b/packages/core/src/app/resolveAppMarkdown.ts @@ -19,7 +19,7 @@ export const resolveAppMarkdown = async (app: App): Promise => { if (app.options.markdown.assets !== false) { app.options.markdown.assets ??= {} app.options.markdown.assets.absolutePathPrependBase ??= - app.options.bundler.name === '@vuepress/bundler-webpack' + app.options.bundler.type === 'webpack' } const markdown = createMarkdown(app.options.markdown) diff --git a/packages/core/src/types/bundler.ts b/packages/core/src/types/bundler.ts index 4f8255cf91..757d925dac 100644 --- a/packages/core/src/types/bundler.ts +++ b/packages/core/src/types/bundler.ts @@ -14,6 +14,11 @@ export interface Bundler { */ name: string + /** + * Type of the bundler, e.g. 'vite' or 'webpack' + */ + type: string + /** * Method to run vuepress app in dev mode, starting dev server */ diff --git a/packages/core/tests/app/resolveAppOptions.spec.ts b/packages/core/tests/app/resolveAppOptions.spec.ts index ab3033c435..edb1f186b2 100644 --- a/packages/core/tests/app/resolveAppOptions.spec.ts +++ b/packages/core/tests/app/resolveAppOptions.spec.ts @@ -11,7 +11,7 @@ it('should create app options with default values', () => { resolveAppOptions({ source, theme: { name: 'theme' }, - bundler: { name: 'bundler' } as Bundler, + bundler: { name: 'bundler', type: 'vite' } as Bundler, }), ).toEqual({ base: '/', @@ -23,7 +23,7 @@ it('should create app options with default values', () => { '/': { lang: 'en-US', title: '', description: '' }, }, theme: { name: 'theme' }, - bundler: { name: 'bundler' }, + bundler: { name: 'bundler', type: 'vite' }, source, dest: path.resolve(source, '.vuepress/dist'), temp: path.resolve(source, '.vuepress/.temp'), From 29a9ae4427db37b0e2bca6aa7d508929ee9affd2 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Wed, 24 Jun 2026 22:17:37 +0800 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Mister-Hope --- packages/bundler-vite/src/types.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/bundler-vite/src/types.ts b/packages/bundler-vite/src/types.ts index 72c5a85fde..1b3c30d58c 100644 --- a/packages/bundler-vite/src/types.ts +++ b/packages/bundler-vite/src/types.ts @@ -6,16 +6,10 @@ import type { InlineConfig } from 'vite' * Options for bundler-vite */ export interface ViteBundlerOptions extends BundlerOptions { - /** - * Vite options - */ /** * Vite options */ viteOptions?: InlineConfig - /** - * Options for @vitejs/plugin-vue - */ /** * Options for @vitejs/plugin-vue */ From 8194c51cf09f7ea01a269184fe2a281770741c4f Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Wed, 24 Jun 2026 22:21:42 +0800 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Mister-Hope --- packages/bundler-vite/src/types.ts | 2 +- packages/bundler-webpack/src/types.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/bundler-vite/src/types.ts b/packages/bundler-vite/src/types.ts index 1b3c30d58c..533369a55f 100644 --- a/packages/bundler-vite/src/types.ts +++ b/packages/bundler-vite/src/types.ts @@ -21,7 +21,7 @@ export interface ViteBundlerOptions extends BundlerOptions { * @param isServer - Whether it is server bundle * @param isBuild - Whether in build mode * @param mergeConfig - Vite's mergeConfig function, in case you want to use it to merge config - * @returns New Vite config + * @returns optional whole new Vite config */ configureVite?: ( config: InlineConfig, diff --git a/packages/bundler-webpack/src/types.ts b/packages/bundler-webpack/src/types.ts index 2505c180e2..524d1f4087 100644 --- a/packages/bundler-webpack/src/types.ts +++ b/packages/bundler-webpack/src/types.ts @@ -20,7 +20,16 @@ export type { export interface WebpackBundlerOptions extends BundlerOptions { /** * use webpack-merge to set webpack config - */ +/** + * use webpack-merge to set webpack config + * + * + * @param config - Vite config + * @param isServer - Whether it is server bundle + * @param isBuild - Whether in build mode + * @param mergeConfig - merge function from webpack-merge, in case you want to use it to merge config + * @returns optional whole new webpack config + */ configureWebpack?: ( config: WebpackConfiguration, isServer: boolean, From 0f2118a4f70aa743ac41a50a7f31118b3f8ec20a Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Wed, 24 Jun 2026 22:22:18 +0800 Subject: [PATCH 5/5] Update packages/bundler-webpack/src/types.ts --- packages/bundler-webpack/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bundler-webpack/src/types.ts b/packages/bundler-webpack/src/types.ts index 524d1f4087..ec88d37565 100644 --- a/packages/bundler-webpack/src/types.ts +++ b/packages/bundler-webpack/src/types.ts @@ -24,7 +24,7 @@ export interface WebpackBundlerOptions extends BundlerOptions { * use webpack-merge to set webpack config * * - * @param config - Vite config + * @param config - Webpack config * @param isServer - Whether it is server bundle * @param isBuild - Whether in build mode * @param mergeConfig - merge function from webpack-merge, in case you want to use it to merge config