问题
用 Vue3 实现了一个 h5 页面,运行在低版本 Android 的 WebView,会出现无法解析高级语法的问题,导致页面无法正常显示,或者功能异常的现象。
原因
项目是使用 Vite 搭建的,但是缺少了 babel 配置,虽然 Vite 正常来说不用配置 babel:
-
Vite 默认使用 esbuild 进行依赖预构建和 TypeScript/JSX 的转换
-
esbuild 比 Babel 快 10-100 倍,性能更优
-
在开发环境中,Vite 利用浏览器原生 ESM 能力,无需像 Babel 那样进行完整的代码转换
-
在生产构建时,Vite 使用 Rollup 进行打包
-
除非你有特殊的转换需求,否则使用 Vite 时完全不需要手动配置 Babel。Vite 的现代构建方案已经很好地解决了代码转换和兼容性问题。
但在低版本Android的 webview 中,会出现 Vue3 项目不兼容的问题,造成这个问题的原因可能有:
-
低版本 Android 系统的 WebView 不支持某些现代 JavaScript 特性
-
Vue3 使用了 Proxy 等现代特性,在低版本设备上需要降级处理
-
缺少必要的 polyfills 支持
解决
- 方案一:在项目入口添加 polyfills,对 JS 高级语法做降级处理(对所有环境生效)
/**
* 确保在应用程序代码之前引入 polyfill
* 兼容低版本安卓
*/
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import { createApp } from 'vue';
import App from './App.vue';
import router from '@/router';
// import '@/mocks';
import '@/assets/css/reset.scss';
import '@/assets/css/font.scss';
import '@/assets/css/global.scss';
import 'vant/lib/index.css';
import '@/assets/css/vant.scss';
import { createPinia } from 'pinia';
import VConsole from 'vconsole';
(function () {
window.web_hidePage = function () {}
window.web_showPage = function () {}
if (import.meta.env.VITE_VUE_APP_ERUDA_OPEN !== '1') {
return;
}
new VConsole();
})();
const app = createApp(App);
const pinia = createPinia();
app.use(router);
app.use(pinia);
app.mount('#app');
// micro-app 微前端,卸载应用,子应用卸载时会自动执行window.unmount
window.unmount = () => {
app.unmount();
};
同时需要安装相关的依赖
"dependencies": {
"core-js": "^3.39.0",
"regenerator-runtime": "^0.14.1"
},
- 方案二:配置 vite.config.ts 的 legacy
import { defineConfig, loadEnv } from 'vite';
import legacy from '@vitejs/plugin-legacy';
export default ({ mode }: { mode: string }) => {
const env = loadEnv(mode, process.cwd());
return defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11', 'Chrome >= 53', 'Android >= 6'],
additionalLegacyPolyfills: ['core-js/stable', 'regenerator-runtime/runtime'],
}),
],
});
};
同时需要安装相关的依赖
"dependencies": {
"core-js": "^3.39.0",
"regenerator-runtime": "^0.14.1"
},
其他问题
在测试过程中,发现不同手机厂商在相同的 Android 版本中的表现也有差异,比如有些手机支持某些高级 JS 语法,有些手机却不支持,所以最终经过测试了好几台主流厂商的Android6及以上的安卓机之后,发现上面写的 polyfills 降级处理是最全面的,应该能兼容很大一部分的Android6以上的机型。