在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. react native 左边固定,右边横向滑动左右自适应高度

    要实现的效果 https://zuobaiquan.github.io/blogImg/201903/01.gif

  2. 【linux】线上服务器要关注哪些参数

    服务器(nginx/apache): 1.吞吐率. 2.并发连接数. 3.qps. 4.并发连接数详细数据统计,包括读取请求.持久连接.发送响应内容.关闭连接.等待连接. 5.连接线程池利用率. 关系 ...

  3. 洛谷P3268 [JLOI2016]圆的异或并(扫描线)

    扫描线还不是很熟啊--不管是从想的方面还是代码实现的方面-- 关于这题,考虑一条平行于\(y\)轴的扫描线从左到右扫描每一个圆,因为只有相离和内含两种关系,只用在切线处扫描即可 我们设上半圆为1,下半 ...

  4. CF1157A-Reachable Numbers题解

    原题地址 题目大意:有一个函数\(f(x)\),效果是将\(x+1\)后,去掉末尾所有的\(0\),例如: \(f(599)=6\),因为\(599+1=600→60→6\) \(f(7)=8\),因 ...

  5. Django视图

    Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误, ...

  6. 机器学习KNN算法

    KNN(最邻近规则分类K-Nearest-Neighibor)KNN算法 1. 综述      1.1 Cover和Hart在1968年提出了最初的邻近算法      1.2 分类(classific ...

  7. CF451E Devu and Flowers

    多重集求组合数,注意到\(n = 20\)所以可以用\(2 ^ n * n\)的容斥来写. 如果没有限制那么答案就是\(C(n + s - 1, n - 1)\).对每一个限制依次考虑,加上有一种选多 ...

  8. (二叉树 递归) leetcode94. Binary Tree Inorder Traversal

    Given a binary tree, return the inorder traversal of its nodes' values. Example: Input: [1,null,2,3] ...

  9. java第一课 面向对象的编程概念

    一.什么是对象(object)? 对象是相关状态和行为的软件包. 1.现实社会的对象都有两个共同特征:状态和行为.如:狗有状态(名称,颜色,品种,饥饿)和行为(吠叫,取出,摇尾). 2.软件对象在概念 ...

  10. python学习07

    函数中的模块及包管理1)1.模块查找的顺序:运行代码时当前目录 -> PYTHONPATH ->系统环境变量PATH设置的路径2.导入模块的书写规范:内置模块-------第三方模块--- ...