Vue Router 嵌套路由导致安卓低版本系统 WebView H5 页面空白

1,007 阅读6分钟

背景

混合应用,App 嵌套 H5,H5 技术栈:vue 2.6。 项目本身不是从零开发的。

问题

原生 app 访问 H5 功能页面XXX,在 vivo x21 i 机型上页面空白。

探究过程

一、初诊断

因为没有这个机型,所以通过 wetest 的云真机测试,结果能够复现。

面对这个问题,首先想到的是看看控制台有没有报错,开发环境包打开 vconsole。结果是 console 没有任何报错。

接口也没有异常。

二、看代码

那么到底有什么特殊情况呢?还是先看看代码。

发现原生先是到 A 页面,然后跳转到 B 页面。会不会是在跳转的过程中发生了什么?

再仔细观察效果,打开 A 页面似乎能看到页面已经渲染元素,然后页面空白。

三、手机浏览器中

本地测试当然没有问题,访问 A 页面正常跳转 B 页面。

对应的机型上,看浏览器能否打开 A 页面?看能否正常跳转 B 页面?一开始发现浏览器也不能正常打开,因为地址有传参,而且在 app 中有 token,这些在浏览器中都没有,所以并不能把直接在浏览器中打开页面和在 app 中打开同等看待。浏览器中页面空白是因为接口报错。

好在 H5 逻辑已经有处理请求的 header 参数(同时在 localstorage 中获取),所以只浏览器的本地存储中设置 token;而路径地址上的传参没有问题,在路径上添加参数就可以。

在云真机上做所有这些操作简直考验人的耐心,所以一度还写错一个本地存储字段。周折一些时间。

最终,证明浏览器中访问 A 页面正常,跳转 B 页面也正常。

四、怎么调试

同事认为空白可能是 ES6 兼容的问题。搜了一下,可以尝试处理试试。那问题来了,怎么调试呢?平时改 bug 无非是本地启动修改,浏览器中看效果。现在我们要在特定的机型上、从 app 中打开页面查看效果,而且只能通过云真机测试。

我想,如果有真机,可以通过将开发环境映射为本地环境,这样就可以修改本地代码来调试。

通过云真机,我们只能每次改动,每次让安卓开发给我打个包,再上传 app,这样简直不敢想……

后来明白,安卓的包并不需要改,我们只需要改前端项目即可,不过需要发布到开发环境,这样才能生效。虽然还是比较麻烦,不过也不是不可行,至少不需要麻烦别人了。

然后要尽可能的尝试可能的原因,不能盲目的试错。

五、vue cli3 安卓低版本 兼容问题 babel-polyfill

根据以上关键词搜索了一些文章,大致都差不多。做了以下处理:

新增 .babelrc:

{
  "presets": ["@babel/preset-env"],
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

修改 babel.config.js:

module.exports = {
  presets: [
    '@vue/app'
    [
      '@vue/app',
      {
        'useBuiltIns': 'entry',
        polyfills: [
          'es6.promise',
          'es6.symbol',
          'es6.array.iterator',
          'es6.object.assign',
          'es6.let'
        ]
      }
    ]
  ],
  plugins: [
    ...
  ]

修改 vue.config.js:

transpileDependencies: ['node_modules/webpack-dev-server/client'],
  chainWebpack: config => {
    config.entry.app = ['babel-polyfill', './src/main.js'];

修改 main.js:

import 'babel-polyfill'
import Es6Promise from 'es6-promise'
Es6Promise.polyfill()

安装依赖:

npm install --save-dev @babel/core @babel/plugin-transform-runtime @babel/preset-env es6-promise @babel/polyfill

最终无法修复。

六、vue router replace 页面空白

这个 github.com/vuejs/vue-r… 中反馈了router replace 的问题,然后尝试用 push 替换 replace,发现也没有解决问题。

然后又去了解了下 router 的实现原理。

尝试直接 location.replace(B),依然不行。

尝试 location = B,不行。

七、不通过A,直接访问 B 页面

在我们目前的业务中,可以不通过 A,直接访问 B,于是让安卓开发帮忙打个包,直接访问 B,然后在云真机上测试,仍然有问题。

这么做,进一步确定为就是B的问题,跟跳转无关。虽然一开始说 A 页面渲染,就可以排除这一点了。

八、测试 B 页面

既然就是 B 页面的问题,感觉离解决问题越来越近了。我们把 B 页面简化到:

<template>
  <pages id="page">
    <div class="list-tips">测试</div>
  </pages>
</template>

发现页面仍然是空白,似乎连 app 的页面 title 也没有了。

九、vue-router 路由

看似很接近了,突然又没了思路。

  • <pages> 是什么组件?跟这个有关吗?
  • 上面说的 title 在 js 中赋值,说明页面 js 正常执行了

再一次确认 app 打开其他页面正常,那么如果这里不是打开 B 页面而是其他页面呢?如果 B 页面路由到其他页面呢?

检查 B 页面的路由文件:

export default [
  {
    path: '/prescribe',
    name: 'prescribe',
    component: Prescribe,
    redirect: '/prescribe/prescriptions',
    children: [
      {
        path: 'prescriptions',
        name: 'prescriptions',
        component: PrescriptionList
      },

跟 redirect 有关吗?没有关系,这里是父路由的重定向。

那么跟能够正常打开的页面的路由对比一下?没有使用 nested routes,没有 children。

测试一下:

{
  path: '/prescribe/prescriptions',
  name: 'prescriptions',
  component: PrescriptionList,
}

哦吼!正常打开!

十、解决

那么这到底是什么原因呢?vue-router 嵌套路由在安卓低版本的 webview 中导致页面空白,搜了一下,没有相关的文章,似乎库也没有相关的 issue,这很正常,因为在浏览器中都是正常的。那么低版本的安卓的 webview 到底有什么特殊?这一点我暂时也不知道怎么探索验证。

解决当然就只能不用嵌套路由咯。

网上很多关于嵌套路由页面空白的问题,要么是子路由多写了/,要么是其他问题。

总结

如果回过头来看,似乎早就应该意识到问题所在,但问题是当你困在问题当中时,就很难理清思路。而且对整个项目不了解,就会怀疑是某些环节出了问题。最后是云真机真的很难用。

最后真的想吐槽 Vue,这是什么坑爹设计,页面空白,不报错,真让人吐血…… 没有经验的人真的要浪费时间,以前经典的白屏问题,控制台至少也报错。

参考