打包第三庫那些事

介紹

通常來講,寫完一個第三方庫須要打包出三個文件夾的文件,對應三種不一樣模塊類型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

相關文章
相關標籤/搜索