-
Notifications
You must be signed in to change notification settings - Fork 324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Polyfill 方案的过去、现在和未来 #80
Comments
mark |
脸上写满了认真,赞 |
如何兼顾开发效率和性能,是每个开发需要思考以及持续优化的地方 |
真棒 云谦师兄 |
👍 |
mark cdn那个有点意思,。, |
mark |
目前看useBuiltIns是不是用usage更合适一点? |
受益良多! |
polyfill.io 这块想试一下,但是发现微信浏览器下访问 |
@sorrycc @jamieYou 你说的服务应该是(CBU)这边做的auto polyfill服务,用了他们的library,上层实现不太一样,主要是从性能和可靠性上有些考量。已经在多个BU落地了哈~~~ 具体链接是:https://polyfill.alicdn.com/polyfill.min.js?features=Promise 现在覆盖了阿里系的绝大部分webview,以及chrome/safari/firefox/IE/EDGE这些,至于微信的webview还不支持,因为这一块需求不是很强烈,就没有去做,一旦有诉求我们会去加进来的~~ 花名:亦昼 |
@sleagon 一个项目用到哪些 features 是怎么收集的? |
我们没有收集开发者用到了什么features,这个暂时还没想到什么好的方案来自动采集,因为一方面现在不少页面是以区块为维度开发的,自动采集不太现实,另一方面跟你说的那样,node_modules里的polyfill容易被漏掉。目前还是靠开发者手动去添加features列表,我们也提供了类似polyfill.alicdn.com/modern/polyfill.min.js 这样的默认带了es6/es7的比较全的集合,以及只带了基本的polyfill的链接。 |
什么时候 umijs 实现啊,期待ing |
维护个 polyfill.io 服务的成本也不小,又想追求性能,又想提效,可以折中下,根据业务场景分个类,允许少量冗余,这样就不会出现 chrome 下也加载给 ie 打得补丁了,也不用挨个打补丁 |
对的,这也是我们搞类似polyfill.alicdn.com/default/polyfill.min.js和polyfill.alicdn.com/modern/polyfill.min.js这类链接的原因,一个提供了基本支持,一个提供了es6/es7之类的,默认集合,免得每个人都去配一串链接 |
赞 present-env + useBuiltIns: 'usage' 应该是不错的选择, 最近正好也在看这个。 |
@sleagon ali的这个polyfill现在算是公开的服务吗? 还是只是你们内部使用的? 谢谢 |
更新下 corejs@3 的方式
|
@HaveF 目前没做限制,不过目前更多地还是针对阿里系和几个大的浏览器做了匹配,你基本可以按照目前开源社区的用法来用都是OK的,后面也有考虑直接放出去用。 @sl1673495 现在babel这种usage的标识支持的能力还是有限的,如果你用了Usage,是不会注入类似fetch这种浏览器api性质的polyfill的,它只会处理es标准的polyfill,还是需要你去手动处理其他的polyfill的。 |
赞!看了好几遍 |
polyfill.io 服务端的成本太大,如果用第三方提供的服务,不敢保证。 其实 @babel/preset-env + useBuiltins: entry + targets 感觉已经解决很多问题了。 当然如果成本允许 polyfill.io 也挺好 |
好文 收藏先 |
有没有好用的 lint 工具,来禁止使用 无法被 babel transform / 配置了 exclude 的语法呢? |
赞 云谦 大佬 |
文章里面有提到关于node_modules下面的package也需要走编译的流程,这块的内容是如何实践的?通过 webpack plugin 进行 babel-loader 的匹配和加入的工作么? |
mark |
1 similar comment
mark |
任何一个小知识点,深挖下去,也是非常有意思的。
什么是补丁?
我们希望浏览器提供一些特性,但是没有,然后我们自己写一段代码来实现他,那这段代码就是补丁。
比如 IE11 不支持 Promise,而我们又需要在项目里用到,写了这样的代码:
这时在 IE 下运行就会报错了,
然后在此之前加上补丁,
刷新浏览器,就可以正常运行了,
过去
shim + sham
如果你是一个 3 年陈 + 的前端,应该会有听说过 shim、sham、es5-shim 和 es6-shim 等等现在看起来很古老的补丁方式。
那么,shim 和 sham 是啥?又有什么区别?
babel-polyfill.js
在 shim 和 sham 之后,还有一种补丁方式是引入包含所有语言层补丁的
babel-polyfill.js
。比如:然后就 es6、es7 特性随便写了。
但缺点是,babel-polyfill 包含所有补丁,不管浏览器是否支持,也不管你的项目是否有用到,都全量引了,所以如果你的用户全都不差流量和带宽(比如内部应用),尽可以用这种方式。
现在
现在还没有银弹,各种方案百花齐放。
@babel/preset-env + useBuiltins: entry + targets
babel-polyfill 包含所有补丁,那我只需要支持某些浏览器的某些版本,是否有办法只包含这些浏览器的补丁?这就是
@babel/preset-env
+useBuiltins: entry
+targets
配置的方案。我们先在入口文件里引入
@babel/polyfill
,然后配置 .babelrc,添加 preset
@babel/preset-env
,并设置useBuiltIns
和targets
,useBuiltIns: entry
的含义是找到入口文件里引入的@babel/polyfill
,并替换为 targets 浏览器/环境需要的补丁列表。替换后的内容,比如:
这样就只会引入 chrome@62 及以上所需要的补丁,什么 Promise 之类的都不会再打包引入。
😄
🤔
细细想想,其实还有不少问题,
@babel/preset-env
有提供 exclude 的配置,如果我配置了 exclude,后面是否得小心翼翼地确保不要用到 exclude 掉的特性chrome: 62, ie: 9
,那意味着 chrome 62 也得载入 ie 9 相关的补丁,这也是一份冗余手动引入
传统的手动打补丁方案虽然低效,但直观有用。有些非常在乎性能的场景,比如我们公司的部分无线 H5 业务,他们宁可牺牲效率也要追求性能。所以他们的补丁方案是手动引入 core-js/modules 下的文件,缺啥加啥就好。
注意:
在线补丁,比如:polyfill.io
前面的手动引入解决的是特性列表的问题,有了特性列表,要做到按需下载,就需要用到在线的补丁服务了。目前最流行的应该就是 polyfill.io,提供的是 cdn 服务,有些站点在用,例如 https://spectrum.chat/。另外,polyfill.io 还开源了 polyfill-service 供我们自己搭建使用。
使用上,比如:
然后在 Chrome@71 下的输出是:
/* Disable minification (remove `.min` from URL path) for more info */
啥都没有,因为 Promsie 特性 Chrome@71 已经支持了。
未来
关于补丁方案的未来,我觉得按需特性探测 + 在线补丁才是终极方案。
按需特性探测保证特性的最小集;在线补丁做按需下载。
按需特性探测可以用
@babel/preset-env
配上targets
以及试验阶段的useBuiltIns: usage
,保障特性集的最小化。之所以说是未来,因为 JavaScript 的动态性,语法探测不太可能探测出所有特性,但上了 TypeScript 之后可能会好一些。另外,要注意一个前提是 node_modules 也需要走 babel 编译,不然 node_modules 下用到的特性会探测不出来。在线补丁可以用类似前面介绍的 https://polyfill.io/ 提供的方案,让浏览器只下载必要的补丁,通常大公司用的话会部署一份到自己的 cdn 上。(阿里好像有团队部署了,但一时间想不起地址了。)
FAQ
组件应该包含补丁吗?比如 dva 里用了 Promise,是否应该把 Promise 打在 dva 的产出里?
不应该。 比如项目了依赖了 a 和 b,a 和 b 都包含 Promise 的补丁,就会有冗余。所以组件不应该包含补丁,补丁应该由项目决定。
组件不包含补丁?那需要处理啥?
通常不需要做特殊处理,但是有些语言特性的实现会需要引入额外的 helper 方法。
比如:
编译后是:
然后我们会有很多文件,每个文件都引入一遍 helper 方法,会有很多冗余。所以我们通常会使用 @babel/plugin-transform-runtime 来复用这些 helper 方法。
在
.babelrc
里配置:编译后是:
所以,组件编译只要确保没有冗余的 helper 方法就好了。
core-js/library or core-js/modules?
core-js 提供了两种补丁方式。
core-js/library
,通过 helper 方法的方式提供core-js/module
,通过覆盖全局变量的方式提供举个例子,
.babelrc
配:编译结果是:
然后把文件内容换成:
.babelrc
配:编译结果是:
然后
@babel/runtime-corejs2/core-js/promise
的内容是:目前推荐是用
core-js/modules
,因为 node_modules 不走 babel 编译,所以core-js/library
的方式无法为依赖库提供补丁。非 core-js 里的特性,如何打补丁?
手动引入,比如 Intl.js、URL 等。但是得小心有些规范后续加入 ecmascript 之后可能的冗余,比如 URL。
参考
The text was updated successfully, but these errors were encountered: