学习UMD

介绍

这个仓库记录了一些关于javascript UMD模块规范的demo,对我学习UMD规范有了很大帮助,希望也能帮助到你。

回顾

之前也写了几篇关于javascript模块的博客,链接如下:

近几天准备总结一下javascript模块的知识点,所以建了这个Git仓库,如果能帮助到您,麻烦点个star哦,非常感谢!

这篇博客主要说下自己关于UMD的一点认知和思考,从实现一个简单的UMD模块,再到实现一个有依赖关系的UMD模块,整个过程加深了我对UMD模块的理解。

什么是UMD

所谓UMD (Universal Module Definition),就是一种javascript通用模块定义规范,让你的模块能在javascript所有运行环境中发挥作用。

简单UMD模块的实现

实现一个UMD模块,就要考虑现有的主流javascript模块规范了,如CommonJS, AMD, CMD等。那么如何才能同时满足这几种规范呢?

首先要想到,模块最终是要导出一个对象,函数,或者变量。

而不同的模块规范,关于模块导出这部分的定义是完全不一样的。

因此,我们需要一种过渡机制。

首先,我们需要一个factory,也就是工厂函数,它只负责返回你需要导出的内容(对象,函数,变量等)。

我们从导出一个简单的对象开始。

function factory() {
return {
name: '我是一个umd模块'
}
}

全局对象挂载属性

假设不考虑CommonJS, AMD, CMD,仅仅将这个模块作为全局对象的一个属性应该怎么写呢?

(function(root, factory) {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory();
}(this, function() {
return {
name: '我是一个umd模块'
}
}))

我们把factory写成一个匿名函数,利用IIFE(立即执行函数)去执行工厂函数,返回的对象赋值给root.umdModule,这里的root就是指向全局对象this,其值可能是window或者global,视运行环境而定。

打开效果页面链接(要看源码的话,点开Git仓库),观察Network的文件加载顺序,可以看到,原则就是依赖先行。

再进一步,兼容AMD规范

要兼容AMD也简单,判断一下环境,是否满足AMD规范。如果满足,则使用require.js提供的define函数定义模块。

(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// 如果环境中有define函数,并且define函数具备amd属性,则可以判断当前环境满足AMD规范
console.log('是AMD模块规范,如require.js')
define(factory)
} else {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory();
}
}(this, function() {
return {
name: '我是一个umd模块'
}
}))

打开效果页面链接,可以看到,原则是调用者先加载,所依赖的模块后加载。

起飞,直接UMD

同理,接着判断当前环境是否满足CommonJSCMD规范,分别使用相应的模块定义方法进行模块定义。

(function(root, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
console.log('是commonjs模块规范,nodejs环境')
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
console.log('是AMD模块规范,如require.js')
define(factory)
} else if (typeof define === 'function' && define.cmd) {
console.log('是CMD模块规范,如sea.js')
define(function(require, exports, module) {
module.exports = factory()
})
} else {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory();
}
}(this, function() {
return {
name: '我是一个umd模块'
}
}))

最终,使用require.js, sea.js, nodejs或全局对象挂载属性等方式都能完美地使用umd-module.js这个模块,实现了大一统。

给个sea.js调用UMD的效果页面链接,sea.js调用UMD模块

nodejs调用UMD模块需要执行node命令,

node umd-simple-used-by-nodejs

效果如下:

有依赖关系的UMD模块

当然,我们不能止步于此,模块会被调用,当然也会调用其他模块。因此我们还需要实现一个有依赖关系的UMD模块,来验证UMD规范的可行性。

全局对象挂载属性

这个简单,在html中你的模块前引入所依赖的模块即可。umd-module-dependedumd-module都是UMD模块,后者依赖前者。

<!DOCTYPE html>
<html>
<head>
<title>Test UMD</title>
<!-- 依赖放前面 -->
<script src="assets/js/umd-dep/umd-module-depended.js"></script>
<script src="assets/js/umd-dep/umd-module.js"></script>
<script src="assets/js/umd-dep/umd-global.js"></script>
</head>
<body>
<h1>测试UMD模块</h1>
<h2></h2>
<p id="content"></p>
<p id="content2"></p>
</body>
</html>

点开效果页面链接,看得更清楚明白!

兼容AMD规范

我们先在入口文件umd-main-requirejs.js中,定义好模块路径,方便调用。

require.config({
baseUrl: "./assets/js/umd-dep/",
paths: {
umd: "umd-module",
depModule: "umd-module-depended"
}
});

被依赖的模块umd-module-depended,只需要简单实现UMD规范即可。

而调用者umd-module,则需要做一些处理。按照require.js的规范来即可, define时,指定依赖的模块depModule,而匿名工厂函数需要在参数上接收依赖的模块depModule

(function(root, factory) {
if (typeof define === 'function' && define.amd) {
console.log('是AMD模块规范,如require.js')
define(['depModule'], factory)
} else {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory(root.depModule);
}
}(this, function(depModule) {
console.log('我调用了依赖模块', depModule)
// ...省略了一些代码,去代码仓库看吧
return {
name: '我自己是一个umd模块'
}
}))

打开效果页面链接,看得更清楚明白!

UMD依赖写法

同理,各种规范要求你怎么写模块依赖,你就怎么写就行。

