关于RequireJS
RequireJS 是一个JavaScript模块加载器。它非常适合在浏览器中使用,但它也可以用在其他脚本环境, 就像 Rhino and Node. 使用RequireJS加载模块化脚本将提高代码的加载速度和质量。
兼容性
- IE 6+ .......... 兼容 ✔
- Firefox 2+ ..... 兼容 ✔
- Safari 3.2+ .... 兼容 ✔
- Chrome 3+ ...... 兼容 ✔
- Opera 10+ ...... 兼容 ✔
github:https://github.com/requirejs/requirejs
关于JavaScript模块化,本站有一篇专门的文章介绍它:JavaScript模块化开发。
为什么要用RequireJS
随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,就像是这样:
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
<script src="d.js"></script>
...
<script src="z.js"></script>
原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作、模块复用、单元测试等等一系列复杂的需求。
RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一。最新版本的RequireJS压缩后只有14K,堪称非常轻量。
- 实现了js文件的按需、异步加载
- 管理模块之间的依赖性,便于代码的编写和维护;
- 利于代码的模块化,便于团队、协作开发;
使用RequireJS
通常在body
的最后引入js文件:
<script src="//cdn.bootcss.com/require.js/2.3.2/require.min.js" data-main="js/main.js"></script>
其中data-main
属性用来指定程序的入口模块,RequireJS使用它来启动脚本加载过程。
RequireJS以一个相对于baseUrl的地址来加载所有的代码,而baseUrl一般设置到与data-main
性相一致的目录。
RequireJS默��假定所有的依赖资源都是js脚本,因此无需在module ID上再加".js"后缀,RequireJS在进行module ID到path的解析时会自动补上后缀。
主模块main.js
下面是一个主模块文件的实例:
目录结构:
|js/
|--main.js
|----ripplejs/
|------ripple.js
main.js:
require.config({
paths:{
'jquery':'http://cdn.bootcss.com/jquery/1.9.1/jquery.min',
'ripple':'ripplejs/ripple',
},
shim:{
'ripple':['jquery']
}
});
require(['jquery','ripple'], function ($,ripple){
$(function(){
var withRipples = [".withripple",].join(",");
$(withRipples).ripples();
});
});
require()函数
require()函数接受两个参数:
- 第一个参数是一个数组,表示所依赖的模块,上例就是['jquery', 'ripple'],即主模块依赖这两个模块。
- 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。
使用define()定义模块
RequireJS加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。
简单的值对
如果一个模块仅含值对,没有任何依赖,则在define()中定义这些值对就好了:
define({
color: "black",
size: "unisize"
});
模块定义为一个函数
假定现在有一个stu模块,它定义了一个getName()方法,那么stu.js就要这样写:
define(function (){
return{
getName:function (){
return 'justyeh'
}
}
};
我们可以这样使用它:
require.config({
paths:{
stu:"stu"
}
})
require(['stu'],function(stu){
alert(stu.getName())
})
带有依赖的模块
如果这个模块还依赖其他模块,那么define()函数需要设置一个数组参数,指明该模块的依赖性。
define(['jquery'],function ($){
return{
getName:function (){
return $("#name").val();
}
}
};
命名模块
你可能会看到一些define()中包含了一个模块名称作为首个参数:
define('jquery', [], function() { ... });
运行下面这段代码:
requirejs.config({
paths: {
myjquery: '//cdn.bootcss.com/jquery/3.1.1/jquery.min'
}
});
requirejs(['myjquery'], function($) {
console.log($);
});
它会提示你:undefined
,现在改个名字:
requirejs.config({
paths: {
jquery: '//cdn.bootcss.com/jquery/3.1.1/jquery.min'
}
});
requirejs(['jquery'], function($) {
alert($);
});
这时输出正确了,为什么jquery模块必须命名为jquery
,因为jquery是一个命名模块;命名模块表示给当前这个模块起了名字,它已经是有主的了,只能属于jquery。所以当我们使用另一个名字myjquery
去引用这个库的时候,它会发现,在 jquery.js 里声明的模块名jquery
与我自己使用的模块名myjquery
不同,便不会把它赋给myjquery
,所以myjquery
的值是undefined。
所以我们在使用一个第三方的时候,一定要注意它是否声明了一个确定的模块名。
配置选配
baseUrl
所有模块的查找根路径。如未显式设置baseUrl,则默认值是加载require.js的HTML所处的位置。如果用了data-main属性,则该路径就变成baseUrl。
paths
path映射那些不直接放置于baseUrl下的模块名。设置path时起始位置是相对于baseUrl的,除非该path设置以"/"开头或含有URL协议(如http:)。
用于模块名的path不应含有.js后缀,因为一个path有可能映射到一个目录。路径解析机制会自动在映射模块名到path时添加上.js后缀。
在浏览器中运行时,可指定路径的备选(fallbacks),比如:
requirejs.config({
paths: {
jquery: ['//cdn...1','//cdn...3','//cdn...2']
}
});
以实现诸如首先指定了从CDN中加载,一旦CDN加载失败则从本地位置中加载这类的机制。
shim
理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。但是实际上,虽然已经有一部分流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。
在这种情况下,我们要使用 shim ,将某个依赖中的某个全局变量暴露给requirejs,当作这个模块本身的引用。
在下面的示例中,underscore和backbone这两个库,都没有采用AMD规范编写,我们可以这样使用:
requirejs.config({
//The shimconfig will not work correctly if used on AMD scripts,
//in particular, the exports and init config will notbe triggered, and the deps config will be confusingfor those cases.
shim: {
'backbone': {
//在加载backbone.js之前应先加载它的依赖函数underscore.js和jquery.js
deps: ['underscore', 'jquery'],
//加载完毕后该模块使用的引用名
exports: 'Backbone'
},
'underscore': {
exports: '_'
}
});
//Then, later in a separate file, call it 'MyModel.js', a module is defined,specifting 'backbone' as a dependency.
//RequireJS will use the shim config to properly load 'backbone' and give a local reference to this module.
//The global Backbone will still exist on the page too.
define(['backbone'], function (Backbone) {
return Backbone.Model.extend({});
});
那些仅作为jQuery或Backbone的插件存在而不导出任何模块变量的"模块"们,shim配置可简单设置为依赖数组:
requirejs.config({
shim: {
'jquery.colorize': ['jquery'],
'jquery.scroll': ['jquery'],
'backbone.layoutmanager': ['backbone']
}
});
shim配置仅设置了代码的依赖关系,想要实际加载shim指定的或涉及的模块,仍然需要一个常规的require/define调用。设置shim本身不会触发代码的加载。
map
对于给定的模块前缀,使用一个不同的模块ID来加载该模块。
该手段对于某些大型项目很重要:如有两类模块需要使用不同版本的"foo",但它们之间仍需要一定的协同。 在那些基于上下文的多版本实现中很难做到这一点。而且,paths配置仅用于为模块ID设置root paths,而不是为了将一个模块ID映射到另一个。map示例:
requirejs.config({
map: {
'some/newmodule': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
如果各模块在磁盘上分布如下:
|foo1.0.js |foo1.2.js |some/ |--newmodule.js |--oldmodule.js
当“some/newmodule”调用了“require('foo')”,它将获取到foo1.2.js文件;而当“some/oldmodule”调用“`require('foo')”时它将获取到foo1.0.js。
该特性仅适用于那些调用了define()并将其注册为匿名模块的真正AMD模块脚本。并且,请在map配置中仅使用绝对模块ID,“../some/thing”之类的相对ID不能工作。
另外在map中支持“”,意思是“对于所有的模块加载,使用本map配置”。如果还有更细化的map配置,会优先于“”配置。示例:
requirejs.config({
map: {
'*': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
意思是除了“some/oldmodule”外的所有模块,当要用“foo”时,使用“foo1.2”来替代。对于“some/oldmodule”自己,则使用“foo1.0”。
config
常常需要将配置信息传给一个模块。这些配置往往是application级别的信息,需要一个手段将它们向下传递给模块。在RequireJS中,基于requirejs.config()的config配置项来实现。要获取这些信息的模块可以加载特殊的依赖“module”,并调用module.config()。示例:
requirejs.config({
config: {
'bar': {
size: 'large'
},
'baz': {
color: 'blue'
}
}
});
//bar.js, which uses simplified CJS wrapping:
//http://requirejs.org/docs/whyamd.html#sugar
define(function (require, exports, module) {
//Will be the value 'large'
var size = module.config().size;
});
//baz.js which uses a dependency array,
//it asks for the special module ID, 'module':
//https://github.com/jrburke/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-magic
define(['module'], function (module) {
//Will be the value 'blue'
var color = module.config().color;
});
若要将config传给包,将目标设置为包的主模块而不是包ID:
requirejs.config({
//Pass an API key for use in the pixie package'smain module.
config: {
'pixie/index': {
apiKey: 'XJKDLNS'
}
},
//Set up config for the "pixie" package, whose mainmodule is the index.js file in the pixie folder.
packages: [
{
name: 'pixie',
main: 'index'
}
]
});
packages
从CommonJS包(package)中加载模块。
nodeIdCompat
在放弃加载一个脚本之前等待的秒数。设为0禁用等待超时。默认为7秒。
waitSeconds
命名一个加载上下文。这允许require.js在同一页面上加载模块的多个版本,如果每个顶层require调用都指定了一个唯一的上下文字符串。
deps
指定要加载的一个依赖数组。当将require设置为一个config object在加载require.js之前使用时很有用。一旦require.js被定义,这些依赖就已加载。使用deps就像调用require([]),但它在loader处理配置完毕之后就立即生效。它并不阻塞其他的require()调用,它仅是指定某些模块作为config块的一部分而异步加载的手段而已。
callback
在deps加载完毕后执行的函数。当将require设置为一个config object在加载require.js之前使用时很有用,其作为配置的deps数组加载完毕后为require指定的函数。
enforceDefine
如果设置为true,则当一个脚本不是通过define()定义且不具备可供检查的shim导出字串值时,就会抛出错误。
xhtml
如果设置为true,则使用document.createElementNS()去创建script元素。
urlArgs
RequireJS获取资源时附加在URL后面的额外的query参数。作为浏览器或服务器未正确配置时的“cache bust”手段很有用。使用cache bust配置的一个示例:
urlArgs: "bust=" + (new Date()).getTime()
在开发中这很有用,但请记得在部署到生成环境之前移除它。
scriptType
指定RequireJS将script标签插入document时所用的type=""值。默认为“text/javascript”。想要启用Firefox的JavaScript 1.8特性,可使用值“text/javascript;version=1.8”。