从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!
关于作者
- 张丹(Conan), 程序员Java,R,PHP,Javascript
- weibo:@Conan_Z
- blog: http://blog.fens.me
- email: bsspirit@gmail.com
转载请注明出处:
http://blog.fens.me/nodejs-requirejs/
前言
随着项目越来越大,依赖越来越多,代码的耦合度也越来越高。我们需要从架构的层面设计和优化代码的组织结构。RequireJS遵循AMD(异步模块定义)规范,从架构层抽象出“模块化”开发方案,并以标准化了模块化开发,同时和其他的开发框架保持兼容。
按照RequireJS的规范,我们能够更容易地实现更复杂,更强大的JS的富客户端程序。
目录
- RequireJS介绍
- RequireJS安装
- RequireJS基本使用
- nodejs构建简易的web服务器
- RequireJS模块化
- 多路径配置: baseUrl,paths
- 编译Requirejs模块
1. RequireJS介绍
RequireJS是一个Javascript的模块加载器,倡导的是一种模块化开发理念,核心价值是让 JavaScript 的模块化开发变得更简单自然。RequireJS 遵循的是 AMD(异步模块定义)规范,帮助用户异步按需的加载 JavaScript 代码,并解决 JavaScript 模块间的依赖关系,提升了前端代码的整体质量和性能。
2. RequireJS安装
我的系统环境
- win7 64bit
- Nodejs:v0.10.5
- Npm:1.2.19
通过nodejs安装RequireJS
~ D:\workspace\javascript>mkdir nodejs-require && cd nodejs-require
~ D:\workspace\javascript\nodejs-require>npm install requirejs
npm http GET https://registry.npmjs.org/requirejs
npm http 200 https://registry.npmjs.org/requirejs
requirejs@2.1.8 node_modules\requirejs
全局安装requirejs:使用r.js工具。
~ D:\workspace\javascript\nodejs-require>npm install requirejs -g
npm http GET https://registry.npmjs.org/requirejs
npm http 304 https://registry.npmjs.org/requirejs
D:\toolkit\nodejs\r.js -> D:\toolkit\nodejs\node_modules\requirejs\bin\r.js
npm ERR! peerinvalid The package generator-karma does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer generator-angular@0.4.0 wants generator-karma@~0.5.0
npm ERR! System Windows_NT 6.1.7601
npm ERR! command "D:\\toolkit\\nodejs\\\\node.exe" "D:\\toolkit\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "
requirejs" "-g"
npm ERR! cwd D:\workspace\javascript\nodejs-require
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.19
npm ERR! code EPEERINVALID
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! D:\workspace\javascript\nodejs-require\npm-debug.log
npm ERR! not ok code 0
运行r.js命令失败
~ D:\workspace\javascript\nodejs-require>r.js
我的win7环境中有错误,所以我只能在当前项目中运行r.js命令.(Linux下面可以全局安装。)
~ D:\workspace\javascript\nodejs-require>node node_modules\requirejs\bin\r.js -h
See https://github.com/jrburke/r.js for usage.
3. RequireJS基本使用
创建项目文件:
~ D:\workspace\javascript\nodejs-require>ls -l
-rwx------ 1 4294967295 mkpasswd 65 Sep 19 13:32 a.js
-rwx------ 1 4294967295 mkpasswd 59 Sep 18 20:33 b.js
-rwx------ 1 4294967295 mkpasswd 82 Sep 18 20:33 c.js
-rwx------ 1 4294967295 mkpasswd 69 Sep 18 20:33 d.js
-rwx------ 1 4294967295 mkpasswd 206 Sep 19 13:32 index.html
-rwx------ 1 4294967295 mkpasswd 48 Sep 19 13:31 main.js
drwx------+ 1 4294967295 mkpasswd 0 Sep 18 20:32 node_modules
对文件的定义:
- index.html: 用于加载javascript文件,这里只加载RequireJS库
- main.js: RequireJS的模块组,用来封装JS模块,通过js来加载其他的js文件
- a.js: 一个JS的功能文件,不依赖其他库
- b.js: 一个JS的功能文件,不依赖其他库
- c.js: 一个JS的功能文件,依赖a.js和b.js
- d.js: 一个JS的功能文件,依赖c.js
新增文件:index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>RequireJS</title>
<script data-main="main" src="node_modules/requirejs/require.js"></script>
</head>
<h1>RequireJS Testing</h1>
<body>
</body>
</html>
新增文件:main.js
require(['a'],function(){
a();
})
新增文件:a.js
function a(){
console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
新增文件:b.js
function b(){
console.log("bbbbbbbbbbbbbbbbbbbbb");
}
新增文件:c.js
function c(){
a();
b();
console.log("cccccccccccccccccccccccc");
}
新增文件:d.js
function d(){
c();
console.log("ddddddddddddddddddddd");
}
打开浏览器:file:///D:/workspace/javascript/nodejs-require/index.html
我们发现a.js被加载了,但我们并没有在index.html中定义script加载a.js。
- 1. a.js的加载是RequireJS帮我们做的。
- 2. 通过在HTML中定义data-main属性,注册一个模块main.js。
- 3. 在main.js中,通过声明式定义,引入a.js文件
- 4. 实现了对a.js加载的控制
通过require函数完全成了依赖管理的功能
require(dependencies, callback)
- dependencies: 是我们要载入的js,使用相对路径。
- callback: 是封装有程序逻辑。
所以,我们可以发现了RequireJS可以帮我们做,js依赖管理。我们可以再也不用在HTML中,以很土的加载顺序的方式管理JS文件了。这种优雅的注入可以帮我很好的管理全局变量。
4. nodejs构建简易的web服务器
在进行下一步之前,我们要用构建一个简易的web服务器,RequireJS的模块化加载需要web server的支持,通过本地文件的方式是不行的。
安装connect依赖
~ D:\workspace\javascript\nodejs-require>npm install connect
connect@2.9.0 node_modules\connect
├── uid2@0.0.2
├── methods@0.0.1
├── cookie-signature@1.0.1
├── pause@0.0.1
├── fresh@0.2.0
├── bytes@0.2.0
├── qs@0.6.5
├── buffer-crc32@0.2.1
├── cookie@0.1.0
├── debug@0.7.2
├── send@0.1.4 (range-parser@0.0.4, mime@1.2.11)
└── multiparty@2.1.8 (stream-counter@0.1.0, readable-stream@1.0.17)
新建文件:app.js
~ vi app.js
var connect = require('connect');
connect.createServer(
connect.static(__dirname)
).listen(3000);
开发模式启动服务器:
supervisor app.js
5. RequireJS模块化
虽然我们可以把所有的程序都写在main.js的callback中,但是程序会变得复杂,关系也不清楚。接下来,我们要做模块化的编程。RequireJS也实现了AMD定义的define的API。
define(id?, dependencies?, factory)
- id:字符串,模块名称,可选。
- dependencies: 是我们要载入的js,使用相对路径。
- factory: 工厂方法,返回一个模块函数
新建ab.js,实现模块ab:
~ vi ab.js
define(function(){
return {
a: function(){
a();
console.log("ab.a()");
},
b:function(){
b();
console.log("ab.b()");
}
};
});
修改main.js
~ vi main.js
require(['a','b','ab'],function(a,b,ab){
ab.b();
})
刷新页面:http://localhost:3000/
调用流程:
- 1. 通过main.js加载了a.js,b.js,ab.js文件
- 2. ab.js构建一个ab的模块
- 3. 在ab的模块中,调用b.js的b()函数
通过模块化的封装后,我们可以更优化我们的程序,程序结构更清晰!
6. 多路径配置: baseUrl,paths
如果我们需要加载多个js文件时,文件在不同的目录下面,我们可以通过baseUrl和paths来设置路径的默认位置和路径别名,方便我们定位文件。
#新建目录
~ mkdir folder
~ mkdir folder/f1
~ mkdir folder/f2
#把c.js移动到f1
~ mv c.js folder/f1
#把d.js移动到f2
~ mv d.js folder/f2
修改main.js
~ vi main.js
require.config({
baseUrl:'./',
paths:{
f1:'folder/f1',
f2:'folder/f2'
}
});
require([
'b',
'a',
'ab',
'f1/c',
'f2/d'
],function(a,b,ab,c){
d();
})
刷新浏览器:
我们看到c.js, d.js都被正确的加载了。
7. 编译Requirejs模块
最后要讲的是,通过r.js命令,对模块进行翻译优化。
在RequireJS安装部分,我们没有实现全局安装,因些只能在项目中通过相对路径使用r.js的命令。
~ D:\workspace\javascript\nodejs-require>node node_modules\requirejs\bin\r.js -o name=main out=main-build.js baseUrl=. pat
hs.f1="folder/f1" paths.f2="folder/f2"
Tracing dependencies for: main
Uglifying file: D:/workspace/javascript/nodejs-require/main-build.js
D:/workspace/javascript/nodejs-require/main-build.js
----------------
D:/workspace/javascript/nodejs-require/b.js
D:/workspace/javascript/nodejs-require/a.js
D:/workspace/javascript/nodejs-require/ab.js
D:/workspace/javascript/nodejs-require/folder/f1/c.js
D:/workspace/javascript/nodejs-require/folder/f2/d.js
D:/workspace/javascript/nodejs-require/main.js
我们会发现,新生成一个文件main-build.js
~ cat main-build.js
function b(){console.log("bbbbbbbbbbbbbbbbbbbbb")}function a(){console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaa")}function c(){a(),b(),console.log("cccccccccccccccccccccccc")}function d(){c(),console.log("ddddddddddddddddddddd")}define("b",function(){}),define("a",function(){}),define("ab",[],function(){return{a:function(){a(),console.log("ab.a()")},b:function(){b(),console.log("ab.b()")}}}),define("f1/c",function(){}),define("f2/d",function(){}),require.config({baseUrl:"./",paths:{f1:"folder/f1",f2:"folder/f2"}}),require(["b","a","ab","f1/c","f2/d"],function(e,t,n,r){d()}),define("main",function(){});
新生成的main-build.js可以用来做为发布的功能模块。
本文简单的介绍了RequireJS的使用,如果我们的程序按照AMD的模块化思路去构建,我相信JS的代码,也是健壮的,可维护的,可传递的。
要是能解决r.js全局安装失败的问题就好了。
这不是什么大问题。Linux都正常的
requirejs 官网有解决办法
不错!回头试试。
i am confused. is RequireJS is for clientside only? other than npm manage the package, any relations connecting RequireJS with NodeJS?
你好,希望中文回答你可以看懂。
1. RequireJS不是只为了浏览器端用的。
2. RequireJS提供了一种模块之间的调用关系,define(id?, dependencies?, factory),这种关系可以让js的程序层次更清楚。
3. Node框架通过require()实现这个调用关系,更通过npm实现的依赖。
4. RequireJS与Node虽然都是做同样的事情,但并不冲突,你通过可以在Node项目中使用RequireJS.
5. 从另外一个角度看,你也可以在非Node项目中使用RequireJS。当然,这样的非Node项目,可能是基于Rhino、V8,或者嵌入在其他语言中的js解释器等。
奇怪的是 我直接安装r.js在全局 win下 却没有错误,是版本的问题吗
2个原因:
1. requirejs版本。
2. Win下,.net Framework中依赖包都完成好了。
[…] 工具包:underscore,moment,connet,later,log4js,passport,passport(oAuth),domain,require,reap, commander,retry […]
想说,为什么一会windows环境一会Linux的,搞的人好混乱
并不是所有包,都可以window平台可以正常运行的。
请问在github上有完整的例子么。 我还是有很多的不明白。 请问main.js和其他例如a.js他们是放在那里的呢?
我觉得我失败的原因是,我是在node里面按照你的方法用requirejs的。请问在nodejs项目下,如何使用呢?
我知道nodejs下如何使用requirejs了。但是我还是有疑问,如何加载jquery或者zepto使全局都可以使用呢?
背景:node建设项目。model下的main.js:
var requirejs = require(‘requirejs’);
requirejs.config({
baseUrl: ‘./public/javascripts’,
nodeRequire: require
});
var zepto = requirejs(‘zepto’)
var transitions = requirejs(‘transitions’);
exports.left = function () {
console.log(‘leftAAAAAAAAA’);
};
ps:zepto.js 和 transitions.js 都是在’./public/javascripts’;
运行后 报错:Error: Evaluating ./public/javascripts/zepto.js as module “zepto” failed with error: ReferenceError: window is not defined
求教,如何在nodejs下用requirejs加载jquery或者zepto呢?
一般nodejs项目,不使用requirejs。requirejs主要用于,没有模块加载器的项目,比如纯前端JS项目。
但是 我现在在用node写一个前端的框架。一般不用但是也是可以用的吧。那请问,node里面jquery或者zepto的正确使用方式是?网上说jqdom,但是它似乎只能用来爬虫。我想要完整的jq或者zepto。
NODE里这样就可以加载jquery包了,npm install jquery
我有个疑问,requirejs在非nodejs项目中可以用来做js按需加载或者说lazy load。但是这里我们用r.js将所有的js文件都合并成一个build文件了,这样一来除了减少https次数之外,似乎屏蔽了按需加载这个feature啊?请楼主赐教
1. 是的,如果合并到一起,就屏蔽了按需加载。
2. 但不一定所有的时候,按需加载都是最好的选择。如果你有100个js小文件(2k以下)需要加载,那么合并成3-4个大文件按需加载,会比分散成100个加载要高效的多。
张老师你好,我在做前台的自动化测试,在karma-的配置文件中frameworks: [‘jasmine’, ‘requirejs’],,并且安装了require模块,之后再运行karma会出现chorm浏览器弹出,但是不跑测试用例的情况,去掉reqirejs就OK了,这是为什么?
我的文章中Karma是基于node的npm进行模块管理的,不需要requirejs。
如果在独立的浏览器中进行测试,不使用node环境开发,可以通过requirejs进行模块加载。