跳到主要内容

plugin-legacy

2023年12月21日
柏拉文
越努力,越幸运

一、认识


Vite 官方已经为我们封装好了一个开箱即用的方案: @vitejs/plugin-legacy,我们可以基于它来解决项目语法的浏览器兼容问题。这个插件内部同样使用 @babel/preset-env 以及 core-js等一系列基础库来进行语法降级和 Polyfill 注入

二、配置


// vite.config.ts
import legacy from '@vitejs/plugin-legacy';
import { defineConfig } from 'vite'

export default defineConfig({
plugins: [
// 省略其它插件
legacy({
// 设置目标浏览器,browserslist 配置语法
targets: ['ie >= 11'],
})
]
})

三、效果


在引入插件后,我们可以尝试执行 npm run build 对项目进行打包,可以看到如下的产物信息:

Preview

相比一般的打包过程,多出了 index-legacy.jsvendor-legacy.js以及polyfills-legacy.js三份产物文件。让我们继续观察一下index.html的产物内容:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/assets/favicon.17e50649.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<!-- 1. Modern 模式产物 -->
<script type="module" crossorigin src="/assets/index.c1383506.js"></script>
<link rel="modulepreload" href="/assets/vendor.0f99bfcc.js">
<link rel="stylesheet" href="/assets/index.91183920.css">
</head>
<body>
<div id="root"></div>
<!-- 2. Legacy 模式产物 -->
<script nomodule>兼容 iOS nomodule 特性的 polyfill,省略具体代码</script>
<script nomodule id="vite-legacy-polyfill" src="/assets/polyfills-legacy.36fe2f9e.js"></script>
<script nomodule id="vite-legacy-entry" data-src="/assets/index-legacy.c3d3f501.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>

通过官方的 legacy 插件, Vite 会分别打包出 Modern 模式和 Legacy模式的产物,然后将两种产物插入同一个 HTML 里面,Modern产物被放到 type="module"script 标签中,而 Legacy 产物则被放到带有 nomodulescript 标签中。浏览器的加载策略如下图所示:

Preview

这样产物便就能够同时放到现代浏览器和不支持 type="module" 的低版本浏览器当中执行。当然,在具体的代码语法层面,插件还需要考虑语法降级和 Polyfill 按需注入的问题,接下来我们就来分析一下 Vite 的官方 legacy 插件是如何解决这些问题的。