lanjingling0510/blog

移动端web缓存,优化第二次访问速度

lanjingling0510 opened this issue · 0 comments

移动端带宽流量要比pc端宝贵的多, 200k的资源在pc端毫无压力,但在不稳定的移动3g下,需要1s中左右。Wi-Fi情况下网络延迟很大,达到200-400ms,直接结果就是304或者200情况下css,js加载很慢,加大白屏时间。

当前问题是如何缓存webpack打包的bundle js文件,提高移动端第二次访问速度?

探索方案一:service worker cache

缓存是service worker做得很好的事情之一,要安装 service worker ,你需要在你的页面上注册。下面的代码会告诉浏览器你的 service worker 脚本在哪里。

    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('/service-worker.js').then(() => {
            console.log('Service worker registered!');
        }).catch((error) => {
            console.log('Error registering service worker: ', error);
        });
    } else {
        console.log('Not supported by browser');
    }

通过webpack.config.js配置,添加sw-precache-webpack-plugin插件

new SWPrecacheWebpackPlugin(
  {
    cacheId: 'cqaso-web-mobile',
    filename: 'service-worker.js',
    verbose: true,
  }
)

SWPrecacheWebpackPlugin是一个webpack插件,用于使用service worker来缓存外部项目依赖项。 它将使用sw-precache生成service worker文件并将其添加到您的构建目录。为了在service worker中生成预缓存的名单, 这个插件必须应用在assets已经被webpack打包之后。

然而,这个方案只能在HTTPS协议中应用,http不能生效。

探索方案二: html5离线应用缓存

离线访问对基于网络的应用而言越来越重要。虽然所有浏览器都有缓存机制,但它们并不可靠,也不一定总能起到预期的作用。HTML5 使用 ApplicationCache 接口解决了由离线带来的部分难题。

使用缓存接口可为您的应用带来以下三个优势:

  • 离线浏览 - 用户可在离线时浏览您的完整网站
  • 速度 - 缓存资源为本地资源,因此加载速度较快。
  • 服务器负载更少 - 浏览器只会从发生了更改的服务器下载资源。
    应用缓存(又称 AppCache)可让开发人员指定浏览器应缓存哪些文件以供离线用户访问。即使用户在离线状态下按了刷新按钮,您的应用也会正常加载和运行。

通过webpack.config.js配置,添加appcache-webpack-plugin插件

var AppCachePlugin = require('appcache-webpack-plugin');

module.exports = {
  plugins: [
    new AppCachePlugin({
      network: null,  // No network access allowed!
      fallback: [],
      settings: ['prefer-online'],
      exclude: [],  // Exclude file.txt and all .js files
      output: 'my-manifest.appcache'
    })
  ]
}

要启用某个应用的应用缓存,请在文档的 html 标记中添加 manifest 属性:

<html manifest="my-manifest.appcache">
  ...
</html>

鉴于项目的实时性比较强,大部分已实时数据渲染为主,离线缓存并没有什么价值。

探索方案三: LocalStorage本地缓存

基本原理就是使用md5版本号+localStorage,把静态文件存储在浏览器本地数据,利用js控制js的加载运行。

配置webpack, 提取入口文件公共chunks, 只要chunks内容不变,打包后的chunks代码就不会改变,md5文件名就不会变。

    new webpack.optimize.CommonsChunkPlugin({
        name: [
            'vendor', 'manifest'
        ], // vendor libs + extracted manifest
        minChunks: Infinity
    }),

    new webpack.HashedModuleIdsPlugin(),

    new WebpackChunkHash(),

通过webpack的html-webpack-plugin插件,配置ejs模板, 使用lsLoader.js异步请求js文件,顺序运行,存储到localstorage中,第二次访问直接从localstorage运行。版本更新后,md5文件名变化的从新请求,更新相应的localstorage。

	 <script src="/lsLoader.js"></script>

    <!-- lsLoader加载chunks -->
    <script type="text/javascript">
        lsloader.load("manifest", "<%= htmlWebpackPlugin.files.chunks['manifest'].entry %>");
        lsloader.load("vendor", "<%= htmlWebpackPlugin.files.chunks['vendor'].entry %>");
        lsloader.load("main", "<%= htmlWebpackPlugin.files.chunks['main'].entry %>");
    </script>

1

3G网下缓存前和缓存后的访问速度对比

第一次访问
2

第二次访问
3

3G网下毫无压力,该方案兼容良好