曾经有写了个工具库发到了npm, 最近有位老哥说这个库低版本浏览器不兼容, 如 数组的 includes 方法之类的。我随即看了下,确实吼, tsc 只是把语法糖的转译了, 至于高级API特性的,还是那个样子。
随即准备给库加polyfill, 但是想了下。 嘿, 这第三方库的, 我要是加了polyfill, 那要是有其他人不考虑浏览器兼容性问题的呢, 那岂不是polyfill得代码都用不到, 徒增体积?
那好勒, 既然这第三方库不打算整合polyfill, 那就是让使用方去用babel转译这个第三方库了。但是第三方行不行呢, 我心里还真发怵,也不敢直接跟人家说,本着毛主席的“没有调查就没有发言权”原则, 我决定自己去 try 一 try。
随便搞个项目
首先, 那就是项目基础了。
mkdir support-ie
cd support-ie
npm init -y
yarn add webpack webpack-cli --dev
# 装上我那个可怜的包
yarn add ffformat
# 装上 babel 相关依赖
yarn add @babel/core @babel/preset-env babel-loader --dev
# 装上 core-js。 按需引入 polyfill 之类的就取这里面的了
yarn add core-js
# 创建 webpack 配置文件
touch webpack.config.js
# 创建 babel 配置文件
touch babel.config.json
# 源代码文件
mkdir src && cd src && touch main.js
文件创建的差不多,然后就是配制 config 文件了
// webpack.config.js
const path = require("path");
module.exports = {
entry: {
main: "./src/main.js",
},
output: "/dist/main.js",
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: [
path.resolve(__dirname, "./src"),
// 这里要把第三方包加入到include中, 不然loader不会去转译
path.resolve(__dirname, "node_modules/ffformat"),
],
},
],
},
optimization: {
minimize: false,
},
};
接着是babel 的配置文件
// babel.config.json
{
"presets": [
[
"@babel/env",
{
// 指明 corejs 的版本,(不同版本的文件和命名方式有区别,避免找文件报错, 所以要指明版本)
"corejs": 3,
// 兼容ie9
"targets": {
"ie": 9,
},
// 使用这个按需引入polyfill
"useBuiltIns": "usage"
}
]
]
}
紧接着,我们开始在 src/main.js
写上一段代码
// src/main.js
import * as ffformat from 'ffforamt';
console.log(ffformat);
然后根目录运行webpack一次 npx webpack
就可以看到 打包 main.js
的时候, 引入了一些 core-js
下面的模块, 去看 dist/main.js
, 就能看到针对一些高级特性, 有做了 polyfill
。
至此, 正常流程完。
遇到的问题
1. Babel 配置文件的问题
刚开始的时候, 用的是 .babelrc
来配置babel, 结果loader 一直不走 node_modules
, 不转译 node_modules
中的代码,卡了半天,不断找文章,后来发现了一位老哥的话。
随即将 .babelrc
重命名为 babel.config.json
, 再 npx webpack
, 成功给 node_modules
中的 ffformat
整入 polyfill
部分的代码。看到这个结果差点把我送走。 这卡了半天的问题, 改了个名字就好了。。。
2. 多种polyfill方式
-
按需引入方式, 用到哪个高级特性, 就自动加入这个特性的polyfill。 (即 本文写的方式)
-
全量引入方式。在入口文件顶部加入这两行。
import "core-js/stable"; import "regenerator-runtime/runtime";
-
动态引入方式。这个是在 polyfill.io 去配置一个外链。配置需要兼容的es版本 或者 需要的对应api。然后 用 script 标签引入该外链, 就会返回对应的一些
polyfill
代码。(因 script 的src 属于get请求, 所以服务器那边可以知道我们浏览器的 userAgent, 然后根据这个去判断我们浏览器, 给浏览器响应对应的polyfill。 所以用高版本浏览器去访问此请求, 可能返回的内容是空的)
三种方式, 感觉第一种和第三种偏好一点。
第一种的按需引入, 不会因为就一个 高级特性的api, 就导致整个bundle文件瞬间增大N多倍。
第三种则是 指定es版本, 由服务器决定需要返回哪些polyfill。这样相当于是将所有的polyfill 都抽离出去,用别人家的cdn引入进来。
至于选择上, 如果说 请求 polyfill.io 的速度过慢, 或者项目内网部署,那么选择第一种方式是更好的。
而如果项目可以访问外网资源。并且访问 polyfill.io 外链速度足够快, 那么用第三种也是极好的。
当然, 如果项目没有涉及到 webpack
, rollup
之类的构建工具, 只是纯的项目,那么只能选择第三种了。
如果没用 构架工具, 还要内网部署, 那就把外链的 polyfill 下载下来,放到本地再一并部署上去。