标签(空格分隔): requireJS NodeJS
翻译自官方文档,英文地址,对翻译内容没有把握,不负责,孩子和我没关系。
第一问:难道 Node 没有一个模块加载器么?
不,Node有。那个加载器使用CommonJS模块样式。CommonJS模块样式对浏览器不理想,并且我并不同意一些使用ConmmonJS模块样式建造的折中方案。通过在服务器端使用RequireJS,你可以使用一种样式对你的所有模块,无论他们是用于服务器端还是浏览器端。这种方式你可以保留速度优势并能轻松调试你得到的通过在浏览器端使用ReuqireJS,还能不用担心由于两种样式的切换而带来的额外转换代价。
如果你想使用define()函数加载你的模块,但是要在Node中运行,而不需要在服务器上运行RequireJS,看下一章节关于使用amddefine部分。
第二问:我能使用已经用CommonJS模块样式写好的Node模块么?
能!关于RequireJS的Node适配器,叫做r.js。它将会使用Node的加载实现方法和Node的寻找路径如果模块根据ReuqireJS的配置没有被找到,因此你能继续使用你的已经存在的基于Node的模块不用去非要改变这些模块。
RequireJS将会首先使用它的配置项去寻找模块。如果RequireJS根据配置项没有找到模块,这个模块就会被假定使用Node模块的样式和配置。因此,只有用RequireJS配置模块位置如果使用了RequireJS的API。对于想使用Node的API和配置路径的模块来说,仅仅使用Node包管理器,例如npm安装他们即可,不要用RequireJS来配置他们的路径。
最佳实践:使用npm安装Node-only的包/模块到项目中node_modules的项目目录中去,但是不要配置RequireJS去在node_modules目录中寻找。同样避免使用相对的模块ID去查阅Node-only的模块。因此,不要做这样的事类似于
require("./node_modules/foo/foo");
最后,RequireJS在Node中仅能加载在本地磁盘的模块,比如通过HTTP来提取模块,目前还是不允许。
第三问:我该怎么使用它?
有两种方法来获取Node适配器
1.npm
使用npm来安装它
npm install requirejs
这种操作能够安装最新的发布版
2.下载 r.js
如果你更倾向不使用npm,你可以直接获取r.js。
- 下载r.js 从下载页并且将他放到你的项目中。
- 获取源代码从r.js的仓库或者生成r.js通过
node dist.js
,或者抓取一个快照从dist的目录。
用法
以下的使用说明是建立在安装了requirejs的基础上的,如果你正在直接使用r.js,把require('requirejs')
替换为require('./path/to/r.js')
基础用法为:
- require('requirejs')
- 将主要js文件的require函数传递给requirejs的配置项
例子:
var requirejs = require('requirejs');
requirejs.config({
//将最顶层的main.js/index.js的require函数传递给requirejs以至于 node模块相对于顶级JS文件加载
nodeRequire:require
});
requirejs(['foo','bar'],function(foo,bar){
//foo和bar通过requirejs的额配置项加载,但是如果没有被找到,那么将使用node的require方法来加载模块
});
确保已经阅读过位于第二部分的关于配置requireJS的提示,因此可以加载通过npm安装的node-only模块。
想看更多完整的关于使用RequireJS加载模块,但是使用node原生模块去做其他事情的事例,参考embedded test位于r.js的仓库中。
注意:requirejs([],function(){})
采用异步调用回调函数在RequireJS 2.1+的版本中。(早期版本为同步调用)。然而,当在Node中运行时,模块加载被载入采用同步IO调用,加载器插件应该同时决定加载方法的调用。这允许同时在node中使用requirejs通过requirejs('stringValue')
调用。
//同步检索值为a的模块
var a = requirejs('a');
搭建node模块使用AMD和RequrireJS
如果你想编写一个模块使其在Node中使用RequireJS工作,但并不需要库的使用者们在Node中使用RequireJS,那么你可以使用amdefine包去实现:
if(typeof define !== 'function'){
var define = require('amdefine')(module);
}
define(function(require){
var dep = require('dependency');
//这个从函数返回的值被用作模块导出并可见于Node
return function(){};
});
RequireJS优化器,自版本1.0.3起,将会去掉上述'amdfine'的使用,因此它也同样对于你的基于网络的模块是安全的。只需要确定使用上述代码中严格的'amdefine' if()检测和内容。空格/换行的区别是允许的。查看amdefine project获取更多信息。
如果你想直接使用RequireJS去编码你的模块,然后导出一个模块值给node使之能在其他Node项目中使用并且不需要app使用RequireJS,你可以使用列在下一个例子中的方法。
最好去明确的设置baseUrl相对于包含这个模块的目录,以便能正常工作当模块被嵌套早node_modules层。使用同步的requirejs('moduleId')
去寻找使用了requirejs配置和规则的模块,然后用Node模块的module.exports
去导出模块值:
var requirejs = require('requirejs');
requirejs.config({
//使用node的特殊变量 __dirname 去获得包含这个文件的目录
//如果构建将在节点中使用但不需要使用外部节点的库,则非常有用(搜狗翻译)
baseUrl : __dirname,
//将顶层的main.js/index.js require函数传递给requirejs以便node模块相对顶层JS文件去加载
nodeRequire : require
});
//foo和bar通过requirejs的配置加载,如果被找到,被假定是一个AMD模块。如果没有通过requirejs的配置找到foo和bar,那么用node的require去加载模块,若此时被找到,这个模块就会被认为是node模式的模块。注意:加载模块的同步方式只在node中有效。
var foo = requirejs('foo');
var bar = requirejs('bar');
//导出一个对Node可见的值
module.exports = function(){};
使用优化器作为node模块
为了通过函数调用而不是命令行工具来使用RequireJS optimizer,node模块也将RequireJS Optimizer公开为最优化的方法。
var requirejs = require('requirejs');
var config = {
baseUrl : '../appDir/scripts',
name:'main',
out:'../build/main-built.js'
};
requirejs.optimize(config,function(buildResponse){
//buildResponse是一个包含模块的文本输出。给contents加载生成的文件。使用config.out来获得优化后的文件内容
var contents = fs.readFileSync(config.out,'utf8');
},function(err){
//优化后错误回调
});
这能让你构造其他的最优化工作流程,比如可以使用a web builder,如果你更喜欢用“< /body>标签前包含一个脚本文件”去开发的话。这个优化器在Node中的运行相当迅速,只针对那些在每次浏览器请求时不想重新生成构造文件的大型项目,也只在你修改的脚本属于这些构造文件的情况下。你可以使用Node的fs.watchFile()
去监测文件,然后当文件变化时触发文件的重新构造。