背景
- Vite + Vue3
- 多页面打包
- APP 嵌入混合开发
问题
在安卓 WebView 中加载 Web 页面显示黑屏,后来 APP 排查发现如下报错:
Uncaught SyntaxError: Unexpected token '?'
这是线上地址,于是查看打包的这个文件,但是 ? 又看不出来什么。
昨天在 iOS 加载 H5 正常,所以是安卓 WebView 的问题。
但是记得之前安卓也没问题啊,后来想起来之前只是在本地测试安卓,而且是做多页面设置之前。
于是加载本地开发地址,又有了新的报错:
I/chromium: [INFO:CONSOLE(11)] "Uncaught SyntaxError: Unexpected token '.'", source: http://10.227.198.175:5173/pages/signin/App.vue (11)
类型是一样的,而且有了位置,又是在本地调试,所以排查更方便了。
分析
首先是语法问题,猜测是 ES6 以上的语法不支持。经过排查,很快定位是可选链 (?.) 语法的问题:
obj.val?.prop
改为:obj.val && obj.val.prop 就好了。页面正常显示。
修复
了解了原因之后,修复就简单了。问自己两个问题:
- Vite 在生产环境打包会进行编译语法转换吗?
- Vite 在开发环境会进行编译语法转换吗?
生产环境
关于构建选项 build.target:cn.vitejs.dev/config/buil…
默认值 'modules',Vite 将替换 modules 为 ['es2020', 'edge88', 'firefox78', 'chrome87', 'safari14']。
所以默认支持的 Chrome 最小版本是 87。也就是默认除了 ES 模块、原生 ESM 动态导入相关的,有可能其他的语法不支持。
转换过程将会由 esbuild 执行,并且此值应该是一个合法的 esbuild 目标选项。自定义目标也可以是一个 ES 版本(例如:es2015)、一个浏览器版本(例如:chrome58)或是多个目标组成的一个数组。
关于浏览器兼容的介绍:cn.vitejs.dev/guide/build…
你也可以通过
build.target配置项 指定构建目标,最低支持es2015。
关于 esbuild target:esbuild.github.io/api/#target
For example, the
??operator was introduced in Chrome 80 so esbuild will convert it into an equivalent (but more verbose) conditional expression when targeting Chrome 79 or earlier.
这个过程是由 esbuild 就行转换,只是要设置想要的目标选项。
target 未设置之前,打包的文件:
可以搜索到 ??。
target 设置为 es2015:
但是 Vite 最低支持 es2015,也就是 ES6,如果想要支持 ES5,需要引入 Babel 和相应的插件,需要在项目中安装 Babel 和预设:
npm install --save-dev @babel/core @babel/preset-env
然后修改 babelrc:
{
"presets": [
["@babel/preset-env", {
"targets": "> 0.25%, not dead"
}]
]
}
这将使用 @babel/preset-env 预设,它会根据你的目标浏览器自动选择需要的 Babel 插件和 polyfills。
然后,你可以在你的 vite.config.ts 文件中使用 rollup-plugin-babel:
import { defineConfig } from 'vite'
import babel from '@rollup/plugin-babel'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
babel({ babelHelpers: 'bundled' })
]
})
开发环境
Vite 依赖于原生的 ES Module 导入语法,在开发时,Vite 假设你使用的是现代浏览器。Vite 在开发环境中不进行语法的转换,因此如果使用现代的 JavaScript 特性,比如可选链 (?.) 或者空值合并 (??),而使用的浏览器不支持这些特性,那么你的代码在开发环境下将不能正常运行。这也是上面安卓 WebView 在开发环境报错的原因。
所以开发环境测试就用高版本的机型吧。
验证
为什么记得之前的测试手机可以呢?原来是不同的机型。
查看可选链的兼容性:caniuse.com/?search=%3F.
Chrome 80 以上才支持。
测试手机 oppo r15x: