0


前端模块化-UMD规范及其实现

前言

UMD(Universal Module Definition)是一种通用的模块定义规范,旨在使同一个模块能够在不同的环境中使用,包括浏览器、Node.js 等。它采用一种灵活的方式,既支持类似 CommonJS 的模块加载方式,也支持类似 AMD 的异步加载方式,同时兼容浏览器全局变量的使用。

UMD 模块通常通过一定的判断逻辑来确定当前的模块加载环境,从而决定采用何种加载方式。这种灵活性使得开发者能够编写一次模块代码,然后在不同的环境中使用,无需修改代码。

本节对应的所有 demo 在此处

UMD 模块的基本结构

UMD 模块通常采用一种通用的结构,用于在不同的加载环境中判断和执行。以下是一个简单的 UMD 模块结构示例:

(function(root, factory){if(typeof define ==="function"&& define.amd){// AMDdefine(["dependency"], factory);}elseif(typeof define ==="function"&& define.cmd){// CMD 环境define(function(require, exports, module){
      module.exports =factory(require("dependency"));});}elseif(typeof exports ==="object"){// Node.js/CommonJS
    module.exports =factory(require("dependency"));}else{// Browser globals
    root.YourModule =factory(root.Dependency);}})(typeof self !=="undefined"? self :this,function(Dependency){// 你的模块代码return YourModule;// 暴露模块});

此结构中,通过判断 define、exports 和全局对象,确定当前所处的环境,从而选择合适的加载方式。

React 中的 UMD 模块

React 是一个流行的 JavaScript 库,用于构建用户界面。React 库也支持 UMD 格式,使得它可以在浏览器和 Node.js 等环境中使用。

在浏览器中使用 React 的 UMD 模块的示例:

<!DOCTYPEhtml><html><head><metacharset="utf-8"/><title>React Demo template</title><scriptsrc="https://cdn.jsdelivr.net/npm/[email protected]/umd/react.development.min.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.development.min.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/@babel/[email protected]/babel.min.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/dayjs/dayjs.min.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/antd/dist/antd.min.js"></script></head><body><divid="root"></div><scripttype="text/babel">const{ render }= ReactDOM;// ReactDOM的UMD对象const{ useEffect }= React;const{ Button }= antd;// antd的UMD对象//  AppfunctionApp(props:{name: string }){return(<div><h1>Hello,{props.name}!</h1><Button type="primary">click me</Button></div>);}// ----------------------------------------------------render(<App name="App"/>, document.getElementById("root"));</script></body></html>

注意上述的代码中使用了

type="text/babel"

,这是因为 React 使用了 JSX 语法,需要使用 Babel 进行转换。如果不使用 JSX 语法,可以将

type="text/babel"

去掉。

完整的 demo 请看 👉 在线效果预览, 查看示例代码请点击此处

回到 React, 其 UMD 模块基本结构如下:

(function(global, factory){typeof exports ==="object"&&typeof module !=="undefined"?factory(exports):typeof define ==="function"&& define.amd
    ?define(["exports"], factory):((global = global || self),factory((global.React ={})));// 我们可以从这里看出,React 的 UMD 模块实际上是将 React 挂载到全局对象上})(this,function(exports){"use strict";// React 导出的代码
  exports.Component = Component;
  exports.createElement = createElement;
  exports.createContext = createContext;// ... (其他导出的React功能)});

手动实现一个 UMD 模块

假设你实现了一个 Hello 模块, 代码如下

functionsayHello(){
  console.log("Hello!");}

第一步,准备一个 factory 函数,用于在不同的环境中执行,代码如下:

function(){functionsayHello(){
        console.log('Hello!');}return{sayHello: sayHello
    };}

第二步: 全局兼容

(function(root, factory){
  console.log("-----global环境--------");
  root.Hello =factory();})(this,function(){functionsayHello(){
    console.log("Hello!");}return{sayHello: sayHello,};});

在这一步中,我们简单地将模块挂载到全局对象 this 上。这样,你可以在浏览器环境中通过 YourModule 来访问模块。

执行结果如下:

-----global 环境--------
 Hello.js:6 Hello!

完整的 demo 请看 👉 在线效果预览, 查看示例代码请点击此处

第三步: CommonJS 兼容

(function(root, factory){if(typeof exports ==="object"&&typeof module !=="undefined"){
    console.log("-----commonJS环境--------");
    module.exports =factory();}else{
    console.log("-----global环境--------");
    root.Hello =factory();}})(this,function(){functionsayHello(){
    console.log("Hello!");}return{sayHello: sayHello,};});

我们通过判断 module 和 module.exports 的存在,确定当前环境是否支持 CommonJS。如果是 CommonJS 环境,我们将模块导出,否则继续挂载到全局对象。

执行结果如下:

-----commonJS 环境--------
 Hello!

查看示例代码请点击此处

第四步: AMD

(function(root, factory){if(typeof exports ==="object"&&typeof module !=="undefined"){
    console.log("-----commonJS环境, 如nodeJS--------");
    module.exports =factory();}elseif(typeof define ==="function"&& define.cmd){
    console.log("-----CMD环境, 如seaJS--------");define([], factory);}elseif(typeof define ==="function"&& define.amd){
    console.log("-----AMD环境, 如requireJS--------");define([], factory);}else{
    console.log("-----global环境--------");
    root.Hello =factory();}})(this,function(){functionsayHello(){
    console.log("Hello!");}return{sayHello: sayHello,};});

在这一步中,我们通过判断 define 函数的存在,确定当前环境是否支持 AMD。如果是 AMD 环境,我们通过 define 函数来定义模块,否则继续挂载到全局对象。

输出结果如下:

 -----AMD 环境, 如 requireJS--------
 hello.js:17 Hello!

完整的 demo 请看 👉 在线效果预览, 查看示例代码请点击此处

第五步: CMD 支持

(function(root, factory){if(typeof exports ==="object"&&typeof module !=="undefined"){
    console.log("-----commonJS环境, 如nodeJS--------");
    module.exports =factory();}elseif(typeof define ==="function"&& define.cmd){
    console.log("-----CMD环境, 如seaJS--------");define([], factory);}elseif(typeof define ==="function"&& define.amd){
    console.log("-----AMD环境, 如requireJS--------");define([], factory);}else{
    console.log("-----global环境--------");
    root.Hello =factory();}})(this,function(){functionsayHello(){
    console.log("Hello!");}return{sayHello: sayHello,};});

输出结果如下:

-----CMD 环境, 如 seaJS--------
 Hello.js:17 Hello!

完整的 demo 请看 👉 在线效果预览, 查看示例代码请点击此处

本文首发于个人 Github前端开发笔记,由于笔者能力有限,文章难免有疏漏之处,欢迎指正

标签: 前端 模块化 UMD

本文转载自: https://blog.csdn.net/zhuanyemanong/article/details/141004428
版权归原作者 逍遥的编程笔记 所有, 如有侵权,请联系我们删除。

“前端模块化-UMD规范及其实现”的评论:

还没有评论