在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. python3.6使用pygal模块不具交互性,图片不能显示数据

    1.版本 个人电脑版本:win10+python3.6 2.安装 2.1 安装过的版本 1. 先使用pip安装pygal1.7,(参考<python从入门到实践>)         pyt ...

  2. Ubuntu terminal colors

    Today I run ubuntu docker image on powershell and find the directory color is blue, so I want to cha ...

  3. 用js提取字符串中的某一段字符

    String.prototype.getQuery = function(name){var reg = new RegExp("(^|&)"+ name +"= ...

  4. CentOS部署yapi

    转载自 https://www.linuxidc.com/Linux/2018-01/150513.htm 在mongoDB添加yum源时,源路径有修改,原文中的路径404不可用 一.准备工作 1.1 ...

  5. es6异步编程

    https://blog.csdn.net/tcy83/article/details/80274772 等一系列文章

  6. LA4080/UVa1416 Warfare And Logistics 最短路树

    题目大意: 求图中两两点对最短距离之和 允许你删除一条边,让你最大化删除这个边之后的图中两两点对最短距离之和. 暴力:每次枚举删除哪条边,以每个点为源点做一次最短路,复杂度\(O(NM^2logN)\ ...

  7. DML、DDL、DCL的分别是什么

    DML.DDL.DCL的分别是什么 一直以来,分不清这三者的简称代表什么,甚至在面试中遇到可能会张冠李戴.今天特意记录一下. 一.DML(data manipulation language) 数据操 ...

  8. socket(TCP)通讯之Python实现

    1.Service address = ('localhost', 9102) # AF_INET = ipv4; SOCK_STREAM:TCP s = socket.socket(socket.A ...

  9. clickhouse的使用和技巧,仅个人

    centos 安装clickhouse curl -s https://packagecloud.io/install/repositories/altinity/clickhouse/script. ...

  10. python super参数错误

    # -*- coding:utf-8 _*-"""@author:Administrator@file: yamlparser.py@time: 2018/09/07&q ...