这里只是调侃一下,“杏仁”其实指的是almond,requirejs作者的另一个开源项目,它的定位是作为requirejs的一个替代品。
本文概要:
1. 使用场景
2. 打包例子:未使用almond
3. 打包例子:使用almond
4. 如何暴露公共API
5. 限制 & 支持的特性
6. 写在后面 & demo下载
什么情况下需要使用almond
呢?假设你手头有个基于requirejs的小项目,所有业务代码加起来就几十K(压缩后可能更小).出于性能优化的考虑,你可能在想:如果能够去掉requirejs的依赖就好了,毕竟,gzip后的requirejs还有大概20k(2.1.6版本)。
almond就是为了这个目的而诞生的,开发过程,你可以照常使用requirejs来管理你的依赖,而到了打包上线阶段,替换成almond就行了。gzip后的almond只有大约1k,优化幅度相当大。
这一小节主要举个requirejs+r.js
打包的例子,下一小杰会在本小节的基础上,通过almond
进行进一步的优化。代码很简单,扫一下就可以了
目录结构如下:
demo.html
build.js
js/
js/main.js
js/cookie.js
js/util.js
demo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>demo</title>
</head>
<body>
<h1>简单的requirejs例子 - almond</h1>
<script type="text/javascript" src="js/require.js" data-main="js/main-built.js"></script>
<!-- <script type="text/javascript" src="js/main-almond-built.js"></script> -->
</body>
</html>
js/main.js
requirejs.config({
baseUrl: 'js'
});
require(['cookie', 'util'], function(Cookie, Util){
Cookie.say('hello');
Util.say('hello');
});
js/cookie.js
define([], function(){
return {
say: function(msg){
alert('cookie: '+msg);
}
};
});
js/util.js
define([], function(){
return {
say: function(msg){
alert('util: '+msg);
}
};
});
首先,在build.js
里声明打包的配置
({ baseUrl: "js", name: "main", optimize: "none", out: "js/main-built.js" })
然后,下载打包工具r.js
npm install -g requirejs
最后,通过r.js
打包
r.js -o build.js
恭喜!可以看到js
目录下生成了打包后的文件main-built.js
js/main-built.js
define('cookie',[], function(){
return {
say: function(msg){
alert('cookie: '+msg);
}
};
});
define('util',[], function(){
return {
say: function(msg){
alert('util: '+msg);
}
};
});
requirejs.config({
baseUrl: 'js'
});
require(['cookie', 'util'], function(Cookie, Util){
Cookie.say('hello');
Util.say('hello');
});
define("main", function(){});
为了检验打包后的结果是运行的,我们需要到浏览器里验证一下。首先我们要把demo.html
里的资源引用修改下
<script type="text/javascript" src="js/require.js" data-main="js/main-built.js"></script>
在浏览器里打开demo.html
,看到下面的弹窗,搞定
我们看到,上面的例子打包后生成了main-built.js
,gzip后看下文件多大
gzip main-built.js
可以看到只有174B,这种情况下,在页面中引用requirejs有点不划算,这个时候我们就要引入almond了
-rw-r--r-- 1 user staff 174B 4 20 22:03 main-built.js.gz
很简单,首先下载almond,并放置到js
目录下
然后,运行下面命令,通过r.js + almond
生成打包后的文件main-almond-built.js
r.js -o baseUrl=js name=almond include=main out=js/main-almond-built.js wrap=true optimize=none
js/main-almond-built.js
/** * @license almond 0.2.9 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/almond for details */
// almond的代码篇幅略长,这里略过...
define("cookie",[],function(){return{say:function(e){alert("cookie: "+e)}}}),define("util",[],function(){return{say:function(e){alert("util: "+e)}}}),requirejs.config({baseUrl:"js"}),require(["cookie","util"],function(e,t){e.say("hello"),t.say("hello")}),define("main",function(){});
同样,在修改修改main.js
的链接后,在浏览器里访问demo.html
,done!
<script type="text/javascript" src="js/main-almond-built.js"></script>
看下gzip后的main-almond-built.js
多大,只有1.6k!
-rw-r--r-- 1 user staff 1.6K 4 20 22:34 main-almond-built.js.gz
上面打包的命令行有点长,对于楼主这样对命令行有恐惧症的人来说,还是比较习惯写个配置文件,命令行则越简短越好
build-almond.js
({ baseUrl: "js", name: "almond", include: "main", out: "js/main-almond-built.js", wrap: true })
接下来就很简单了,很短的一行命令
r.js -o build-almond.js
上面的例子,如果没有加上wrap: true
这个选项,打包后生成的文件,你是可以访问到之前的定义的模块的,比截图所
但加上wrap: true
后就完全不一样了,因为所有的代码都会被包在一个匿名的闭包里,大致如下
(function () {
//almond will be here
//main and its nested dependencies will be here
}());
此时就访问不到之前定义的模块了,包括require
都成了匿名函数里的一个局部变量
这种情况下,如果我们想要访问模块里的方法,该怎么做呢?可以修改下配置文件
build-almond-frag.js
({ baseUrl: "js", name: "almond", include: "main", out: 'js/main-built-almond-public.js', wrap: { startFile: 'js/start.frag.js', endFile: 'js/end.frag.js' }
})
js/start.frag.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else {
root.Main = factory();
}
}(this, function () {
//almond, and your modules will be inlined here
js/end.frag.js
return { cookie: require('cookie'), util: require('util') };
}));
打包
r.js -o build-almond-frag.js
生成的文件结构如下
start.frag
almond.js
modules for your lib, including 'main'
end.frag
现在,可以在浏览器里继访问我们暴露的API了
毫无意外,almond只是支持了requirejs
功能的子集,所以,在使用前需要了解下它的支持哪些特性,有哪些限制。
requirejs.config()
(原来可以调用两次??)var require = {};
来传递配置参数require.toUrl()
、require.nameToUrl()
do not use packages/packagePaths config. If you need to use packages that have a main property, volo can create an adapter module so that it can work without this config. Use the amdify add command to add the dependency to your project.
本文简单介绍了下如何通过almond
对依赖requirejs的项目进行进一步的优化。当然,almond
也存在着一些限制,比如无法动态加载模块、只能将模块打包成一个文件等,具体的可以参考这里。是否在打包阶段使用almond
替代requirejs
,得看具体场景,这里就不展开,后面有时间再简单介绍下。
demo下载