Skip to content

参考

基于 MDN / Vue Router / Webpack / Vite & Rolldown / React Router 官方文档编写,对照 Vite 8 / Webpack 5.108+ / Vue Router 4 / React Router v7.5

速查

  • 分割原语:动态 import('./X') 返回 Promise<模块命名空间对象>,ES2020 标准、Baseline Widely Available
  • Vue Routercomponent: () => import('./X.vue')(路由组件不要包 defineAsyncComponent
  • React Router v7:v6.4+ lazy: () => import('./X'),v7.5 对象式 lazy: { Component, loader, action } 逐属性并行加载
  • Webpack splitChunks 默认chunks: 'async'minSize: 20000maxAsyncRequests: 30maxInitialRequests: 30
  • cacheGroups 内置defaultVendorstest: node_modulespriority: -10)+ defaultminChunks: 2priority: -20
  • Vite 8 / Rolldownbuild.rolldownOptions.output.codeSplitting.groups 替代 Rollup 的 manualChunks
  • 魔法注释(Webpack):webpackChunkName / webpackMode / webpackPrefetch / webpackPreload / webpackExports
  • preload vs prefetch:preload 当前导航必用 + 高优先级(须带 as);prefetch 未来导航投机 + 低优先级
  • 部署兜底:HTML no-cache + 资源带 hash + 监听 vite:preloadErrorpreventDefaultlocation.reload
  • 版本:Vite 8(2026-03)、Webpack 5.108+、Vue Router 4.x、React Router v7.5(2025-04)
  • 完整说明见 入门 / 分割策略与构建配置

动态 import() 语义速查

维度静态 import动态 import()
求值时机加载期调用时(按需)
是否产生分割点是(所有打包器)
返回值命名空间对象(同步)Promise<模块命名空间对象>
求值次数一次一次(缓存命中)
错误处理抛同步错误Promise reject(永不抛同步错误)
模块标识字符串字面量表达式(须用 webpackInclude 收口)
标准ES2015ES2020(Baseline Widely Available)

路由级分割写法速查

Vue Router

ts
import { createRouter, createWebHistory } from "vue-router";

const router = createRouter({
  history: createWebHistory(),
  routes: [
    // ✓ 路由组件就是返回 Promise 的函数
    { path: "/", component: () => import("./views/Home.vue") },
    // 用 webpackChunkName 聚合同路由的嵌套组件到同一 chunk
    {
      path: "/dashboard",
      component: () => import(/* webpackChunkName: "group-dashboard" */ "./views/Dashboard.vue"),
      children: [
        {
          path: "stats",
          component: () => import(/* webpackChunkName: "group-dashboard" */ "./views/Stats.vue"),
        },
      ],
    },
  ],
});

React Router v7

ts
// v6.4+ 函数式
export default [
  { path: "/projects/:id", lazy: () => import("./routes/project") },
];
// routes/project.ts 具名导出 Component/loader/action/ErrorBoundary

// v7.5+ 对象式(逐属性并行加载)
export default [
  {
    path: "/projects/:id",
    lazy: {
      Component: () => import("./routes/project/component").then(m => m.default),
      loader: () => import("./routes/project/loader").then(m => m.default),
      action: () => import("./routes/project/action").then(m => m.default),
      ErrorBoundary: () => import("./routes/project/error-boundary").then(m => m.default),
      unstable_middleware: () => import("./routes/project/middleware").then(m => m.default),
    },
  },
];

Webpack splitChunks 配置速查

顶层选项

选项默认作用
chunks'async''async' / 'initial' / 'all' / function / RegExp
minSize20000(20kb)新 chunk 最小体积
minRemainingSize0minSize 配合确保剩余 chunk 不太小
minChunks1至少被几个 chunk 共享
maxSize-提示上限,超过则尽量拆分(HTTP/2 + 长缓存用)
maxAsyncSize-异步 chunk 的 maxSize
maxInitialSize-入口 chunk 的 maxSize
maxAsyncRequests30按需加载时最大并行请求数
maxInitialRequests30入口最大并行请求数
enforceSizeThreshold50000强制分割的体积阈值
namefalse(生产推荐)chunk 名;固定字符串会合并所有公共模块,别用
automaticNameDelimiter'~'自动命名时的分隔符
cacheGroups见下自定义分组

cacheGroups 内置两组

js
cacheGroups: {
  defaultVendors: {
    test: /[\\/]node_modules[\\/]/,
    priority: -10,
    reuseExistingChunk: true,
  },
  default: {
    minChunks: 2,
    priority: -20,
    reuseExistingChunk: true,
  },
}

cacheGroups 组级属性

属性作用
testRegExp 或函数,匹配模块路径
priority多组命中时高者胜出(默认 -20)
reuseExistingChunktrue 复用已有 chunk
enforcetrue 忽略 minSize / minChunks,强制创建
namechunk 名
filename产出文件名
idHintchunk id 提示
type按模块类型(css/mini-extract 等)过滤
layer按 layer 过滤
usedExports配合 tree-shaking
chunks / minSize / minChunks组级覆盖顶层

默认触发条件

