同时兼容 AMD, CommandJS 和全局变量的模块化定义的一个通用实现

2015-07-10 12:10:29 +08:00
 bramblex

最近围观了一下UMD,发现虽然不错,但是其实并不是非常通用,所以自己尝试折腾了一个来玩玩,发现还不错,就拿来给大家围观一下。水平渣渣,请轻拍。

先不废话,先看个实例。一共是三个文件,example.js、lib1.js和lib2.js。其中example.js依赖lib1.js和lib2.js,同时也就是意味着example模块依赖lib1模块和lib2模块。

-
|-example.js
|-lib1.js
|-lib2.js

首先,来看看example.js。如下所示,example.js定义一个example模块输出"example",并且调用lib1()和lib2(),依赖当前目录下的lib1模块和lib2模块。

//example.js
(function (r, n, d, f) {
  if (typeof define === 'function' && define.amd)
    define(n, d, f);
  else if (typeof exports === 'object')
    module.exports = f.apply(r, d.map(function(m){return require(m)}));
  else
    r[n] = f.apply(r, d.map(function(m){return r[m]}));
}(this, 'example', ['./lib1', './lib2'], function (lib1, lib2) {

  var myFunc = function myFunc(){
    console.log('example');
    lib1();
    lib2();
  };

  return myFunc;
}));

接下来是lib1.js和lib2.js。下面是lib1.js的代码,定义一个lib1模块输出"lib1",没有依赖。lib2.js的代码一样,定义一个lib2模块,输出"lib2"。

// lib1.js
(function (r, n, d, f) {
  if (typeof define === 'function' && define.amd)
    define(n, d, f);
  else if (typeof exports === 'object')
    module.exports = f.apply(r, d.map(function(m){return require(m)}));
  else
    r[n] = f.apply(r, d.map(function(m){return r[m]}));
}(this, 'lib1', [], function () {

  var myFunc = function myFunc(){
    console.log('lib1');
  };

  return myFunc;
}));

来,最后来看看效果。

//在node里加载
var example = require('./example');
example();
//在浏览器中使用require.js加载
require(['example'], function(example){example();});
<!-- 在浏览器中通过script标签加载 -->
<script src="lib1.js"></script>
<script src="lib2.js"></script>
<script src="example.js"></script>
<script>
  example();
</script>

上面三种方式都能正确输出如下结果

//=> "example"
//=> "lib1"
//=> "lib2"
3641 次点击
所在节点    JavaScript
9 条回复
magicdawn
2015-07-10 21:35:47 +08:00
umd 哪里不通用请说明...
amrio
2015-07-11 09:15:06 +08:00
你这不支持 CJS 啊,UMD 都没你这绕 ┑( ̄Д  ̄)┍
bramblex
2015-07-11 10:21:06 +08:00
@amrio

1. 支持 CommandJS 你可以自己测试一下。我在node里面跑的无压力。我不支持的是CMD……不过感觉CMD有些坑,正在想办法加通用壳。

2. 你该不会觉得你要手写这大串蛋疼东西吧?我折腾这套通用壳就是为了让它足够通用到直接用工具包装一下就能用的程度。这种重复无聊的工作请留给机器做。

昨晚已完成把一个AMD模块直接包装成UMD模块的工具,我从来没想过这种蛋疼的东西需要人手工来做。 https://github.com/bramblex/UMDT
bramblex
2015-07-11 10:23:50 +08:00
@magicdawn

我说的不通用并不是指标准不通用,而是代码不通用。不能简单的进行转换,仅此而已。

我现在选用AMD做基准,然后通过用工具加通用壳来保证一处编写,到处运行的目的。而不需要到处写一大段重复代码。
bramblex
2015-07-11 11:10:33 +08:00
@amrio
@magicdawn

最新的代码模板,只需要把AMD模块套上这个壳,就可以同时兼容AMD,CommandJS和全局变量加载了,不需要多谢一行代码 https://github.com/bramblex/UMDT/blob/master/template
amrio
2015-07-11 11:59:06 +08:00
@bramblex 好吧,我想说的就是 CMD。要支持其实不复杂,CMD 也是支持 `define(deps, factory)` 的,只不过 `factory` 的实参是 `require, exports, module`

代码:

``` js
if (typeof __define__ === 'function' && __define__.cmd) {
__define__(dependencies, function (require, exports, module) {
module.exports = factory.apply(__root__, dependencies.map(function(m){
return require(m);
}));
})
}```

简单测了下,没啥问题
bramblex
2015-07-11 13:00:29 +08:00
@amrio

我加上试试OwO ,谢啦~~~
sodatea
2015-07-12 08:27:19 +08:00
CommonJS 不是 CommandJS……
bramblex
2015-07-12 16:57:44 +08:00
@sodatea
嗯…打错了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/204705

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX