打包第三库那些事

介绍

通常来讲,写完一个第三方库须要打包出三个文件夹的文件,对应三种不一样模块类型javascript

# 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 文件,咱们应该配置哪些选项html

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 文件了java

使用 babel 打包 commonjs 模块

使用 babel 打包就很简单了, 先看一下 babelrc 怎么写node

babelrc

{
  presets: [['@babel/env', { loose: true, modules: 'cjs' }], '@babel/preset-react'],
  plugins: [
    ['@babel/plugin-transform-runtime', { useESModules: false }],
  ]
}

loose

一句话解释: true 的时候代码更现代化代码量少,false 更兼容代码量也更多react

modules

设置使用不一样的模块类型,commonjs 的话,就设置成'cjs'webpack

transform-runtime

babel 会给每一个编译的文件插入一些辅助方法,若是文件一多的话,就出现了不少重复代码,这个插件会改成从第三方包引用辅助方法,
须要额外安装@babel/runtimegit

e.g.github

var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault')

build

babel src --out-dir lib

使用 babel 打包 ES Module 模块

只要把上面里全部 module 相关的设置改为 es module 就好了web

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都支持哦!:)shell

相关文章
相关标签/搜索