解决移动端h5的动态polyfill问题

背景

目前咱们h5主要是面向两个app,V(简称)以及W(简称)(都只是安卓端),基本都是基于这两个app的webview作一些活动 W(简称) 面向最低的Android版本是4.1,V(简称) 面向最低的Android版本是4.0。低版本的手机js环境比较老,所以一些咱们要针对低版本的手机作一些polyfill补充(例如babel-polyfill,react-intl的polyfill => intl,vw/vh 等等)。php

咱们的polyfill主要是针对在4.2以及4.2如下的手机.css

这是 V(简称) 的手机型号用户占比: 4.2以及如下的手机uv大概100万,占比大概1.72%
html

image.png

这是 W(简称) 的手机型号用户占比: 4.2以及如下的活跃设备数量大概350万,Dau大概120万,4.2如下的设备大概1.5万,占比不到1%
react

image.png

目前的策略

目前咱们的方法是统一引入这些polyfill!
这是咱们某个活动页面的build出来的结果,用BundleAnalyzerPlugin查看能够看到,整个活动应用300多kb,而 code-js(babel-polyfill) + react-intl/lib  就已经占了200多kb! 即便gzip以后传输也得66kb。
webpack

image.png

痛点

  1. 这些polyfill其实只是不多的一部分机型须要,而如今的状况是全部的用户都要承受加载它们的痛苦。
  2. 咱们活动的dau和pv很大(斋月活动等dau达到200-300万),加载多余的js也消耗咱们不少的流量费用。

解决方案

对于babel-polyfill

由于目前咱们的h5主要是面对于app的webview,app提供给咱们 jsBridge 让咱们拿到手机的版本信息。
咱们没有必要直接统一引入babel-polyfill,由于只有一小部分的用户须要,吸取阿里巴巴的babel-polify动态接入方案,它们提供了对应的polyfill cdn.git

//polyfill.alicdn.com/polyfill.min.js?features=default,es2017,es6,fetch,RegeneratorRuntime
复制代码

而咱们能够在拿到手机的版本后,判断低于4.2及如下的版本,才引入cdn作兼容处理。es6

对于react-intl(国际化)

与babel-polyfill相似,react-intl 须要给没有内嵌intl的手机引入intl包,咱们能够判断window.Intl对象是否存在,不存在就动态下载这个包而且引入(要考虑阻塞渲染的状况)。github

import * as React from 'react';
import request from "request";
import Spinner from "@/component/welike_spinner/welike_spinner"
import { IntlProvider } from "react-intl";
interface Props {
  messages: Object;
  children: React.ReactNode;
}
/**
 * 多语言组件,由于某些浏览器没有内嵌intl,因此会报错,
 * 这时候须要动态下载polyfill,避免了不须要intl的用户的冗余加载
 */
const INTL_CDN = '//cdn.polyfill.io/v2/polyfill.js?features=Intl.~locale.en'
export default React.memo<Props>(({ messages, children }) => {
  //是否原本就有intl
  const hasIntl = !!window.Intl;
  const [loading, setLoadingState] = React.useState(!hasIntl);
  //若是没有,就去下载
  if (!hasIntl) {
    request.loadScript(INTL_CDN).then(() => {
      //下载完才真正的展示UI
      setLoadingState(false);
    }).catch(err => {
      console.log(err);
    })
  }
  return !loading ? <IntlProvider key={'en'} locale={'en'} messages={messages}>
    {children}
  </IntlProvider> : <div style={{ position: 'absolute', top: '0', left: '0', width: '100%', height: '100%' }}>
      <div style={{
        position: 'absolute',
        left: '50%',
        top: '50%',
        transform: 'translate(-50%, -50%)'
      }} >
        <Spinner />
      </div>
    </div>

})

复制代码

能够看到,改为动态加载后,少了快40kb的资源!web

对于vw vh兼容性

image.png
能够看到,针对安卓Browser,vw,vh只能向下支持到4.3.

  1. 为了移动端浏览器能安全的使用vw单位实现多屏适配,从而让css代码运行在各类尺寸的手机屏幕上,而且和设计稿保持一致
  2. 技术方案为:经过js动态判断当前浏览器是否支持vw单位,若是不支持,把全部css样式中vw转为rem,并设置html font-size为当前浏览器宽度 的 1/100, 从而使1rem=1vw;
  3. write once run everywhere, 开发者无需考虑多屏适配问题和vw兼容问题
  4. 使用尽量简单,代码量尽量少,尽量不阻塞页面基础样式和逻辑 使用vw-polyfill能够解决这个问题。

不仅是vw,vh. 还有其余的一些css属性也要作兼容,这个得一步步地去测试以及优化了.npm

Last but not least

因为随着咱们项目愈来愈大愈来愈多,咱们须要引入的polyfill的场景以及条件都愈来愈多。
参考咱们的设备占比数据,其实4.2如下的设备占比比较小,因此咱们开发的时候须要取决成本和人力以及收益去判断是否必要去作这些兼容性,若是有些项目不须要兼容,有些项目须要,咱们能够在webpack的entry统一配置是否须要兼容的字段,不须要兼容的,咱们直接默认给一个相似提示更新的优雅降级操做便可。

参考文献

  1. 动态Polyfill解决方案
  2. Polyfill 方案的过去、如今和将来
  3. react-intl-polyfill
  4. vw-polyfill
相关文章
相关标签/搜索