满足以下才分割:

  1. 新 chunk 来自 node_modules被 ≥2 个 chunk 共享
  2. 体积 > minSize(20kb)
  3. 并行请求数 ≤ maxAsyncRequests / maxInitialRequests(各 30)

chunks 三档语义

取值含义
'async'仅按需(动态 import())chunk 参与分割(默认)
'initial'仅入口 chunk
'all'同步 + 异步都参与(最强,消除跨入口重复)

Webpack 魔法注释速查

注释作用
/* webpackChunkName: "name" */命名 chunk
/* webpackMode: "lazy" */默认,按需下载 + 求值
/* webpackMode: "lazy-once" */单个 chunk,首次下载后缓存
/* webpackMode: "eager" */不产出独立 chunk,同步打进主 bundle(仍是 Promise)
/* webpackMode: "weak" */已加载才 resolve,否则 reject
/* webpackPrefetch: true */浏览器空闲时低优先级预取(未来导航)
/* webpackPreload: true */与当前导航并行高优先级预加载(当前导航必用)
/* webpackExports: ["a", "b"] */裁剪导出助 tree-shaking
/* webpackInclude: /re/ */动态路径收口(必填)
/* webpackExclude: /re/ */动态路径排除

魔法注释易被 Babel / TS 编译剥掉,需显式保留 comments(@babel/preset-envcomments: true)。

Vite 8 / Rolldown 配置速查

Rolldown codeSplitting.groups

ts
import { defineConfig } from "vite";

export default defineConfig({
  build: {
    rolldownOptions: {
      output: {
        codeSplitting: {
          groups: [
            // 单项属性:test / name / minSize / minChunks / priority
            { name: "react-vendor", test: /node_modules[\\/](react|react-dom)[\\/]/ },
            { name: "viz-vendor", test: /node_modules[\\/](echarts|monaco-editor)[\\/]/ },
            { name: "common", minChunks: 2, test: /src[\\/]shared[\\/]/, minSize: 20000 },
          ],
        },
      },
    },
  },
});

迁移要点:Rollup 的 build.rollupOptions.output.manualChunks 在 Rolldown 下不再支持,强行写会报错或被忽略;手工列模块 ID 易产生循环依赖(Vite issue #12209),改用 test 正则匹配业务路径。

Vite 其他相关配置

配置默认作用
build.modulePreloadtrue为动态 import() 注入 <link rel="modulepreload">
build.cssCodeSplittrue是否按 chunk 分割 CSS
build.assetsInlineLimit4096小于此体积的资源内联为 base64
build.target'modules'等价于 Chrome≥111 / Edge≥111 / Firefox≥114 / Safari≥16.4
build.minDynamicImportstrue(生产)是否对动态 import 进行 minify

Vite 部署兜底:vite:preloadError

ts
// main.ts —— 必须在路由懒加载触发前注册
window.addEventListener("vite:preloadError", (e) => {
  e.preventDefault();
  location.reload();
});

资源提示速查

提示语义优先级必带属性典型用法
<link rel="preload">当前导航必用高(与 document 同级)asscript / font / style / image关键字体 / 关键 CSS / hero 图
<link rel="prefetch">未来导航投机低(浏览器空闲时)无强制下一页路由 chunk
<link rel="modulepreload">当前路由依赖的 JS 模块无强制Vite 默认注入
/* webpackPreload: true */同 preload-当前导航必用的 chunk
/* webpackPrefetch: true */同 prefetch-下一页 chunk

Vite 生产构建默认假定浏览器原生 ESM 动态 import + import.meta(最低 Chrome 64 / Firefox 67 / Safari 11.1),构建目标等价于 Chrome ≥ 111 / Edge ≥ 111 / Firefox ≥ 114 / Safari ≥ 16.4。

部署兜底速查

措施配置作用
HTML no-cacheCache-Control: no-cache每次拿最新 HTML(含最新 chunk 清单)
资源带 hashCache-Control: public, max-age=31536000, immutablechunk 不变则永久缓存
vite:preloadError 兜底addEventListener('vite:preloadError', e => { e.preventDefault(); location.reload() })旧 chunk 失效时自动 reload
CDN 保留历史版本至少保留 1-2 个历史部署的 chunk老用户撞 404 概率降到接近 0
Webpack ChunkLoadErrorimport().catch() 里 reload 或重试同 vite:preloadError

版本状态(截至 2026-07)

库 / 标准当前关键变化
Vite8.x(2026-03)Rolldown 成唯一默认打包器,提速 10-30x;manualChunkscodeSplitting.groups
Webpack5.x(5.108+)SplitChunksPlugin 自 v4 替代 CommonsChunkPlugin,默认 chunks: 'async'minSize: 20000
Vue Router4.x(Vue 3)component: () => import() 为标准路由懒加载
React Routerv7.5(2025-04)对象式 route.lazy API 逐属性懒加载 + 中间件懒加载;函数式自 v6.4 起
动态 import()ES2020 标准Baseline Widely Available,全主流浏览器原生支持
modulepreload标准Chrome 66+ / Firefox 75+ / Safari 16+

Vite 7(2025)通过 rolldown-vite 作为过渡包引入 Rolldown;2026-06 Cloudflare 收购 VoidZero(Vite / Rolldown / Oxc / Vitest 母公司)。

官方资源