介绍
一般来说,写完一个第三方库需要打包出三个文件夹的文件,对应三种不同模块类型
# outputpath
├── dist # umd module
├── es # es module
├── lib # commonjs module
三个模块类型
umd
-
UMD(Universal Module Definition)是 AMD 和 CommonJS 的糅合,跨平台的解决方案
- UMD 打包出来的文件可以直接通过 script 插件 html 中使用
- 我们的代码会被这样一段代码包裹起来
;(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object')
module.exports = factory()
else if (typeof define === 'function' && define.amd) define([], factory)
else if (typeof exports === 'object') exports['A'] = factory()
else root['A'] = factory()
})(window, function() {
//...
})
commonjs
-
CommonJS 模块是对象,是运行时加载,运行时才把模块挂载在 exports 之上(加载整个模块的所有),加载模块其实就是查找对象属性。
-
导出使用 module.exports,也可以 exports。就是在此对象上挂属性。exports 指向 module.exports,即 exports= module.exports
- 加载模块通过 require 关键字引用
module.exports.add = function add() {
return
}
exports.sub = function sub() {
return
}
const a = require('a.js')
es module
-
ES Module 不是对象,是使用 export 显示指定输出,再通过 import 输入。此法为编译时加载,编译时遇到 import 就会生成一个只读引用。等到运行时就会根据此引用去被加载的模块取值。所以不会加载模块所有方法,仅取所需。
export const m = 1
export {
m
}
import { m } from 'a.js'
why
- umd 为了支持使用者通过各种不同的模块类型引用,包括通过 script 使用第三方库
- commonjs 支持使用者在 commonjs 模块类型下引用,而且可以部分使用第三方库,不会引入整个库
- es module 支持使用者在 es module 模块类型下引用, 如果使用者需要对第三方库再打包时,webpack、rollup 都对 es module 有特殊的优化,只打包使用到的方法
使用 webpack 打包 umd 模块
如果使用 webpack 来打包 umd 文件,我们应该配置哪些选项
webpack config
const config = {
entry,
output: {
path: './dist',
libraryTarget: 'umd',
filename: 'index.min.js',
library: 'MyLibrary',
libraryExport: 'default'
},
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react'
}
}
}
- libraryTarget
指定打包文件的模块类型 - library
如果生成的输出文件,是在 HTML 页面中作为一个 script 标签引入,则变量 MyLibrary 将与入口文件的返回值绑定 - libraryExport
默认 webpack 会把返回值绑定在 MyLibrary 的 default 属性下, 也就是MyLibrary.default
才是我们模块的返回值。通过设置libraryExport: 'default'
,起到MyLibrary = MyLibrary.default
的效果, 不需要再通过default
属性去访问返回值 - externals
为了缩小打包文件的体积,对引用到的其他库的文件,应该过滤掉,比如在这里引用到了 react,但实际上我们并不需要把 react 一起打包进去,我们可以通过一些方式来从 node_modules 文件夹中或者全局变量中访问到 react
// webpack 会判断不同的环境,并以不同的方式去访问react
;(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require('react'))
else if (typeof define === 'function' && define.amd)
define(['react'], factory)
else if (typeof exports === 'object')
exports['MyLibrary'] = factory(require('react'))
else root['MyLibrary'] = factory(root['React'])
})
最后再配置一下 babel-loader,就能生成我们期望的 umd 文件了
使用 babel 打包 commonjs 模块
使用 babel 打包就很简单了, 先看一下 babelrc 怎么写
babelrc
{
presets: [['@babel/env', { loose: true, modules: 'cjs' }], '@babel/preset-react'],
plugins: [
['@babel/plugin-transform-runtime', { useESModules: false }],
]
}
loose
一句话解释: true 的时候代码更现代化代码量少,false 更兼容代码量也更多
modules
设置使用不同的模块类型,commonjs 的话,就设置成'cjs'
transform-runtime
babel 会给每个编译的文件插入一些辅助方法,如果文件一多的话,就出现了很多重复代码,这个插件会改为从第三方包引用辅助方法,
需要额外安装@babel/runtime
e.g.
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault')
build
babel src --out-dir lib
使用 babel 打包 ES Module 模块
只要把上面里所有 module 相关的设置改成 es module 就行了
babelrc
{
presets: [['@babel/env', { loose: true, modules: false }], '@babel/preset-react'],
plugins: [
['@babel/plugin-transform-runtime', { useESModules: true }],
]
}
build
babel src --out-dir es
最后
安利一波个人写的打包库的工具 build-my-package, js, ts都支持哦!:)