webpack 集成 basket.js 实现 localStorage 本地缓存

basket.js 是什么

basket.js 可以用来加载 js 和 css 脚本并且保存到 LocalStorage 上,使我们可以更加精准地控制缓存,即使是在 http 缓存过期之后也可以使用。因此可以使我们防止不必要的重新请求 js 脚本,提升网站加载速度。

basket.js 的简单使用方式

basket.require({url: 'helloworld.js'});

和浏览器缓存相比的优势

在 PC 端和浏览器缓存相比没有任何优势,移动端 SPA 值得尝试。
(特别是在某信的 WebView 里,304 缓存的时间短如小香菇 2333)


以下总结来自某乎

PC 上应用价值不大的原因在于:

  • 兼容性不太好,不支持 LS 的浏览器比例仍然很大
  • 网络速度快,协商缓存响应快,LS 读取 + eval 很多时候会比不上 304
  • 通常需要 SEO,导致 css 不能缓存,仅缓存 js 使得整个缓存方案意义进一步减小
  • 浏览器本地缓存足够可靠持久
  • 跨页面间共享缓存即便有浪费也差别不大

移动端 webapp 值得一试的原因在于:

  • 兼容性好
  • 网速慢,LS 读取 + eval 大多数情况下快于 304
  • 都说是 webapp 了,不需要 seo,css 也可以缓存,再通过 js 加载
  • 浏览器缓存经常会被清理,LS 被清理的几率低一些
  • 以模块文件为单位,缓存失效率低
  • 不同页面状态直接访问、二次访问、页面状态跳转资源组合是不确定的,不能通过 url 来缓存资源,否则就不 “增量” 啦

暗中观察

以最常见的 vue-cli 来举例(PS:虽然不用 Vue,但是它的 webpack 配置还行,直接抄了),默认会打包出以下几个 js 文件,在 Chrome 的 network 选项卡中可以看到加载过程。

改造 HtmlWebpackPlugin 的模板文件

在 ejs 模板中加入以下代码, keys 数组可能需要对应自己的 entry 名来修改。

<% if (process.env.NODE_ENV === 'production') { %>
    <script src="<%=htmlWebpackPlugin.files.publicPath %>basket.full.min.js"></script>
    <script>
      <%
      var resources = [];
      var keys = ["manifest", "vendor", "main"];
      // css
      for (var css in htmlWebpackPlugin.files.css) {
        resources.push({
          url: htmlWebpackPlugin.files.css[css],
          execute: false
        });
      }
      // js
      var i = -1;
      for (var chunk in htmlWebpackPlugin.files.chunks) {
        i++;
        resources.push({
          url: htmlWebpackPlugin.files.chunks[chunk].entry,
          execute: true
        });
      }
      %>
      (function(b) {
        b.require.apply(this, <%=JSON.stringify(resources) %>)
          .then(function(responses) {
            responses.forEach(function(response) {
              if (!response.execute) {
                var style = document.createElement('style');
                style.innerHTML = response.data;
                var head = document.getElementsByTagName('head')[0];
                head.appendChild(style);
              }
            });
          });
      })(basket);
    </script>
<% } >

webpack 配置文件也需要相应修改,因为没有用到 CDN 上的 basket.full.min.js ,所以就自己本地托管吧。
使用 CopyWebpackPluginnode_modules 目录中的 js 复制到打包目录下:

 new CopyWebpackPlugin([
      {
        from: path.join(__dirname, 'node_modules/basket.js/dist/basket.full.min.js'),
        to: path.join(__dirname, 'dist')
      }
])

同时 HtmlWebpackPlugininject 选项需要设置为 false ,这样打包的时候就不会在 index.html 中置入 <script> 标签啦~(≧▽≦)/~。

大成功

重新打包编译,打开浏览器测试,可以看到结果。 basket.js 会以 ajax 的形式调用这些静态文件并缓存到 LocalStorage 里。

Screenshot from 2017-11-09 13:07:47.png

再次刷新页面,就不会有这些请求~(≧▽≦)/~ 啦。