打包第三库那些事
介绍
一般来说,写完一个第三方库需要打包出三个文件夹的文件,对应三种不同模块类型
# 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都支持哦!:)
相关推荐
不知道该写啥QAQ 2020-11-12
webfullStack 2020-11-09
Yvettre 2020-09-15
想做大牛的蜗牛 2020-10-30
gloria0 2020-10-26
gaojie0 2020-09-11
SelinaChan 2020-08-14
不知道该写啥QAQ 2020-08-09
gloria0 2020-08-09
不知道该写啥QAQ 2020-08-02
hline 2020-07-29
SelinaChan 2020-07-28
wangdianyong 2020-07-23
webpackvuees 2020-07-23
yqoxygen 2020-07-20
不知道该写啥QAQ 2020-07-18
waterv 2020-07-18
81463166 2020-07-17