(function(root, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
console.log('是commonjs模块规范,nodejs环境')
var depModule = require('./umd-module-depended')
module.exports = factory(depModule);
} else if (typeof define === 'function' && define.amd) {
console.log('是AMD模块规范,如require.js')
define(['depModule'], factory)
} else if (typeof define === 'function' && define.cmd) {
console.log('是CMD模块规范,如sea.js')
define(function(require, exports, module) {
var depModule = require('depModule')
module.exports = factory(depModule)
})
} else {
console.log('没有模块环境,直接挂载在全局对象上')
root.umdModule = factory(root.depModule);
}
}(this, function(depModule) {
console.log('我调用了依赖模块', depModule)
// ...省略了一些代码,去代码仓库看吧
return {
name: '我自己是一个umd模块'
}
}))

给个sea.js调用的示例链接

nodejs调用也是通过命令行测试,

node umd-dep-used-by-nodejs

效果如下:

总结

以上实现了简单的UMD模块,也验证了UMD模块间存在依赖关系时的可行性。虽然本文是以简单对象导出为例,但足以作为我们深入UMD规范的起点,加油!

最后厚着脸皮求个star点亮我吧

首发链接


扫一扫下方小程序二维码或搜索Tusi博客,即刻阅读最新文章!

可能是最详细的UMD模块入门指南的更多相关文章

  1. 这可能是最详细的 iOS 学习入门指南(含书目/文档/学习资料)

    1 零基础小白如何进行 iOS 系统学习 首先,学习目标要明确: 其次,有了目标,要培养兴趣,经常给自己一些正面的反馈,比如对自己的进步进行鼓励,在前期小步快走: 再次,学技术最重要的一点就是多动手. ...

  2. Nginx开发HTTP模块入门

    Nginx开发HTTP模块入门 我们以一个最简单的Hello World模块为例,学习Nginx的模块编写.假设我们的模块在nginx配置文件中的指令名称为hello_world,那我们就可以在ngi ...

  3. Webpack 入门指南 - 2.模块

    这一次我们谈谈模块问题. 通常我们希望这个项目可以分为多个独立的模块,比如,上一次提高的 hello 函数,如果我们定义为一个模块,其它模块引用之后,直接调用就好了.在前端怎么使用模块呢?这可说来话长 ...

  4. AngularJS快速入门指南12:模块

    AngularJS模块定义了一个application. 模块是一个application中不同部分的容器. application中的所有控制器都应该属于一个模块. 带有一个控制器的模块 下面这个a ...

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

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

  6. 详细的Hadoop的入门教程-完全分布模式Fully-Distributed Operation

    1. 前面在伪分布模式下已经创建了一台机器,为了统一命名,hostname更名为hadoop01.然后再克隆2台机器:hadoop02. hadoop03:将第一台机器hadoop01上的伪分布停止, ...

  7. Request模块入门学习

    使用指令npm install --save request来安装模块,然后使用var request = require('request')完成引用. 对于GET请求,主要是获取目的url中数据. ...

  8. UMD 模块 vs CJS 模块

    UMD 模块 vs CJS 模块 使用方式 UMD, window 全局注册后,直接使用 <!DOCTYPE html> <html lang="zh-Hans" ...

  9. yii2实战教程之新手入门指南-简单博客管理系统

    作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...

随机推荐

  1. 《Java知识应用》Java读写DBF文件

    1. 准备: Jar包下载:链接: https://pan.baidu.com/s/1Ikxx-vkw5vSDf9SBUQHBCw 提取码: 7h58 复制这段内容后打开百度网盘手机App,操作更方便 ...

  2. linux 删除.svn文件

    linux删除当前目录及其子目录下的.svn文件,linux下删除全部的.svn文件 find . -name "*.svn" -type d -print -exec rm -r ...

  3. <科普>CPU进行四则运算(加减乘除)的主流方法

    以下除特殊说明外均为32位数的运算 1.加法运算 A   +   B    =   C 无符号整数加法和有符号整数加法均采用以下方案进行操作 用到的寄存器与初始化内容: 32位加数寄存器------- ...

  4. Mysql 的异常:The last packet successfully received from the server was 90 milliseconds ago. The last packet sent successfully to the server was 43,603,303 milliseconds ago. is longer than the server con

    调试一个程序, 调试到一半, 下班回家, 程序卡在了某一行, 第二天早上回来一看, 发现了异常: Wed Sep :: GMT+: WARN: Establishing SSL connection ...

  5. jQuery 源码解析(二十五) DOM操作模块 html和text方法的区别

    html和text都可以获取和修改DOM节点里的内容,方法如下: html(value)     ;获取匹配元素集合中的一个元素的innerHTML内容,或者设置每个元素的innerHTML内容,   ...

  6. linux查看磁盘及文件夹大小命令

    https://www.runoob.com/w3cnote/linux-view-disk-space.html 1.使用lsof查看已删除但未释放的文件 lsof -n | grep delete ...

  7. .NET面试题解析(9)-SQL语言基础及数据库基本原理

    见面试题 1. 索引的作用?她的优点缺点是什么? 2. 介绍存储过程基本概念和 她的优缺点? 3. 使用索引有哪些需要注意的地方? 4. 索引碎片是如何产生的?有什么危害?又该如何处理? 5. 锁的目 ...

  8. vue--CRUD

    1. Create this.$http.post("http://localhost:3000/users",newCustomer).then(function (respon ...

  9. swift声明属性为某个类型同时遵循某协议

    swift声明属性为某个类型同时遵循某协议 var instanse:(协议A & 类B)

  10. BIM工程信息管理系统-EF实体框架数据操作基类

    EF实体框架数据操作基类主要是规范增.改.查.分页.Lambda表达式条件处理,以及异步操作等特性,这样能够尽可能的符合基类这个特殊类的定义,实现功能接口的最大化重用和统一. 1.程序代码 /// & ...