webpack output.library的16 種取值方法示例
前置準備
在項目開發中使用 webpack 打包前端代碼,對 output.library 配置項總是不求甚解,隻知道將代碼打包成 npm 庫的時候要配置它。這段時間又要開發組件庫,借助這次機會對 output.library 求甚解。
配置過 output.library 的同學應該也配置過 output.libraryTarget,在開發庫的時候總是一起配置它們。由於在webpack文檔中推薦使用 output.library.type 代替 output.libraryTarget,所以本文隻介紹 output.library。
本文 webpack 的版本是 5.74.0。
入口代碼如下:
// index.js export default function add(a, b) { console.log(a + b) }
webpack 的配置如下,後續我們隻關註 library 字段。
const path = require('path'); module.exports = { entry: './index.js', mode: "none", output: { filename: 'main.js', // library: 'MyLibrary', path: path.resolve(__dirname, 'dist'), }, };
打包輸出的文件中,除瞭包含 index.js 中的源碼,還包含 webpack 運行時,代碼如下,後續將不再介紹它。
var __webpack_require__ = {}; // 將 definition 中的屬性添加到 exports 上 __webpack_require__.d = (exports, definition) => { for(var key in definition) { if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; // 判斷 obj 上是否有 prop __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) // 在 exports 上定義 __esModule 屬性 __webpack_require__.r = (exports) => { if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); };
點這裡得到文本的代碼。
不配置 library
在介紹 library 各配置項的作用前,先看一下不配置 library 時的打包結果。如下:
// 自執行函數 (() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__) }); // 打包入口導出的函數 function __WEBPACK_DEFAULT_EXPORT__(a, b) { console.log(a + b) } })() ;
從上述代碼可以看出,不配置 library 時,__WEBPACK_DEFAULT_EXPORT__
函數沒有被公開,在庫外部的任何位置都訪問不到它。
下面將介紹配置 library 時的各種情況,library 可接受的數據類型是 string | string[] | object
。string
是 object
類型的簡寫形式,當值為 object
類型時,object 中能包含的屬性有 name、type、export、auxiliaryComment 和 umdNamedDefine。本文將重點放在 type 字段上,它決定如何公開當前庫,取值基本固定,name 字段可以是任何字符串,它用來指定庫的名稱。
library.type = var(默認值)
將 library 的值改成 {type: 'var', name: 'MyLibrary'}
, 打包結果如下:
var MyLibrary; (() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } MyLibrary = __webpack_exports__; })()
從上述代碼可以看出,通過MyLibrary
能訪問到add
函數,當不能保證MyLibrary
在全局變量上。
library.type = window
將 library 的值改成 {type: 'window', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } window.MyLibrary = __webpack_exports__; })()
從上述代碼可以看出,通過window.MyLibrary
能訪問到add
函數。
library.type = module
將 library 的值改成 {type: 'module'}
, 此時還要 experiments.outputModule 設置為 true , 打包結果如下:
var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } var __webpack_exports__default = __webpack_exports__["default"]; export { __webpack_exports__default as default };
此時不存在閉包,並且能用 es modules 將庫導入。
library.type = this
將 library 的值改成 {type: 'this', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } this.MyLibrary = __webpack_exports__; })()
此時通過 this.MyLibrary 能訪問到 add 函數
library.type = self
將 library 的值改成 {type: 'self', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } self.MyLibrary = __webpack_exports__; })()
此時通過 self.MyLibrary 可訪問到 add 函數,在瀏覽器環境的全局上下文中 self 等於 window
library.type = global
將 library 的值改成 {type: 'global', name: 'MyLibrary'}
,此時 MyLibrary 會被分配到全局對象,全局對象會根據target值的不同而不同,全部對象可能的值是 self、global 或 globalThis。當 target 的值為 web(默認值),代碼結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } self.MyLibrary = __webpack_exports__; })()
此時的打包結果與 library.type = self 結果一樣。
library.type = commonjs
將 library 的值改成 {type: 'commonjs', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } exports.MyLibrary = __webpack_exports__; })()
顧名思義,如果公開的庫要在 CommonJS 環境中使用,那麼將 library.type 設置成 commonjs,此時 MyLibrary 分配給瞭 exports
library.type = commonjs2
將 library 的值改成 {type: 'commonjs2', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } module.exports.MyLibrary = __webpack_exports__; })()
此時 MyLibrary 分配給瞭 module.exports,如果公開的庫要在 Node.js 環境中運行,推薦將 library.type 設置為 commonjs2。commonjs 和 commonjs2 很像,但它們有一些不同,簡單的說 CommonJs 規范隻定義瞭 exports ,但是 module.exports 被 node.js 和一些其他實現 CommonJs 規范的模塊系統所使用,commonjs 表示純 CommonJs,commonjs2 在 CommonJs 的基礎上增加瞭 module.exports。
library.type = commonjs-static
將 library 的值改成 {type: 'commonjs-module'}
,註意此時沒有設置 name 屬性, 打包結果如下:
(() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } exports["default"] = __webpack_exports__["default"]; Object.defineProperty(exports, "__esModule", { value: true }); })()
在 CommonJS 模塊中使用庫
const add = require('./dist/main.js');
在 ESM 模塊中使用庫
import add from './dist/main.js';
當源代碼是用 ESM 編寫的,但你的庫要同時兼容 CJS 和 ESM 時,library.type = commonjs-static將很有用。
library.type = amd
將 library 的值改成 {type: 'amd', name: 'MyLibrary'}
, 打包結果如下:
define("MyLibrary", [], () => { return /******/ (() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } return __webpack_exports__; })() ; });;
當你的庫要在 amd 模塊中使用時,將 library.type 設置成 amd
library.type = umd
將 library 的值改成 {type: 'umd', name: 'MyLibrary'}
, 打包結果如下:
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') // commonjs2 module.exports = factory(); else if(typeof define === 'function' && define.amd) // amd define([], factory); else if(typeof exports === 'object') // commonjs exports["MyLibrary"] = factory(); else // 全局變量 root["MyLibrary"] = factory(); })(self, () => { return /******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } return __webpack_exports__; })() ; });
此時你的庫能用 Commonjs、AMD 和全局變量引入,在開發庫時將 library.type 設置成 umd 很常見。
library.type = assign
將 library 的值改成 {type: 'assign', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. (() => { "use strict"; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } })(); MyLibrary = __webpack_exports__; })()
這將生成一個隱含的全局變量 MyLibrary,通過 MyLibrary 能訪問 add 函數,它有可能覆蓋一個現有值,因此要小心使用。
library.type = assign-properties
將 library 的值改成 {type: 'assign-properties', name: 'MyLibrary'}
, 打包結果如下:
(() => { var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. (() => { "use strict"; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } })(); var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === "undefined" ? {} : MyLibrary); // 將 __webpack_exports__ 上的屬性轉移到 __webpack_export_target__ 上。 for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true }); })()
它與 assign 類似,但更安全,如果 MyLibrary 存在,那麼它將重用 MyLibrary,而非覆蓋。
library.type = jsonp
將 library 的值改成 {type: 'jsonp', name: 'MyLibrary'}
, 打包結果如下:
MyLibrary((() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } return __webpack_exports__; })() );
此時入口的源碼在 jsonp 的包裹器中,這種情況要確保 MyLibrary 函數存在。
library.type = system
將 library 的值改成 {type: 'system', name: 'MyLibrary'}
, 打包結果如下:
System.register("MyLibrary", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { return { execute: function() { __WEBPACK_DYNAMIC_EXPORT__( (() => { var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ add) }); function add(a, b) { console.log(a + b) } return __webpack_exports__; })() ); } }; });
將你的庫公開為一個System 模塊。
總結
當你的庫導出的內容需要在另外的地方(通常是另一個項目)訪問,那麼你應該給 webpack 配置 library 字段,library 究竟要配置成什麼值,這取決於你希望你的庫怎麼被引入
以上就是webpack output.library的16 種取值方法示例的詳細內容,更多關於webpack output.library取值的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- webpack模塊化的原理解析
- Js模塊打包exports require import的用法和區別
- 淺談JS前端模塊化的幾種規范
- 淺談Webpack是如何打包CommonJS的
- js 模塊化CommonJS AMD UMD CMD ES6規范詳解