当前位置:   article > 正文

So, How About UMD模块-Universal Module Definition

umd: universal module definition 外部如何调用

ES6模块解决方案出现之前,工具库或包常用三种解决方案提供对外使用的接口,最早是直接暴露给全局变量,比如我们熟知的Jquery暴露的全局变量是$,Lodash对外暴露的全局变量是_,后来出现了AMD和CommonJS(CMD的一种实现)两种常用的模块解决方案.

  • 全局变量
  1. // MyDependency is in your global scope
  2. var MyModule = function() {
  3. MyDependency.xxx()
  4. };
  • CommonJS
  1. var MyDependency = require('my-dependency');
  2. module.exports = function() {
  3. MyDependency.xxx()
  4. };
  • AMD
  1. define(['my-dependency'], function(MyDependency) {
  2. return function() {
  3. MyDependency.xxx()
  4. };
  5. });

为了同时兼容各种场景下的使用,业界提出了UMD的解决方案.遵循该标准的包可以通过上面三种方式引入.

以Lodash为例,其源码结构大致如下:

  1. ;(function(){
  2. ...
  3. ...
  4. /** Detect free variable `global` from Node.js. */
  5. var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
  6. /** Detect free variable `self`. */
  7. var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
  8. /** Used as a reference to the global object. */
  9. var root = freeGlobal || freeSelf || Function('return this')();
  10. /** Detect free variable `exports`. */
  11. var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
  12. /** Detect free variable `module`. */
  13. var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
  14. function lodash(value) {
  15. return xxxx
  16. }
  17. lodash.xxx= xxxxxx
  18. lodash.prototype.xxxx= xxxxx
  19. ...
  20. ...
  21. ...
  22. /*--------------------------------------------------------------------------*/
  23. // 导出为AMD模块
  24. if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
  25. root._ = lodash;
  26. define(function() {
  27. return lodash;
  28. });
  29. }
  30. // 导出为CommonJS模块
  31. else if (freeModule) {
  32. (freeModule.exports = lodash)._ = lodash;
  33. freeExports._ = lodash;
  34. }
  35. //导出到全局变量
  36. else {
  37. root._ = lodash;
  38. }
  39. }.call(this))

关于UMD的实现方式有很多种,都大同小异,下面是常见的实现方式.

  1. (function (root, factory) {
  2. if (typeof exports === 'object') {
  3. // CommonJS
  4. module.exports = factory(require('b'));
  5. } else if (typeof define === 'function' && define.amd) {
  6. // AMD
  7. define(['b'], function (b) {
  8. return (root.returnExportsGlobal = factory(b));
  9. });
  10. } else {
  11. // Global Variables
  12. root.returnExportsGlobal = factory(root.b);
  13. }
  14. }(this, function (b) {
  15. // Your actual module
  16. return {
  17. b.xxx
  18. };
  19. }));

以Zepto为例,由于其仅用于浏览器端,因此不需要支持CommonJS.

  1. /* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */
  2. ;(function(global, factory) {
  3. if (typeof define === "function" && define.amd)
  4. define(function() {
  5. return factory(global)
  6. })
  7. else factory(global)
  8. })(this, function(window) {
  9. var Zepto = (function() {
  10. ...
  11. ...
  12. ...
  13. })()
  14. window.Zepto = Zepto
  15. window.$ === undefined && (window.$ = Zepto)()
  16. return Zepto
  17. })

Ramda的UMD封装通用性更强,还支持Babel转换ES6模块的方式.参见babel-plugin-transform-es2015-modules-commonjs

  1. // Ramda v0.25.0
  2. // https://github.com/ramda/ramda
  3. // (c) 2013-2017 Scott Sauyet, Michael Hurley, and David Chambers
  4. // Ramda may be freely distributed under the MIT license.
  5. ;(function(global, factory) {
  6. typeof exports === "object" && typeof module !== "undefined"
  7. ? factory(exports) // CommonJS
  8. : typeof define === "function" && define.amd
  9. ? define(["exports"], factory) // AMD
  10. : factory((global.R = {})) // Global Variables
  11. })(this, function(exports) {
  12. "use strict"
  13. exports.F = F
  14. exports.T = T
  15. exports.__ = __
  16. exports.add = add
  17. exports.addIndex = addIndex
  18. exports.adjust = adjust
  19. exports.all = all
  20. // ...
  21. // ...
  22. exports.zipWith = zipWith
  23. // 支持 Babel 转换的 ES6 module
  24. Object.defineProperty(exports, "__esModule", { value: true })
  25. })

当然实际开发过程中,我们不需要自己写样板代码,可以使用webpack+babel打包.例如我们设计一个简单的求和模块.

  1. // sum.js
  2. function Sum(a, b){
  3. return a + b
  4. }
  5. export { Sum }

安装如下几个依赖

  1. // package.json
  2. "devDependencies": {
  3. "@babel/core": "^7.1.6",
  4. "babel-loader": "^8.0.4",
  5. "babel-plugin-transform-es2015-modules-umd": "^6.24.1",
  6. "webpack": "^4.25.1",
  7. "webpack-cli": "^3.1.2"
  8. }

