UMD
一、认识
UMD
(Universal Module Definition
) 规范是一种旨在兼容多种模块化环境的模块定义标准。它提供了一种方式兼容各种模块系统,包括 AMD
、CommonJS
和全局变量模式。UMD
规范允许模块在不同的环境中使用,使得同一个模块可以被 AMD
、CommonJS
和全局变量加载。UMD
规范使得模块可以无缝集成到不同的项目和工具链中,无需针对特定的模块加载系统进行调整。
UMD
支持多种模块环境:
-
AMD(Asynchronous Module Definition)
:模块加载器,如RequireJS
。UMD
模块通过检查是否存在define
函数来决定是否使用AMD
规范。 -
CommonJS
:如Node.js
。UMD
模块通过检查是否存在module.exports
来决定是否使用CommonJS
规范。 -
全局环境(浏览器):在浏览器环境中,
UMD
模块会将模块内容挂载到window
对象上,以便通过全局变量访问。
UMD
模块的各个部分:
-
IIFE(Immediately Invoked Function Expression)
:UMD
模块使用IIFE
包裹模块代码,以确保模块在被加载时立即执行,并避免污染全局命名空间。IIFE
是一个自执行的函数表达式,它定义了模块的作用域。(function (root, factory) {
// UMD 模块的实现
}(this, function () {
// 模块定义
})); -
AMD
支持:UMD
模块会检查define
是否为一个函数并且具有amd
属性。如果是,则使用AMD
规范来定义模块。if (typeof define === 'function' && define.amd) {
define(['dependency'], factory);
} -
CommonJS
支持:UMD
模块会检查module
是否为对象并且module.exports
存在。如果是,则使用CommonJS
规范来导出模块。else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('dependency'));
} -
全局环境支持: 如果以上条件都不满足,
UMD
模块将模块内容挂载到全局对象(如window
),以便在浏览器环境中直接通过全局变量访问。else {
root.myModule = factory(root.dependency);
}
二、语法
定义模块
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// 1. 支持 AMD: 检查 `define` 是否为一个函数,并且具有 `amd` 属性。如果是,则使用 `AMD` 规范来定义模块。
define(['dependency1'], factory);
} else if (typeof module === 'object' && module.exports) {
// 2. 支持 CommonJS: 检查 `module` 是否为对象并且 `module.exports` 存在。如果是,则使用 `CommonJS` 规范来导出模块。
module.exports = factory(require('dependency1'));
} else {
// 3. 支持 Browser: 如果以上条件都不满足,模块将被定义为全局变量,供浏览器中的全局作用域访问。 root 就是 window
root.myModule = factory(root.dependency1);
}
}(this, function (dep1) {
// Define your module here
var module = {};
module.greet = function(name) {
return 'Hello, ' + name;
};
return module;
}));
使用模块
// AMD
require(['myModule'], function(myModule) {
console.log(myModule.greet('World')); // Hello, World
});
// CommonJS
var myModule = require('./myModule');
console.log(myModule.greet('World')); // Hello, World
// Global
console.log(myModule.greet('World')); // Hello, World
三、场景
3.1 Vite
3.2 Node
// umdModule.js
(function (root, factory) {
if (typeof define === "function" && define.amd) {
// AMD
define(["dependency"], factory);
} else if (typeof module === "object" && module.exports) {
// CommonJS
module.exports = factory(require("dependency"));
} else {
// Browser (root is window)
root.umdModule = factory(root.dependency);
}
})(this, function (dependency) {
return {
foo: function () {
console.log("foo 函数");
},
};
});
// app.js
const umdModule = require("./umdModule.js");
umdModule.foo();
3.3 Rollup
3.4 Browser
// umdModule.js
(function (root, factory) {
if (typeof define === "function" && define.amd) {
// AMD
define(["dependency"], factory);
} else if (typeof module === "object" && module.exports) {
// CommonJS
module.exports = factory(require("dependency"));
} else {
// Browser (root is window)
root.umdModule = factory(root.dependency);
}
})(this, function (dependency) {
return {
foo: function () {
console.log("foo 函数");
},
};
});
<script src="./umdModule.js"></script>
<script>
const { umdModule } = window;
umdModule.foo();
</script>
3.5 Webpack
一、为什么将产物打包成 UMD
格式?
-
兼容性:
UMD
格式兼容多种模块系统,包括AMD
、CommonJS
和全局变量。这使得模块能够在不同的环境和项目中无缝使用,而无需重新打包或修改代码。 -
通用性:
UMD
模块可以在浏览器、Node.js
、RequireJS
等环境中使用。适用于需要支持多种加载器和环境的公共库或工具。 -
灵活性:
UMD
格式允许在没有模块加载器的情况下直接在浏览器中使用模块(通过全局变量)。这对那些不使用模块加载器的旧系统或简单项目非常有用。 -
广泛的应用场景:许多开源库和工具使用
UMD
格式,以确保它们可以在各种项目中被广泛接受和使用。
二、什么场景下需要将产物打包成 UMD
格式呢?
-
公共库和工具:如开源库、第三方工具和框架,通常需要在不同的环境中被使用(如浏览器和
Node.js
)。UMD
格式保证了它们的兼容性和灵活性。 -
企业内部工具:在企业内部,可能存在不同的技术栈和模块加载方式。
UMD
格式的库可以在这些不同环境中都能正常工作。 -
无需安装模块加载器的环境:对于某些简单的项目或静态网页,可能不使用模块加载器。
UMD
格式的模块可以直接作为全局变量使用,无需额外配置。
三、Webpack
通过 library
、libraryTarget
、globalObject
将打包产物配置为 UMD
格式, 配置如下:
const path = require('path');
module.exports = {
entry: './src/index.js', // 入口文件
output: {
path: path.resolve(__dirname, 'dist'), // 输出目录
filename: 'bundle.js', // 输出文件名
library: 'MyLibrary', // 模块名(在 UMD 模式下,模块将以 `MyLibrary` 名称暴露)
libraryTarget: 'umd', // 输出模块格式为 UMD
globalObject: 'this' // 确保在 Node.js 和浏览器环境中都能正常工作
},
mode: 'production' // 或 'development'
};
-
library
: 指定模块暴露的全局变量名。在UMD
模式下,库将暴露为全局变量。如果库在浏览器中被加载,它将以此名称挂载到全局对象上。 -
libraryTarget
: 设置模块的输出格式。设置为umd
表示生成UMD
格式的产物。 -
globalObject
: 指定全局对象的名称。设置为this
可以确保在不同的JavaScript
环境中(如Node.js
和浏览器)都能正确工作。