性能分析(一)前戏:用 rollup 打包一个 js-sdk

5,182 阅读4分钟

在开启这个篇章之前,我决定先开一篇来讲一下rollup,毕竟干活嘛,前戏要足。

做一个抉择,rollup vs webpack

webpack 于 2012 年由 Tobias Koppers 创立,旨在解决现有工具无法解决的难题:构建复杂的单页应用程序(SPA)。特别是两个功能对后期产生了很大的影响:

  1. Code-splitting,通过代码拆分,可以将您的应用程序拆分为可管理的块,这些块可以按需加载。这意味着您的用户获得交互式站点的速度要比等待整个应用程序下载和解析的速度快得多。

  2. Static assets,可以将静态资产(例如图像和 CSS)导入到您的应用中,并仅将其视为依赖关系图中的另一个节点。

rollup 的创立确实因为另外的原因,利用 ES2015 模块的巧妙设计,尽可能高效地构建 JavaScript 库的统一可分发版本。

让我们逐个功能看看对比两者之间的不同

以下内容来自 webpack 官网: webpack.js.org/comparison

功能 webpack rollup
按需加载 Yes No
AMD define Yes rollup-plugin-amd
AMD require Yes No(个人使用发现是支持)
AMD require 按需加载 Yes No
CommonJS exports Yes commonjs-plugin
CommonJS require Yes commonjs-plugin
CommonJS require.resolve Yes No
Concat in require require("./fi" + "le") Yes No
Debugging support SourceUrl, SourceMaps SourceUrl, SourceMaps
Dependencies 19MB / 127 packages ?MB / 3 packages
ES2015 import/export Yes Yes
Plugins Yes Yes

大概放出来这么多,其他的大家可以去链接地址去看看。

从这个对比,我们可以看出,webpack简直是完胜,甚至rollup感觉很丢人,什么都不行,你活在这个世上还有什么意义?

存在即合理 —— 黑格尔

让我们拿出来一行有趣的对比:

功能 webpack rollup
Dependencies 19MB / 127 packages ?MB / 3 packages

19MB?意味着什么?意味着一个用户如果以 1m/s 的速度,需要 19s 才能下载完这个 js。很可怕不是吗?这个时候,你突然想到,我可以压缩啊,是的,我们可以利用uglify或者Terser进行压缩,但是,仍然,我们不可避免的,19M 就算利用了压缩,也仅可以压缩在 6M 左右,如果再利用分chunk的形式,我们可以将主包降低到 2M 左右,但是这仍然是一个可怕的数字,空白的项目,都是这个大小,更何况我们会引入其他的包呢?

反之rollup注意到了这点,所以我们用 rollup 打包的空白项目,仅有几 kb。

Use webpack for apps, and Rollup for libraries

没错,webpack确实很强大,但是也是有应用范围的,应用是他的立足之地,如果是一个 libraries,则可以使用rollup

2. 使用并且打包一个js-sdk

首先,我们定一个需求: 我们要收集用户的性能数据。

打开掘金的推荐页面https://juejin.im/timeline/recommended,在 chrome 的控制台我们可以输入如下代码,得到数据如图 1 所示:

console.log(performance.getEntries());

准备数据

我们现在的需求是收集这条数据之前的数据上报到后端进行数据分析。

// lib/PerformanceEntries.js
export default class {
  constructor() {
    this.entries = this._handleEntries();
  }

  _handleEntries() {
    const entries = window.performance.getEntries();
    const fptIndex = entries.findIndex(entry => entry.entryType === 'paint');
    return entries.slice(0, fptIndex);
  }

  getEntries() {
    return this.entries;
  }
}

解下来我们需要把这个数据上报上去

import PerformanceEntries from './lib/PerformanceEntries';

(async () => {
  const performanceEntries = new PerformanceEntries();
  const entries = performanceEntries.getEntries();
  try {
    const res = await fetch('https://server.save.data/api/v1/entries', {
      method: 'POST',
      body: JSON.stringify(entries),
    });
    // some code...
  } catch {}
})();

写一个rollup.config.js

import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';

import { version } from './package.json';

export default {
  input: 'index.js',                              // 入口文件
  output: {
    file: 'dist/performance.{version}.js',        // 打包之后的文件名以及存放位置
    format: 'umd',                                // 以什么模式打包,支持umd,cmd,esm...
    name: 'ihap',                                 // 导出文件的名字
    exports: 'named',
  },
  plugins: {
    babel({
      exclude: ['node_modules'],                  // 忽略 node_modules
      runtimeHelpers: true,                       // 开启体积优化
    }),
    commonjs(),
    resolve({
      mainField: ['jsnext', 'main'],
      browser: true,
    }),
    terser(),
  },
}

babelrc还是不可少

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-external-helpers",
    "@babel/plugin-transform-runtime",
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}

执行,看看结果

ok,没有什么问题,我们执行一下rollup -c

看一下我们打包之后的文件大小

仅有772b,还是很喜人的。

那么问题来了,可以用嘛?好的,我们稍微写一个简单的node,然后执行一下。

看,我们的结果发出去了。

本集总结&下集预告

如何用rollup打包一个很小的文件,我们已经学会了,下一张,我们就要针对如何进行性能分析来研究了。好的,大家下次见,我是 ihap 技术黑洞的肥少,喜欢我的话,记得关注点赞收藏,爱我的可以微信支持我给我赞赏啊!