什么是 module/nomodule 技术
我们在打包时,如果打包目标是中底版本的浏览器,就需要插入许多兼容函数和语法转化。
而用高版本浏览器访问,其实并不需要这些变换。如果用高版本浏览器访问,能够直接运行高版本浏览器的语法,就可以太大减小在高版本浏览器下的包体积。
使用 <script type="module"> 可以在让支持 esmodule 的浏览器运行,不支持 esmodule 的浏览器忽略。
使用 <script nomodule> 可以让支持 esmodule 的浏览器忽略,不支持 esmodule 的浏览器运行。
我们可以利用以上特性写个打包方案输出 2 个版本,用不同的配置进行使用。
比较特殊的一点是 Safari 10 两个都会运行,我们提前运行个 polyfill 就能解决。
处理高版本
高版本转化为 es2015,但是有 2 个常用的重要特性是 es2015 不支持的。
一个是 async await 一个是动态 import。
async await Babel 可以直接转,没有什么特殊处理。
动态 import 比较特殊,要先在全局变量里保存 promise 的 resolve,然后动态 import 需要动态创建 script 标签,内容大致如下
<script type="module">
import * as namespace from "模块";
__import_promise_resolve__["模块"](namespace)
</script>
我们可以把动态 import 和资源预加载和 nomodule polyfill 写成基础库放在最前面运行。
这样我们就在高版本省去了 Promises、Map、Set 的打入和 Class 、arrow functions 的转化等。
处理中低版本
中低版本,我们写个 amd 或 systemjs 的加载器放在最前面就行了。
然后我们看看效果。
Nice
处理低版本
中低版本我们也可以按照这个思路进一步细分
IE8 到 IE9 有巨大的差异,我们用条件注释在分为低中 2 个版本。
低版本不会打入其不支持的功能,中版本也不会打入已支持的功能。
还可以用别名让低版本使用低版本实现的相关库(如 anujs)
我们引入个 React 看看效果
Nice
CSS
使用这种方式 CSS 的使用我们也可以通过不同版本的 PostCSS 配置打出不同版本的 CSS 可以减少加载的代码。
打更多版本
是否能够再更包版本上进行区分?让浏览器原生运行 async await 和动态 import?
按道理是可以的,但是需要打更多版本的包。而且需要 js 判断。
我认为目前 3 个版本最佳,因为差异够大,且有 html 层的判断方式。
今后也许会有差异够大的特性需要再打一个版本的包