From 72f899477c30ee86ad76f2eab3817264c8746371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Thu, 21 May 2026 01:25:19 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E9=85=8D=E7=BD=AE=20manualChunks=20?= =?UTF-8?q?=E6=8B=86=E5=88=86=20vendor=20chunk=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=89=93=E5=8C=85=E4=BD=93=E7=A7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用 Vite 插件 manualChunksForHtmlOnly 仅对 HTML 多入口构建生效 - 跳过 background/content-script 的 IIFE 构建(不支持 manualChunks) - 拆分 vendor-react (193KB)、vendor-mui (326KB)、vendor-i18n (55KB) - 按需加载 vendor-qr (78KB)、vendor-dnd (45KB)、vendor-markdown (41KB) - PageErrorBoundary chunk 从 454KB 降至 36KB --- wxt.config.ts | 66 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/wxt.config.ts b/wxt.config.ts index f0218ba..2b19027 100644 --- a/wxt.config.ts +++ b/wxt.config.ts @@ -1,4 +1,59 @@ import { defineConfig } from 'wxt'; +import type { Plugin } from 'vite'; + +/** + * 仅在 HTML 多入口构建(popup / options / sidepanel)中启用 manualChunks 拆分 vendor。 + * WXT 对 background / content-script 使用 lib 模式(IIFE),该模式不支持 manualChunks。 + */ +function manualChunksForHtmlOnly(): Plugin { + return { + name: 'manual-chunks-html-only', + outputOptions(rawOptions) { + // lib 模式(IIFE)不支持 manualChunks,仅对 ES/CJS 格式启用 + if (rawOptions.format === 'iife' || rawOptions.format === 'umd') { + return; + } + rawOptions.manualChunks = (id: string) => { + if (!id.includes('node_modules')) return; + + // React 核心 + if (id.includes('/react-dom/') || (id.includes('/react/') && !id.includes('/react-dom/'))) { + return 'vendor-react'; + } + // MUI + Emotion + if ( + id.includes('@mui/') || + id.includes('@emotion/') || + id.includes('hoist-non-react-statics') || + id.includes('csstype') || + id.includes('@popperjs/') + ) { + return 'vendor-mui'; + } + // 国际化 + if ( + id.includes('i18next') || + id.includes('react-i18next') || + id.includes('intl-messageformat') + ) { + return 'vendor-i18n'; + } + // QR 相关 + if (id.includes('qr-scanner') || id.includes('qrious')) { + return 'vendor-qr'; + } + // 拖拽 + if (id.includes('@dnd-kit')) { + return 'vendor-dnd'; + } + // Markdown + if (id.includes('marked')) { + return 'vendor-markdown'; + } + }; + }, + }; +} // See https://wxt.dev/api/config.html export default defineConfig({ @@ -31,19 +86,12 @@ export default defineConfig({ }, }, vite: () => ({ + plugins: [manualChunksForHtmlOnly()], build: { - // 1. 切换压缩器为 terser minify: 'terser', - - // 2. 配置 terser 强制转义所有非 ASCII 字符 terserOptions: { - format: { - ascii_only: true, - comments: false, - }, + format: { ascii_only: true, comments: false }, }, - - // 3. 调整 chunk 大小警告阈值 chunkSizeWarningLimit: 600, }, }),