1

写在前面的话

日常工作中,为了提高开发能效,我们通常需要抽象整合一些代码,例如:工具库,组件库。这些库不同于我们的业务开发项目,一般形成 npm 包的形式发布,给别人调用,所以需要不同的方式去编译和打包。

需要打出什么?

结合实际生产环境的需要一般的使用场景有以下几种:

  • CommonJS 格式:提供给 WebpackBrowserify, 或者 Node 环境,SSR,Jest等
  • ES2015 的格式:直接提供模块化的方案,方便 Tree shaking
  • UMD 格式:各种兼容
  • <script> 标签注入挂载到浏览器 window 对象下,或者是 Node 的 global 下

社区的例子

Redux 的打包输出
image.png

  • dist:UMD格式,兼容 window 或 global ,同时也兼容 AMD、CommonJS格式
  • es:ES2015 的风格的模块
  • lib:CommonJS 格式
  • src:源代码

再看一下它打包的输出配置:

// package.json
...
  "main": "lib/redux.js",
  "unpkg": "dist/redux.js",
  "module": "es/redux.js",
  "types": "types/index.d.ts",
  "files": [
    "dist",
    "lib",
    "es",
    "src",
    "types"
  ],
...

现有的社区工具

  • Webpack
  • Rollup
  • Babel
  • Father(没错,就是这个名字。。。其实是 umi-library 的别名)

用什么工具?

Webpack、Rollup、Babel大家都比较熟悉,就不一一赘述了,对于工具库的打包,社区一般都是推荐 Rollup,Redux 也是用 Rollup 打包,但配置的有点多,看了下源码,大概用了 200+ 行实现。这里主要讲一下 Father ,基于 Babel 和 Rollup 的封装。

这是官网的特性:

  • ✔︎ 基于 docz 的文档功能
  • ✔︎ 基于 rollup 和 babel 的组件打包功能
  • ✔︎ 支持 TypeScript
  • ✔︎ 支持 cjs、esm 和 umd 三种格式的打包
  • ✔︎ esm 支持生成 mjs,直接为浏览器使用
  • ✔︎ 支持用 babel 或 rollup 打包 cjs 和 esm
  • ✔︎ 支持多 entry
  • ✔︎ 支持 lerna
  • ✔︎ 支持 css 和 less,支持开启 css modules
  • ✔︎ 支持 test
  • ✔︎ 支持用 prettier 和 eslint 做 pre-commit 检查

实践

在项目中用一下,看看有木有文档说的那么香

需要编译的源文件:

// src/index.js
const sum = (a, b) => a + b;
export default sum;

配置一下文件 .fatherrc.js

// .fatherrc.js
export default {
  entry: 'src/index.js',
  esm: { type: 'rollup', file: 'es/index' },
  cjs: { type: 'rollup', file: 'lib/index'},
  umd: { file: 'umd/index', name: 'father-test' }
};

输出:
image.png
比较符合我们的期望,分别输出了:UMD、CommonJS、ES2015 三种规格的代码,再来看一下具体内容。

ES2015格式的编译代码:

// dist/es/index.js
var sum = function sum(a, b) {
  return a + b;
};

export default sum;

CommonJS格式的编译代码:

// dist/lib/index.js
'use strict';

var sum = function sum(a, b) {
  return a + b;
};

module.exports = sum;

UMD格式的编译代码:

// dist/umd/index.js
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = global || self, global['father-test'] = factory());
}(this, (function () { 'use strict';

    var sum = function sum(a, b) {
      return a + b;
    };

    return sum;

})));

总体来看,还是比较香的,配置很简单,适合用于工具包的打包,输出的内容多样化,能够满足不同的使用场景。


河马嘴不大
376 声望77 粉丝

生命比你想象的要短,多写两行代码吧!少年