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个请求,请求时间由于服务器的网络问题数据不准确,但是也有大幅度的提高。
至于以后有什么用的心得和考虑,再补充。