Open SunshowerC opened 5 years ago
针对polyfill.io,会不会因为某些浏览器UA不正确而造成引入的polyfill不正确,然后报错呢...
针对polyfill.io,会不会因为某些浏览器UA不正确而造成引入的polyfill不正确,然后报错呢...
@imshgga 这是有可能的,尤其是在 Webview 场景下 UA 可能会被改得面目全非,polyfill.io 官方的 polyfill-service/issues 也有人遇到类似问题。这也是 polyfill.io 存在的问题,把主动权都交给第三方服务了,Web App 的稳定性会在一定程度上依赖 polyfill.io 服务的稳定性
请问,文中的可以搜索core-js被加载了多少个模块是什么插件实现的,谢谢
请问,文中的可以搜索core-js被加载了多少个模块是什么插件实现的,谢谢
@winnieBear webpack-bundle-analyzer
请问,文中的可以搜索core-js被加载了多少个模块是什么插件实现的,谢谢
@winnieBear webpack-bundle-analyzer
多谢,之前也用了这个插件,没发现那个输入框是干嘛用的,呵呵
@babel/polyfill为啥还需要安装这个库啊?
你好,我于近日使用"@babel/preset-env": "^7.7.1"
,babel.config.js配置如下:
const presets = [
[
"@babel/env",
{
useBuiltIns: 'usage',
corejs: 3,
modules: false,
targets: {
"esmodules": false
}
},
],
];
module.exports = {
presets,
};
当使用async语法时,看到转换后的文件中的处理为import "regenerator-runtime/runtime";
,并没有产生helpers。
第一个问题: 当前版本的preset-env以modules为标准对垫片进行引入的,而不是helpers?
然而,当设置targets: {"esmodules": true}
后再次进行转换,出现了如下helpers
function asyncGeneratorStepcatch
function _asyncToGenerator
第二个问题:是否可以这样认为:对于targets: {"esmodules": true}
的这种情况,当使用高于es6的语法(例如async)时,当前版本的preset-env会对regenerator-runtime/runtime
进行按需引入垫片的处理,且处理方式为内联的helpers?
usage和plugin-transform-runtime不能混用的...
https://github.com/babel/babel/issues/10271#issuecomment-528379505
首先安装依赖包: npm i -S @babel/polyfill @babel/runtime && npm i -D @babel/preset-env @babel/plugin-transform-runtime
babel7里都已经废弃了@babel/polyfill,你这最佳配置还需要使用它?我一直理解babel7对于polyfill的使用,应该是用@babel/plugin-transform-runtime和@babel/runtime做按需引入吧,useBuiltIns还有必要用吗?没什么用处吧
你好,您的邮件我已收到,谢谢。
前言
大家都知道 babel 是兼容对 ES6 支持不完善的低版本浏览器的转换编译器。
而 babel 其实主要做的只有两件事情:
那么废话少说,我们直接点,直接说说常见几个场景下兼容旧版浏览器的方案。
实践方案
polyfill.io
如果你的工程是用的语法是 ES5,但是用了一些 ES6+ 的API特性,那么可以直接引入:
来兼容 Web 应用不支持的 API。
原理大概是 polyfill.io 会读取每个请求的User-Agent标头,并返回适合请求浏览器的polyfill。具体的还可以自己指定加载哪些 特性的 polyfill,具体想了解更多的大家可以看看 官方文档。
优点:每个浏览器的设备加载的 polyfill 都不一样,最新的完全兼容ES6栋浏览器基本加载的 polyfill 大小为0。
缺点:
es6.array.from
特性,polyfill.io 依然可能会把该浏览器所有不支持的特性(如:es6.promise,es6.string.includes等特性)全部加载进来。@babel/preset-env 按需加载
上面提到了 polyfill.io 的一个缺点是无法按需引入,那么现在就介绍下 babel7 @babel/preset-env
@babel/preset-env 默认根据 .browserslist 所填写的需要兼容的浏览器,进行必要的代码语法转换和 polyfill
此处重点介绍一下其新推出的 useBuiltIns 选项:
import '@babel/polyfill'
, 会无视.browserslist
将所有的 polyfill 加载进来。import '@babel/polyfill'
才生效(否则会抛出错误:regeneratorRuntime undefined), 根据.browserslist
过滤出 需要的polyfill
(类似 polyfill.io 方案)import '@babel/polyfill'
(加上也无妨,编译时会自动去掉), 且会根据.browserslist
+ 业务代码使用到的新 API 按需进行 polyfill。上面提到的
useBuiltIns:'usage'
似乎已经很完美解决我们的需要了,但是我们构建的时候发现:根据上述的
useBuiltIns:'usage'
配置编译后:上述代码中,我们看到,
asyncGeneratorStep
,_asyncToGenerator
这两个函数是被内联进来,而不是 import 进来的。也就是说,如果你有多个文件都用到了 async,那么每个文件都会内联一遍
asyncGeneratorStep
,_asyncToGenerator
函数。这代码明显是重复了,那么有什么方法可以进行优化呢? 答案是
@babel/plugin-transform-runtime
@babel/plugin-transform-runtime
babel 在每个需要的文件的顶部都会插入一些 helpers 代码,这可能会导致多个文件都会有重复的 helpers 代码。
@babel/plugin-transform-runtime
的 helpers 选项就可以把这些模块抽离出来可以看到,已经没有了内联的 helpers 代码,大功告成。
总结
如果没有什么特殊的需求,使用 babel 7 的最佳配置是:
首先安装依赖包:
npm i -S @babel/polyfill @babel/runtime && npm i -D @babel/preset-env @babel/plugin-transform-runtime
配置
.babelrc.js
PS: 如果想要了解更多有关 @babel/preset-env 和 @babel/plugin-transform-runtime 的选项配置用途,可以参考我的个人总结
思考与探索(Modern Build)
上述的方案,其实还一直隐藏着一个不算问题的问题,那就是如果使用最新的浏览器,其实不需要任何的语法转换和polyfill。
那么参考下上述的 polyfill 方案,能不能实现如果低版本浏览器,就使用usage方案按需 transform + polyfill 的代码,如果是较新浏览器,就不进行任何的语法转换和 polyfill 呢?
必须能!
参考这篇文章 deploying es2015 code in production today,其中提出了基于 script 标签的
type="module"
和nomodule
属性 区分出当前浏览器对 ES6 的支持程度。具体原理体现在,对于以下代码:
支持 ES Module 的浏览器能够识别
type="module"
和nomodule
,会加载main.js
忽略main.legacy.js
,还未支持 ES module 的浏览器则恰恰相反,只会加载
main.legacy.js
。那么怎么实现优化就很清晰了:
nomodule
属性@babel/preset-env
的选项target.esmodules = true
,不转换所有的语法也不添加 polyfill,生成 ES6+ 的能被现代浏览器识别解析的代码,并给这类代码文件的 script 标签加上type="module"
常规webpack打包流程图
Modern Build 打包构建流程
Modern Build 注意事项
<link href="app.css" rel="stylesheet" onload="this.media='all'" media="nope!">
动态加载,不然也会下载两份代码只执行一份都下载的情况:
只下载一份的情况
参考文献: type module 执行顺序