ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VitePress MPA 模式(Multi-Page Application)完整指南:零 JavaScript 页面与 `<script client>` 按需加载

VitePress MPA 模式(Multi-Page Application)完整指南:零 JavaScript 页面与 `<script client>` 按需加载 VitePress MPA 模式Multi-Page Application完整指南零 JavaScript 页面与script client按需加载【免费下载链接】vitepressVite Vue powered static site generator.项目地址: https://gitcode.com/gh_mirrors/vi/vitepressMPAMulti-Page Application多页应用模式是 VitePress 提供的一种实验性构建模式它让构建出的每个页面默认不携带任何 JavaScript从而显著提升 Lighthouse 等审计工具给出的首次访问性能评分。本文以 docs/en/guide/mpa-mode.md 为骨架结合仓库源码src/node/build/bundle.ts、src/node/build/buildMPAClient.ts、src/node/build/render.ts 等深入讲解 MPA 模式的启用方式、底层原理、script client的用法边界以及它适合与不适合的使用场景。MPA 模式是什么MPA 是与 SPASingle Page Application相对的一种站点形态。在默认的 SPA 构建下VitePress 会把整站打包为一套客户端应用首次加载后页面之间的跳转由前端路由接管无需整页刷新但在 MPA 模式下所有页面在构建时均被渲染为独立的 HTML 文件默认情况下每个页面都不包含任何 JavaScript。这种默认无 JS的产出意味着生产站点的首次访问性能评分来自 Lighthouse 等审计工具通常会更好因为浏览器无需下载、解析和执行整份客户端 bundle 即可展示完整内容代价是失去 SPA 导航页面之间的链接会触发完整的浏览器刷新因此加载后的跳转体验不如 SPA 模式那样瞬时。简而言之MPA 模式是在首屏性能与导航流畅度、交互能力之间做的一次明确取舍。如何启用 MPA 模式MPA 模式可以通过两种方式开启二者效果等价。方式一命令行参数构建时附加--mpa参数vitepress build --mpa从源码看src/node/build/build.ts 中正是通过读取该参数来设置站点配置的if (buildOptions.mpa) { siteConfig.mpa true delete buildOptions.mpa }也就是说--mpa最终仍然只是把siteConfig.mpa置为true后续的构建流程统一以该配置分支执行。方式二配置文件在 VitePress 配置文件config.mts/config.ts中设置import { defineConfig } from vitepress export default defineConfig({ mpa: true })配置解析发生在 src/node/config.tsmpa: !!userConfig.mpa,!!保证了该字段最终是严格布尔值src/node/siteConfig.ts 中的类型注释将该选项链接回本文档并标注为 MPA 模式开关。两种方式CLI 与配置文件可以任选其一若同时使用效果一致不会叠加出额外的行为。MPA 模式下的无 JS 渲染原理在 MPA 模式下构建流程与 SPA 模式有本质区别。查看 src/node/build/bundle.ts 可以还原出完整的构建决策let clientResult config.mpa ? null : ((await build(await resolveViteConfig(false))) as Rolldown.RolldownOutput) const serverResult (await build( await resolveViteConfig(true) )) as Rolldown.RolldownOutput if (config.mpa) { // 将服务端构建中除 .js 之外的资产文件复制到输出目录 // 由于没有客户端构建这些资产只能从服务端构建中取得 // ... // 仅当存在 script client 时才额外执行一次客户端打包 if (Object.keys(clientJSMap).length) { clientResult await buildMPAClient(clientJSMap, config) } }从中可以归纳出三层关键事实跳过常规客户端构建MPA 模式下clientResult直接置为null不会走默认的客户端打包因此产物中没有整站应用入口 JS页面 HTML 全部来自 SSR服务端渲染每个页面在构建期被渲染为静态 HTMLsrc/node/build/render.ts 直接生成完整的!DOCTYPE html文档SSR 构建被 minifyminify: ssr ? !!config.mpa : ...src/node/build/bundle.ts说明 MPA 模式连服务端产物都会压缩进一步控制体积。在页面渲染阶段src/node/build/render.ts 展示了 MPA 模式特有的脚本处理逻辑当页面存在对应的客户端 chunk 且其代码不含import语句时脚本会被直接内联进 HTMLif (config.mpa result) { const matchingChunk result.output.find( (chunk): chunk is Rolldown.OutputChunk chunk.type chunk chunk.facadeModuleId slash(path.join(config.srcDir, page)) ) if (matchingChunk) { if (!matchingChunk.code.includes(import)) { inlinedScript script typemodule${matchingChunk.code}/script // 内联后删除独立的 chunk 文件避免重复加载 await rm(path.resolve(config.outDir, matchingChunk.fileName), { force: true }) } else { inlinedScript script typemodule src${assetUrl(matchingChunk.fileName)}${assetsCrossOrigin}/script } } }这也是为什么 MPA 站点在无script client的情况下可以做到页面零 JS整份交互代码都不存在了浏览器只需要解析 HTML 与 CSS。Vue 被降级为服务端模板语言由于默认无 JSMPA 模式下浏览器端不会挂载任何事件处理器Vue 实际上只作为服务端模板语言参与渲染内容在构建期由 Vue 的 SSR 能力输出为 HTML到了浏览器端则没有任何 Vue 运行时在运行。这意味着页面内不会存在任何开箱即用的交互——按钮点击、表单联动、组件状态等都需要你显式地通过script client引入客户端脚本才能工作。按需加载客户端脚本script client如果站点确实需要少量客户端交互VitePress 提供了专用的script client标签作为唯一入口。它只在 MPA 模式下生效是VitePress 独有的特性并非 Vue 特性。基本用法在.md或.vue文件中直接书写script client document.querySelector(h1).addEventListener(click, () { console.log(client side JavaScript!) }) /script # Hello这段脚本会以 JavaScript 模块的方式在浏览器端执行从而为页面补充交互能力。作用范围与打包策略script client有两个关键的作用域规则见 docs/en/guide/mpa-mode.md 及 src/node/build/buildMPAClient.ts 的实现主题组件中的客户端脚本会被打包在一起buildMPAClient中把除.md之外的主题相关文件统一作为虚拟入口client.js的依赖导入const themeFiles files.filter((f) !f.endsWith(.md)) const pages files.filter((f) f.endsWith(.md)) // 虚拟入口所有主题文件聚合为一个 chunk load(id) { if (id virtualEntry) { return themeFiles .map((file) import ${JSON.stringify(file)}) .join(\n) } else if (id in js) { return js[id] } }某个具体页面的客户端脚本会单独拆分为该页专属的 chunkbuild.rolldownOptions.input中把每个.md页面也作为独立入口src/node/build/buildMPAClient.ts从而避免在不需要的页面上加载其他页面的脚本。重要限制不是 Vue 组件代码必须特别强调script client不会按照 Vue 组件代码来求值它被当作一个普通 JavaScript 模块处理。也就是说你不能在其中直接使用 Vue 的响应式 API、组件选项或模板语法它更适合做 DOM 操作、事件绑定、接入第三方纯 JS 库这类轻交互由于缺乏框架层的协调复杂交互在 MPA 模式下会变得难以维护。正是因为这个限制官方文档明确指出只有在站点几乎不需要客户端交互时才应该使用 MPA 模式docs/en/guide/mpa-mode.md。MPA 模式下的其他行为差异除了脚本处理MPA 模式还在若干细节上与 SPA 模式分道扬镳这些差异大多可以从源码中得到印证。不注入暗色模式切换内联脚本在 src/node/config.ts 的resolveSiteDataHead中function resolveSiteDataHead(userConfig?: UserConfig): HeadConfig[] { const head userConfig?.head ?? [] if (userConfig?.mpa) return head // 非 MPA 模式下才会追加 check-dark-mode 内联脚本防止首屏闪烁 ... }SPA 模式下 VitePress 会往head注入一段检查暗色主题的内联脚本以避免刷新时的闪烁MPA 模式下这段脚本被直接跳过——这既符合默认无 JS的原则也意味着暗色主题的初始化行为需要你自行通过head配置或script client处理。不生成元数据脚本src/node/build/build.ts 中的generateMetadataScript在 MPA 模式下直接返回空内容if (config.mpa) { return { html: , inHead: false } }SPA 模式会把站点数据与页面 hash 映射以脚本形式内嵌到每个页面MPA 模式没有客户端应用需要消费这些数据因此直接省略进一步减少了页面中的脚本体积。不生成 modulepreload / prefetch 链接src/node/build/render.ts 中预加载preload与预取prefetch链接的生成被限定在非 MPA 且非默认 404 页面if (result appChunk !config.mpa !isDefault404) { // 计算 preloadLinks 与 prefetchLinks }MPA 页面之间通过整页刷新切换不存在提前预取下一个页面 chunk的意义因此这些开销被一并省去。相对 base 场景下不注入站点根地址恢复脚本src/node/build/render.tsrelativeBase !config.mpa ? scriptwindow.__VP_SITE_ROOT__new URL(${pageBase},location).href/script : 当站点使用相对 basebase: ./之类时SPA 模式需要一段脚本在运行时恢复绝对站点根地址MPA 模式没有客户端路由逻辑故不注入。输出目录的资产复制由于 MPA 模式没有常规客户端构建服务端构建中产出的非 JS 资产CSS、图片、字体等会被显式复制到输出目录src/node/build/bundle.tspublicDir也会被一并复制。源码中同时保留了一条 FIXME 注释MPA 模式下输出目录不会被清空多次重建后带 hash 的资产会在输出目录中累积——在 CI 反复构建时需要注意清理旧产物。什么时候该用、什么时候不该用适合使用 MPA 模式的场景内容型站点正文价值远大于交互价值且页面上几乎没有需要 JavaScript 的功能追求极致的首次加载性能例如希望 Lighthouse Performance 分数尽可能高站点部署在弱网环境或面向性能敏感的受众站点交互极简只需少量点缀式脚本统计埋点、目录高亮、回到顶部等且可以通过script client覆盖。不适合使用 MPA 模式的场景站点大量依赖 SPA 式即时导航、页面切换动画或无刷新体验需要复杂的组件交互、状态管理、表单联动等前端逻辑——script client是普通 JS 模块无法承载框架级复杂度深度依赖 Vue 组件生态与响应式能力的站点MPA 模式下这些能力在浏览器端基本不可用。小结MPA 模式是 VitePress 面向内容优先、性能优先场景提供的一个实验性开关它把构建产物从携带完整客户端应用的 SPA降级为默认零 JS 的静态页面集合用牺牲 SPA 导航与浏览器端交互的代价换来更好的首次访问性能。启用方式只有一行vitepress build --mpa或mpa: true当确实需要少量交互时通过 VitePress 独有的script client按需引入客户端模块并注意它仅按普通 JS 模块求值的边界。官方将其标记为experimental实验性建议在采用前先在目标站点上实测构建产物与性能表现并留意仓库后续版本对 MPA 模式行为如输出目录清理的演进。更多相关材料可继续阅读docs/en/guide/mpa-mode.md本文档源、docs/en/reference/cli.mdvitepress build命令说明、src/node/siteConfig.tsmpa配置项的类型定义。【免费下载链接】vitepressVite Vue powered static site generator.项目地址: https://gitcode.com/gh_mirrors/vi/vitepress创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表