UmiJS ES5兼容性配置

目前在做的APP内嵌项目中,使用了UmiJS来做多页开发。Umi的默认配置对各平台较老版本支持并不太友好:

targets: { chrome: 49, firefox: 45, safari: 10, edge: 13, ios: 10 }

作为开发我们当然想要这样的兼容列表,奈何产品不允许~~

因为Umi跟我们做了很多封装,有很多的基础设置我们开始阶段并不需要处理,但是随着项目深入,慢慢就会有问题体现出来。

在开发阶段发现功能在iOS 10Android 7.0上页面白屏,这里自然怀疑兼容问题。于是立马修改了targets的配置:

{ ios: 8, android: '4.4' }

问题依旧存在,转而引入babel-polyfill打算先暴力处理完成需求开发,在做后续优化。但是意外的是白屏问题依旧存在并没有被解决,那就只能暂停开发,先解决这个问题了。

首先根据控制台的错误信息:

SyntaxError: Unexpected token '*'

定位到应该是使用的swiper使用的连乘有兼容性的问题。这里查看一下swiper包的package.json文件:

"main": "dist/js/swiper.js",
"jsnext:main": "dist/js/swiper.esm.bundle.js",
"module": "dist/js/swiper.esm.bundle.js",

我们可以看到它提供了3种引用方式,在main入口文件是兼容到ES5的,而jsnext:**mainmodule因为webpack/rollup要用到ES2015的module语法去做tree-shaking,故而往往包含着ES2015的语法。

所以最快的解决方式是:

1
import Swiper from 'swiper'; --> import Swiper from 'swiper/dist/js/swiper.js';

但是这样肯定不是最优的,比如没法用到tree-shaking来对包体积进行优化等。

如果不用上述方式,那我们引入的还是包含ES2015语法的包,但是最终打包文件还是会报错,也就是说打包时并没有对引入的第三方包进行转义。如果是自己搭的webpack配置,直接在babel-loader中配置对swiper进行编译就好:

1
2
3
4
5
6
7
{
test: /\.js$/,
exclude: function(modulePath) {
return /node_modules/.test(modulePath) &&
!/node_modules\/${include_module}/.test(modulePath);
}
}

Umi中则是通过配置extraBabelIncludes来决定哪些第三方模块需要编译:

1
2
3
4
5
export default {
extraBabelIncludes: [
(filePath) => true | false,
]
}

所以最终在.umirc.js中配置成:

1
2
3
extraBabelIncludes: [
content => /swiper|dom7/.test(content)
],

便能解决swiper的兼容性问题。

但是每次都在打包上线后发现问题,再决绝终归是不好的,umi提供了一个umi-plugin-ecma5-validator插件,让我们在打包文件的过程中就能知道有哪些第三方模块是没有转换成ES5的。上面的dom7就是通过这个发现的。

使用起来也是很简单,只要配置好插件,打包时如果出现报错,再执行:

COMPRESS=none umi build

不对文件进行压缩,就能看到详细的错误提示了, 然后再针对指定模块进行处理就好了。

参考

safari浏览器报错: SyntaxError: Unexpected token ‘*’

uglify 压缩报错问题及 es5-imcompatible-versions

How to exclude node_modules but one

Confused about fields “module” and “jsnext:main” in package.json? Why are both needed?

jsnext:main – should we use it, and what for

0%