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

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

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

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

;(function(){

    ...
...
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')(); /** Detect free variable `exports`. */
var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; /** Detect free variable `module`. */
var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; function lodash(value) {
return xxxx
} lodash.xxx= xxxxxx
lodash.prototype.xxxx= xxxxx ...
...
... /*--------------------------------------------------------------------------*/
// 导出为AMD模块
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { root._ = lodash; define(function() {
return lodash;
});
}
// 导出为CommonJS模块
else if (freeModule) {
(freeModule.exports = lodash)._ = lodash;
freeExports._ = lodash;
}
//导出到全局变量
else {
root._ = lodash;
} }.call(this))

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

(function (root, factory) {
if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('b'));
} else if (typeof define === 'function' && define.amd) {
// AMD
define(['b'], function (b) {
return (root.returnExportsGlobal = factory(b));
});
} else {
// Global Variables
root.returnExportsGlobal = factory(root.b);
}
}(this, function (b) {
// Your actual module
return {
b.xxx
};
}));

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

/* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */
;(function(global, factory) {
if (typeof define === "function" && define.amd)
define(function() {
return factory(global)
})
else factory(global)
})(this, function(window) {
var Zepto = (function() {
...
...
...
})()
window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)()
return Zepto
})

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

//  Ramda v0.25.0
// https://github.com/ramda/ramda
// (c) 2013-2017 Scott Sauyet, Michael Hurley, and David Chambers
// Ramda may be freely distributed under the MIT license. ;(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined"
? factory(exports) // CommonJS
: typeof define === "function" && define.amd
? define(["exports"], factory) // AMD
: factory((global.R = {})) // Global Variables
})(this, function(exports) {
"use strict" exports.F = F
exports.T = T
exports.__ = __
exports.add = add
exports.addIndex = addIndex
exports.adjust = adjust
exports.all = all
// ...
// ...
exports.zipWith = zipWith // 支持 Babel 转换的 ES6 module
Object.defineProperty(exports, "__esModule", { value: true })
})

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

// sum.js
function Sum(a, b){
return a + b
}
export { Sum }

安装如下几个依赖

// package.json
"devDependencies": {
"@babel/core": "^7.1.6",
"babel-loader": "^8.0.4",
"babel-plugin-transform-es2015-modules-umd": "^6.24.1",
"webpack": "^4.25.1",
"webpack-cli": "^3.1.2"
}

webpack配置如如下:

var path = require('path')
module.exports = {
mode: 'development',
entry: './sum.js',
output: {
filename: 'sum.umd.js',
libraryTarget: 'umd',
library: 'UMDSUM',
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
},
]
},
devtool: 'source-map'
};

执行npx webpack打包结果如下:

(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["UMDSUM"] = factory();
else
root["UMDSUM"] = factory();
})(window, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./sum.js");
/******/ })
/************************************************************************/
/******/ ({ /***/ "./sum.js":
/*!****************!*\
!*** ./sum.js ***!
\****************/
/*! exports provided: Sum */
/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sum", function() { return Sum; });
function Sum(a, b) {
return a + b;
} /***/ }) /******/ });
});
//# sourceMappingURL=sum.umd.js.map

参考
Browserify and the Universal Module Definition

