-
Notifications
You must be signed in to change notification settings - Fork 2.6k
从 CommonJS 到 Sea.js #269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
有任何问题,欢迎留言交流。 |
SeaJS貌似是继承了RequireJS的方案(兼容CommonJS),但又不属于AMD,而且也不同于CommonJS。 确实没见过CMD规范,国外只有CommonJS和AMD,如果说CMD是为了和CommonJS以及RequireJS加以区分,那么我建议像AMD一样在define上加上识别,所有符合AMD规范的Module Loader都会有 加上识别的好处是很多第三方的模块可以做到通吃AMD和CMD以及CommonJS,放到哪个环境都可以运行。不用修改第三方插件就可以直接使用。 现在很多插件都在这样做了,但只会判断 if ( typeof define === 'function' && define.amd || define.cmd ) |
@lifesinger 嗯,我单是从第三方考虑了,就是因为现在这种模块加载器太多了,而且不乏一些使用量很多的工具,例如RequireJS和curl,define这个全局命名随处可见,要区分一个插件所处的环境,得有更多的判断。 seajs简单的外包一层就可以变身Sea模块,其实也是优势了。而且jquery插件适配器的配置更是靓点。 ,SeaJS2.0,确实越来越好了 |
@lifesinger 不是分裂的问题,而是如果没有标志,影响为seajs写兼容。仅仅用 typeof define == 'function' 判断CMD似乎过于霸道。 |
这样可否? if (typeof define === 'function' && define.cmd) {} |
写兼容其实很简单, |
通过判断seajs和requirejs是否存在虽然“靠谱”,但是不利于其他的兼容实现。这是为什么有define.amd。其他实现加上.amd表示它实现了AMD(当然是否实现完全无误是另一回事情)。如果我检查define.amd,表示我只预期一个 AMD 实现,而不依赖 requirejs 的特别特性。CMD也是一样的。目前至少司徒正美的mass号称兼容CMD(虽然他似乎也没有检测define.cmd)。 |
@hax 现在问题是,大家对 AMD 的理解并不一致,即便有 define.amd,不同的实现,中间细节差异还不少。要不 CMD 要加下 define.cmd define.amd 的初始用法,是一个
支持 AMD 的组件类库,理论上都需要在 amd 对象中注册下,这太 BT 了。 目前大部分用 |
我 out 了,查找了下最新的 AMD 规范:https://github.com/amdjs/amdjs-api/wiki/AMD 对 define.amd 的用法已更新。现在的定位不错。我去加一个 define.cmd |
有些地方不是很理解,希望能帮忙解释解释: |
@niceue |
和browserify有什么区别?读下来感觉实现原理是一样的,只不过sea.js有一套不同于CommonJS的规范 |
考古 |
CommonJS 是什么
CommonJS 是一个有志于构建 JavaScript 生态圈的组织。它有一个 邮件列表,很多开发者参与其中。 整个社区致力于提高 JavaScript 程序的可移植性和可交换性,无论是在服务端还是浏览器端。
CommonJS 模块是什么
JavaScript 并没有内置模块系统(反正现在没有,需要等到 ES6 的普遍支持,不知还需要多少年),于是 CommonJS 创造了自己的。 传统的 CommonJS 模块如下:
math.js
increment.js
program.js
CommonJS 与浏览器
仔细看上面的代码,您会注意到
require
是同步的。模块系统需要同步读取模块文件内容,并编译执行以得到模块接口。然而, 这在浏览器端问题多多。
浏览器端,加载 JavaScript 最佳、最容易的方式是在
document
中插入<script>
标签。但脚本标签天生异步,传统 CommonJS 模块在浏览器环境中无法正常加载。解决思路之一是,开发一个服务器端组件,对模块代码作静态分析,将模块与它的依赖列表一起返回给浏览器端。 这很好使,但需要服务器安装额外的组件,并因此要调整一系列底层架构。
另一种解决思路是,用一套标准模板来封装模块定义:
这套模板代码为模块加载器提供了机会,使其能在模块代码执行之前,对模块代码进行静态分析,并动态生成依赖列表。
为了让静态分析可行,需要遵守一些简单的 规则。
把上面例子中的模块封装起来,可得到:
math.js
increment.js
program.js
上面是一种封装方案,还有各种各样的封装方案,比如 AMD、Modules/Wrappings、CommonJS/Modules 2.0 等等模块定义规范。
Sea.js 的封装方案就是 CMD 规范:CMD 模块定义规范
CommonJS 与 Sea.js
从上面可以看出,Sea.js 的初衷是为了让 CommonJS Modules/1.1 的模块能运行在浏览器端,但由于浏览器和服务器的实质差异,实际上这个梦无法完全达成,也没有必要去达成。
更好的一种方式是,Sea.js 专注于 Web 浏览器端,CommonJS 则专注于服务器端,但两者有共通的部分。对于需要在两端都可以跑的模块,可以 有便捷的方案来快速迁移。
目前 Sea.js 的模块,如果没有用到浏览器环境下的特有属性,可以很方便跑在 NodeJS 端。只要在入口文件处,引入 Sea.js 的 Node.js 版本即可:
这样,
a.js
就可以是一个用define
包裹起来的 CMD 模块了。CommonJS 的模块需要跑在浏览器端时,通过简单封装就行:
a.js
这样
a.js
就可以在浏览器端通过 Sea.js 加载运行。当然前提是a.js
没有利用到服务器特有属性和模块,比如__dirname
、process
等。通过上面的方案,我们就实现了 CommonJS 与 Sea.js 两个生态圈的融合,可以彼此互通,让我们书写的 JavaScript 模块可移植,可在不同平台上运行。
The text was updated successfully, but these errors were encountered: