浏览器兼容性有何解?plugin-legacy

先把结论摊开说:plugin-legacy 是给"还吃不动现代 ESM 和新 API"的老浏览器准备的"加餐"。真有用户在用老设备,我们就"花点小钱买安心";要是你站点 99% 都是新版 Chrome/Safari,劝你忍痛割爱,别为了那 1% 把所有人拖慢。

它到底干啥?

一句话:打两套包,老少咸宜。

  • 现代包(ESM):给现代浏览器吃的,轻巧、快。
  • 祖传包(Legacy):给不支持 ESM 的老家伙吃的,用 SystemJS 加一堆 polyfill,能跑但会重一些。
  • 加载策略:现代浏览器走 <script type="module">,老浏览器走 <script nomodule>;两套互不打扰,谁该吃谁自己认路。

!tip\] 这波属于"多端投喂":不强迫所有人都吃软饭,但也不饿着老设备。 *** ** * ** *** ## 什么时候该上?三问做决策(别拍脑袋) 1. 你的用户里有 iOS 12/13、Android 7/8 的长尾吗? 2. 有嵌套在古早 WebView(例如某些 X5/厂商定制)的业务必须跑吗? 3. 上线后"白屏/报错"的反馈来自老设备吗?(埋点+日志说话) * 三问"有两个 yes",就开;全都"no",老老实实省下来,别压榨构建时间。 *** ** * ** *** ## 快速上手:三步走就能跑 安装 ```bash npm i -D @vitejs/plugin-legacy # 或 pnpm add -D @vitejs/plugin-legacy ``` 最小配置 ```ts // vite.config.ts import { defineConfig } from 'vite' import legacy from '@vitejs/plugin-legacy' export default defineConfig({ plugins: [ legacy({ targets: ['defaults', 'not IE 11', 'iOS >= 12', 'Android >= 7'], modernPolyfills: true, // 给"准现代"浏览器补上少数新 API additionalLegacyPolyfills: ['regenerator-runtime/runtime'], // async/await 兜底 renderLegacyChunks: true, // 产出独立的 -legacy 包 externalSystemJS: false, // 内联/本地提供 SystemJS(默认 false) }), ], }) ``` 怎么验? * 构建后你会看到 `polyfills-legacy`、`index-legacy` 之类产物。 * 用旧设备/旧 WebView 打开页面,Network 里能看到 `-legacy` 资源在跑;现代浏览器不会去加载它们。 *** ** * ** *** ## 配置项 * targets * 写法基本等于 Browserslist,决定"老的不老"的分界线。 * 建议跟你家 `.browserslistrc` 一致,别前后打架。 * modernPolyfills * true 时,给"差一点就现代"的浏览器(比如 Safari 13)补几个关键 API,避免"一口气噎着"。 * additionalLegacyPolyfills * 点名加一些你用到的 API 垫片,比如 `regenerator-runtime/runtime`(async/await)、`es.array.flat` 等。 * renderLegacyChunks * 设为 true(默认)会生成独立的 `-legacy` 产物,老浏览器才会下载;这也是我们要的"差异装载"。 * externalSystemJS * true 表示不内联 SystemJS,需要你自己提供(CDN 或自托管)。一般保持 false 省心。 \[!warning\] 名字可能不同版本有小差异,但核心思路不变:一套目标(targets)+ 若干补丁(polyfills)+ 两套产物(modern/legacy)。 *** ** * ** *** ## 和 Browserslist / Autoprefixer / Babel 的相处之道 * 思路统一:把"目标浏览器矩阵"写在 `.browserslistrc` 里,一处约定,多处受益。 * CSS 走 Autoprefixer,JS 走 `plugin-legacy`;如果你已经用了 Babel 的 `preset-env` + `core-js`,注意别"双重垫片",否则白白长肉。 * Vite 项目一般不主动上 Babel 全家桶,除非你确实有特殊语法链路需求。 示例 `.browserslistrc` ```ini > 0.5% last 2 versions not dead iOS >= 12 Android >= 7 ``` *** ** * ** *** ## 它是怎么工作的?(点到为止,够用了) * 构建期:Vite 先出一套"现代 bundle",然后 `plugin-legacy` 再把代码过一遍"降级机",生成 `-legacy` 的 SystemJS 版本,并拆出一个 `polyfills-legacy`。 * 运行时:HTML 里会同时注入 `