requirejs的学习与开始实践
基本介绍 requrejs是AMD规范的实践,有利于代码模块化。
基本用法
页面通过.引入requirejs与js的入口文件。一个页面只有只能引用一次requirejs,只能有一个入口文件,如强行引用多个requirejs与入口文件,则只会加载顺序最前面的那个。
模块js的加载的路径,是相对于baseurl的,默认值与data-main的属性值一致。如上的baseUrl为/lib/js。如果为进行config配置baseurl,则使用默认值。
进行引用脚本时候,不需要带.js。不过当引用路径为以下三种时候,则路径是相当于当前的html:
·以.js结束
·以/开始
·包含http https协议。
关于文件夹的架构,官网不建议多级嵌套目录来组织代码结构,而建议都放在baseurl中,要么是一个项目库/第三方库的扁平结构。paths可以配置模块,也可以配置模块路径。
入口文件即requirejs开始先要进行配置(配置文件的翻译会另外记录).
require.config({
})
配置为全局。即开始位置进行或者主文件进行配置,其他文件模块即可使用。由于requirejs加载的模块为异步加载,则页面正常通过src加载的js则不能保证顺序。
通过define定义方法定义模块。可以返回一切对象。若define需要依赖其他模块,则第一个则依赖其他模块。则第一个参数,为依赖模块的数组,第二个为回调函数。参数为依赖模块的注入,需要注意顺序。define的第一个参数还可以为字符串,此时为模块id,但是不建议自己设定,应有第三方工具设定。
并且requirejs可以包装commonjs规范的模块。如下:
commonjs模块
var foo = function () {};
exports = foo;
改成如下:
define(function (require, exports, module) {
var foo = function () {};
exports = foo;
})
注意就可以被其他requirejs模块引用。以上方法也可以通过require引用其他模块。
define(function (require, exports, module) {
var a = require('a')
var aa = function () {
return 'commonjs'
}
exports.aa = aa;
})
知道模块名字但是不知道路径的时候,可以通过依赖require使用同文件下的模块。
define(['require'], function (require) {
var aa = require('./c')
})
可以直接写成:
define(function (require) {
var aa = require('./c')
})
下列方法可以拿到模块的相对路径
define(function(require) {
var url = require.toUrl('./c');
})
循环依赖
如果a依赖b,b依赖a。有可能,在a中调用b的时候,a为undefined。则需要为b定义好后再用require方法获取。待解决
jsonp
jsonp的请求地址中的callback设定为define,则可定义为define,则返回数据可以作为一个模块。
require(['http://example.com/api/data.json?callback=define'], function (data) {
})
需要注意的是,无法处理超时。data也必须为object。也不能处理长连接,因为require会缓存第一个请求的数据。
require有undef模块,暂定。
require会把所有依赖的模块通过head.appendChild为每个添加script标签。
或者是 直接把配置写到html页面如下:
<script type="text/javascript" src='/lib/js/require.js'></script> <script type="text/javascript"> require.config({ baseUrl : '/lib/js/page1', paths : { page2 : '../page2' } }) require(['a', 'b', 'page2/c', 'page2/e'], function (a, b, c, e) { console.log(a) console.log(b) console.log(c) }) </script>
或者作为全局变量提前进行提前声明:
var require = {
deps: ["some/module1", "my/module2", "a.js", "b.js"],
callback: function(module1, module2) {
//This function will be called when all the dependencies
//listed above in deps are loaded. Note that this
//function could be called before the page is loaded.
//This callback is optional.
}
};
requirejs.config({
bundles: {
'primary': ['main', 'util', 'text', 'text!template.html'],
'secondary': ['text!secondary.html']
}
});
require(['util', 'text'], function(util, text) {
//The script for module ID 'primary' was loaded,
//and that script included the define()'d
//modules for 'util' and 'text'
});
压缩
require.js自身提供r.js进行文件的压缩与合并
由于自身使用nodejs,所以安装使用npm install -g require.js进行安装。同时也需要下载r.js放到根目录下。进行压缩可以使用命令行,也可以使用build.js进行配置。
以下为目前使用的一个配置:
build.js:
{
baseUrl:'web',
dir: "dist",
optimizeCss: "standard.keepLines",
removeCombined: true,
paths : {
jquery : 'common/jquery'
},
modules : [
{
name:'main'
}
]
}
baseUrl为当前文件路径,其他文件与模块的读取都以此进行变化。如果不进行appDir的配置,则默认的根文件为build.js所在文件夹。
dir为产出目录,位置基于baseUrl。上述示例则表示web的同级文件。
paths对模块进行路径进行配置。此处特地配置jquery的路径,是因为jquery是自身直接实现AMD规范,所有模块使用共同的名字($,jQuery),正常引用的话,$、jquery会为undefined。根据gitgub与stackoverflow的一些讨论,jquery的模块名字也不能为jQuery。
modules 配置文件没有通过mainConfigFile使用单独的压缩配置,所以此时压缩时候仅根据modules中的模块进行依赖分析,然后进行压缩与合并。所以modules的值应该为页面引用的顶级模块或者称之为程序的入口。
其他配置可以参考: github segmentfault
后记:
requirejs的学习暂时未用到的,很多高级用法后续再学习并使用,一下子走太大,怕hold不住。
[优思]主站开始采用requirejs进行开发。查阅一些参考资料后,考虑到整站的js文件压缩起来后应该在300K以内,所以整站便只使用一个顶级模块,然后根据不同页面考虑到功能性分多个文件夹,进行归放相近的模块。这样有两个问题:
1,由于页面dom操作比较多,比如同一个页面的dom操作是没有必要分开的,只需要功能性的模块分出去即可,所以如果科学合理的划分模块是一个要思考的。 2,既然dom操作,页面也比较多,是否考虑分多个入口文件,不同页面拥有不同的入口文件,那么如何科学合理的打包也是一个问题,特别是整站的js文件超过500K以后。
现在本地的一个测试,压缩后比压缩前减少了80个请求,请求时间由于服务器的网络问题数据不准确,但是也有大幅度的提高。
至于以后有什么用的心得和考虑,再补充。