So, How About UMD模块-Universal Module Definition的更多相关文章

  1. Javascript模块化编程之CommonJS,AMD,CMD,UMD模块加载规范详解

    JavaSript模块化 在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?     模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问 题进行系 ...

  2. 可能是最详细的UMD模块入门指南

    学习UMD 介绍 这个仓库记录了一些关于javascript UMD模块规范的demo,对我学习UMD规范有了很大帮助,希望也能帮助到你. 回顾 之前也写了几篇关于javascript模块的博客,链接 ...

  3. 前端模块化IIFE,commonjs,AMD,UMD,ES6 Module规范超详细讲解

    目录 为什么前端需要模块化 什么是模块 是什么IIFE 举个栗子 模块化标准 Commonjs 特征 IIFE中的例子用commonjs实现 AMD和RequireJS 如何定义一个模块 如何在入口文 ...

  4. 公共模块定义/草案(Common Module Definition / draft - CMD草案)

    This specification addresses how modules should be written in order to be interoperable in browser-b ...

  5. 【02】AMD、CMD、UMD 模块的写法

    AMD.CMD.UMD 模块的写法 简介 最近几年,我们可以选择的Javascript组件的生态系统一直在稳步增长.虽然陡增的选择范围是极好的,但当组件混合匹配使用时就会出现很尴尬的局面.开发新手们会 ...

  6. Axis2(9):编写Axis2模块(Module)

    Axis2可以通过模块(Module)进行扩展.Axis2模块至少需要有两个类,这两个类分别实现了Module和Handler接口.开发和使用一个Axis2模块的步骤如下: 1. 编写实现Module ...

  7. 多模块项目Module must not contain source root. The root already belongs to module

    多模块项目Module "*" must not contain source root *. The root already belongs to module "* ...

  8. Angular之特性模块 ( Feature Module )

    项目结构 一 创建特性模块,及其包含的组件.服务. ng g module art ng g component art/music ng g component art/dance ng g ser ...

  9. 程序集(Assembly)和模块(Managed Module)

    前言 一直都用集成开发坏境(IDE),一直对模块和程序集的概念理解的不是很直观,因为一Build就把你的单个模块塞进程序集里面去了.当然,对你的编程也不会造成太大的影响.但有些东西你最好还是知道比较好 ...

随机推荐

  1. [LVM]创建LVM卷

    https://www.cnblogs.com/softidea/p/5147090.html

  2. How to expand Azure VM OS Disk

    There are three main disk roles in Azure: the data disk, the OS disk, and the temporary disk. 1. OS ...

  3. 【php】php7新特性及其优化原理

    php7.x版本系列相比之前的php的版本提交性能提高了不少,这里面其中的一些主要改变是性能提高的关键,主要有以下内容. 1.zval使用栈内存   在zend引擎和扩展中,经常要创建php变量,其底 ...

  4. 洛谷P4630 铁人两项--圆方树

    一道很好的圆方树入门题 感谢PinkRabbit巨佬的博客,讲的太好啦 首先是构建圆方树的代码,也比较好想好记 void tarjan(int u) { dfn[u] = low[u] = ++dfn ...

  5. mysql的服务器构成

    什么是实例 这里的实例不是类产生的实例对象,而是Linux系统下的一种机制 1.MySQL的后台进程+线程+预分配的内存结构. 2.MySQL在启动的过程中会启动后台守护进程,并生成工作线程,预分配内 ...

  6. django 3.post接口开发

    如果有了一个项目,还想创建一个项目,那么就是进入项目的路径下,运行命令,比如: cd /Users/newcomer/PycharmProjects/djangoProject python3 man ...

  7. mysql You can't specify target table 'xxx' for update in FROM clause的解决

    DELETE from sp_goodscontent where goodsId in (SELECT t.goodsId from ( SELECT goodsId FROM sp_goodsco ...

  8. SSH 连接慢

    关闭连接时的 DNS 解析 # 编辑配置文件,修改如下配置项 vim /etc/ssh/sshd_config GSSAPIAuthentication no UseDNS no # 重启服务 sys ...

  9. Zabbix 添加端口监控链接

    zabbix 添加端口监控 连接数: zabbix  配置  添加 监控项: 其他检测 方式也是 示例: zabbix 客户端配置文件添加: 编辑 zabbix_agentd.conf  添加  端口 ...

  10. 【C#第一天】数据相关

    程序的基本任务:对数据进行处理. 数据分为常量和变量. 变量本质上是内存的空间,用来存储信息. 数据类型:本质上是数据的存储方式及其能参与运算的抽象. 数据类型分两大类:值类型(Value Type) ...