likes
comments
collection
share

vite plugin-legacy 插件介绍

作者站长头像
站长
· 阅读数 38

简介

vite 的runtime是基于 native ESM 的,所以如果开发者需要打包代码在 传统浏览器 or 兼容性差的浏览器版本, 就需要用到此插件

tip 此插件暂时不支持动态返回html,如部分ssr插件。

因为该插件的核心原理是打包后在 index.html 静态文件中注入 scripts, 而大部分ssr是动态返回html

文章末有如何在ssr项目中添加legacy功能的项目链接

前提

什么是polyfill

简单来说,polyfill就是兼容旧浏览器的代码块,磨平差异。比如说 有的浏览器不支持 globalThis, 那我们可以自己实现一个globalThis然后注入到script中

注意:polyfill代码编译(renderLegacyChunks)是两个概念, 前者是添加额外的代码来使得旧浏览器支持某些特性,后者是把浏览器不认识的语法转化为可以运行的语法

vite的polyfill分为 modern polyfill(modernPolyfills属性)和 legacy polyfill(polyfills属性),之所以区分开来,是为了尽量减少polyfills的大小

modern polyfill

plugin-legacy中,modernPolyfills是针对现代浏览器的polyfill,比如,我们可以设置

legacy({
  renderLegacyChunks: false,
  modernPolyfills: ['es.global-this'],
}),

这样就只会打包出针对现代浏览器的polyfill,而不会生成传统的polyfill vite plugin-legacy 插件介绍

来专门针对现代浏览器 globalThis做polyfill,如果设置为true的话,vite 会根据打包代码,使用 babel针对esmodule的浏览器使用useBuiltin来生成polyfill,这是激进的做法,可能会有许多不需要的polyfill生成从而导致polyfill体积变大

如果设置 modernPolyfills为数组的话,plugin-legacy会使用vite内部的build方法(vite.build),使用虚拟模块打包

// 虚拟模块
const polyfillId = '\0vite/legacy-polyfills'

function polyfillsPlugin(
  // 用户设置的modernPolyfills
  imports: Set<string>,
  excludeSystemJS?: boolean
): Plugin {
  return {
    name: 'vite:legacy-polyfills',
    resolveId(id) {
      if (id === polyfillId) {
        return id
      }
    },
    load(id) {
      if (id === polyfillId) {
        return (
          [...imports].map((i) => `import "${i}";`).join('') +
          (excludeSystemJS ? '' : `import "systemjs/dist/s.min.js";`)
        )
      }
    }
  }
}

然后在generateBundle阶段把这个polyfillchunk加入到最后生成的bundle中

legacy polyfill

plugin-legacy中,polyfills是针对传统浏览器的polyfill,比如:

legacy({
  renderLegacyChunks: true,
  polyfills: ['es.global-this'],
}),

这样就会打包出一个传统的polyfill,vite plugin-legacy 插件介绍

legacyPolyfill跟modernPolyfill的功能是一样的,他们的区别仅仅在于语法,就如上文所讲到的代码编译

开启了 renderLegacyChunks才会代码编译生成 legacy chunk

了解 browserslist

js兼容/css兼容,都需要告诉打包工具,需要兼容到哪些浏览器

browserslist这个工具是用来指定浏览器范围的工具,在 postcss/babel中普遍使用。

我们可以在 .browserslistrc中指定需要兼容的浏览器范围,然后设置到 plugin-legacy中。这样就可以统一js/css打包目标了。

import browserslist from 'browserslist'
import legacy from '@vitejs/plugin-legacy'

const browserslistConfig = browserslist.loadConfig({ path: '.' })

legacy({
  targets: browserslistConfig,
})
defaults
last 2 versions
> 1%
not dead

可以在这个网站比较方便查看目标浏览器范围百分比: browsersl.ist/

一个疑问

plugin-legacy内置的对 browserslist的 探测没有生效,ignoreBrowserslistConfig设置了没用,因为 plugin-legacy默认了 targetsbabel会优先读取 targets然后再从browserslist配置里面去找。我觉得这是个bug,开发者只能手动设置targets,而不能探测browserslist配置

2022/12/7 更新

的确是bug: github.com/vitejs/vite…

新手迷惑点

browserslist配置中,咱们可以这样写:

Chrome >= 64

在配置 babel: target时,

{
  "targets": {
    "chrome": "64",
  }
}

plugin-legacy中,只要认 browserslist写法即可

什么是传统浏览器

传统浏览器一般指不支持 native ESM 的浏览器,如chrome<60,Edge<15,Firefox<59 等等,如果使用vite打包而不做任何的处理的话,是无法在这些浏览器上面运行的,因为打包出来的代码是 很新的规范

开发者则需要使用此插件配置相应的兼容处理,如:

// vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default {
  plugins: [
    legacy({
      targets: ['chrome < 60', 'edge < 15'],
      renderLegacyChunks: true,
    })
  ]
}

plugin-legacy 参数

文档里面都有介绍,我就不多比比了,讲一下里面不常用的

additionalLegacyPolyfills

针对传统浏览器的额外polyfills,之所有有这个字段,是因为 plugin-legacy内部只包含了core-js相关的polyfills,如果开发者希望添加非corejs的polyfill,就加在这个字段里面

renderLegacyChunks

简单来说就是是否编译传统代码。true的话会编译一份额外的针对传统浏览器(不支持esm的浏览器)的代码。

vite是怎么区分什么时候使用 legacyChunk呢?很简单

<script nomodule src="legacy.js"></script>

externalSystemJS

开启这个选项会把 systemjs从 legacyPolyfills中排除。

由于 plugin-legacy内部是使用 rollup的format: 'system'打包的,所以如果systemjs移除了需要开发者自己添加

ignoreBrowserslistConfig

plugin-legacy使用 babel来打包 legacy chunkbabel天然支持 browserslist,所以 plugin-legacy暴露了这个配置来指定打包 legacy chunk时的浏览器范围

如何在ssr项目中实现legacy功能?

github.com/hemengke199…

转载自:https://juejin.cn/post/7165493414048301070
评论
请登录