webpack配置如如下:

  1. var path = require('path')
  2. module.exports = {
  3. mode: 'development',
  4. entry: './sum.js',
  5. output: {
  6. filename: 'sum.umd.js',
  7. libraryTarget: 'umd',
  8. library: 'UMDSUM',
  9. path: path.resolve(__dirname, './dist'),
  10. },
  11. module: {
  12. rules: [
  13. {
  14. test: /\.js$/,
  15. use: ['babel-loader'],
  16. },
  17. ]
  18. },
  19. devtool: 'source-map'
  20. };

执行npx webpack打包结果如下:

  1. (function webpackUniversalModuleDefinition(root, factory) {
  2. if(typeof exports === 'object' && typeof module === 'object')
  3. module.exports = factory();
  4. else if(typeof define === 'function' && define.amd)
  5. define([], factory);
  6. else if(typeof exports === 'object')
  7. exports["UMDSUM"] = factory();
  8. else
  9. root["UMDSUM"] = factory();
  10. })(window, function() {
  11. return /******/ (function(modules) { // webpackBootstrap
  12. /******/ // The module cache
  13. /******/ var installedModules = {};
  14. /******/
  15. /******/ // The require function
  16. /******/ function __webpack_require__(moduleId) {
  17. /******/
  18. /******/ // Check if module is in cache
  19. /******/ if(installedModules[moduleId]) {
  20. /******/ return installedModules[moduleId].exports;
  21. /******/ }
  22. /******/ // Create a new module (and put it into the cache)
  23. /******/ var module = installedModules[moduleId] = {
  24. /******/ i: moduleId,
  25. /******/ l: false,
  26. /******/ exports: {}
  27. /******/ };
  28. /******/
  29. /******/ // Execute the module function
  30. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  31. /******/
  32. /******/ // Flag the module as loaded
  33. /******/ module.l = true;
  34. /******/
  35. /******/ // Return the exports of the module
  36. /******/ return module.exports;
  37. /******/ }
  38. /******/
  39. /******/
  40. /******/ // expose the modules object (__webpack_modules__)
  41. /******/ __webpack_require__.m = modules;
  42. /******/
  43. /******/ // expose the module cache
  44. /******/ __webpack_require__.c = installedModules;
  45. /******/
  46. /******/ // define getter function for harmony exports
  47. /******/ __webpack_require__.d = function(exports, name, getter) {
  48. /******/ if(!__webpack_require__.o(exports, name)) {
  49. /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
  50. /******/ }
  51. /******/ };
  52. /******/
  53. /******/ // define __esModule on exports
  54. /******/ __webpack_require__.r = function(exports) {
  55. /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  56. /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  57. /******/ }
  58. /******/ Object.defineProperty(exports, '__esModule', { value: true });
  59. /******/ };
  60. /******/
  61. /******/ // create a fake namespace object
  62. /******/ // mode & 1: value is a module id, require it
  63. /******/ // mode & 2: merge all properties of value into the ns
  64. /******/ // mode & 4: return value when already ns object
  65. /******/ // mode & 8|1: behave like require
  66. /******/ __webpack_require__.t = function(value, mode) {
  67. /******/ if(mode & 1) value = __webpack_require__(value);
  68. /******/ if(mode & 8) return value;
  69. /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  70. /******/ var ns = Object.create(null);
  71. /******/ __webpack_require__.r(ns);
  72. /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  73. /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  74. /******/ return ns;
  75. /******/ };
  76. /******/
  77. /******/ // getDefaultExport function for compatibility with non-harmony modules
  78. /******/ __webpack_require__.n = function(module) {
  79. /******/ var getter = module && module.__esModule ?
  80. /******/ function getDefault() { return module['default']; } :
  81. /******/ function getModuleExports() { return module; };
  82. /******/ __webpack_require__.d(getter, 'a', getter);
  83. /******/ return getter;
  84. /******/ };
  85. /******/
  86. /******/ // Object.prototype.hasOwnProperty.call
  87. /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  88. /******/
  89. /******/ // __webpack_public_path__
  90. /******/ __webpack_require__.p = "";
  91. /******/
  92. /******/
  93. /******/ // Load entry module and return exports
  94. /******/ return __webpack_require__(__webpack_require__.s = "./sum.js");
  95. /******/ })
  96. /************************************************************************/
  97. /******/ ({
  98. /***/ "./sum.js":
  99. /*!****************!*\
  100. !*** ./sum.js ***!
  101. \****************/
  102. /*! exports provided: Sum */
  103. /***/ (function(module, __webpack_exports__, __webpack_require__) {
  104. "use strict";
  105. __webpack_require__.r(__webpack_exports__);
  106. /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sum", function() { return Sum; });
  107. function Sum(a, b) {
  108. return a + b;
  109. }
  110. /***/ })
  111. /******/ });
  112. });
  113. //# sourceMappingURL=sum.umd.js.map

参考
Browserify and the Universal Module Definition

转载于:https://www.cnblogs.com/star91/p/So-How-About-UMD-mo-kuaiUniversal-Module-Definitio.html

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/748191
推荐阅读
相关标签
  

闽ICP备14008679号