u33938848553020748807fm21gp0

为什么想到优化代码和合并代码

最近项目中使用到了 requirejs 然后陆陆续续引入了许多的 js 文件 造成了许多不必要的网络请求。(以后会改用 webpack 和 gulp 来对项目 js 进行打包 requirejs 感觉已经有点儿过时了) 下面将演示如何合并与压缩一个基于 RequireJS 的项目。本文中将用到苦干个工具,这其中就包括 Node.js。 因此,如果你手头上还没有 Node.js 可以点击此处下载一个。

动机

关于 RequireJS 已经有很多文章介绍过了。这个工具可以将你的 JavaScript 代码轻易的分割成苦干个模块(module)并且保持你的代码模块化与易维护性。这样,你将获得一些具有互相依赖关系的 JavaScript 文件。仅仅需要在你的 HTML 文档中引用一个基于 RequireJS 的脚本文件,所有必须的文件都将会被自动引用到这个页面上. 但是,在生产环境中将所有的 JavaScript 文件分离,这是一个不好的做法。这会导致很多次请求(requests),即使这个些文件都很小,也会浪费很多时间。 可以通过合并这些脚本文件,以减少请求的次数达到节省加载时间的目的。 另一种节省加载时间的技巧是缩小这些被加载文件的大小,相对小一些的文件会传输的更快一些。这个过程叫作最小化(minification) ,它是通过小心的改变脚本文件的代码结构并且不改变代码的形为(behavior)和功能(functionality)来实现的。例如这些:去除不必要的空格,缩短(mangling,或都压缩)变量(variables)名与函数(methods,或者叫方法)名,等等。这种合并并压缩文件的过程叫做代码优化( optimization)。这种方法除了用于优化(optimization)JavaScript 文件,同样适用于 CSS 文件的优化。 RequireJS 有两个主要方法(method): define()和 require()。这两个方法基本上拥有相同的定义(declaration) 并且它们都知道如何加载的依赖关系,然后执行一个回调函数(callback function)。与 require()不同的是, define()用来存储代码作为一个已命名的模块。 因此 define()的回调函数需要有一个返回值作为这个模块定义。这些类似被定义的模块叫作AMD(Asynchronous Module Definition,异步模块定义)。 如果你不大熟悉 RequireJS 或者不太明白我写的东西 - 不要担心。下面有一个关于这些的例子。

JavaScript 应用程序的优化

在本小节中我将向大家展示如何优化 Addy Osmani 的TodoMVC Backbone.js + RequireJS 项目。 由于 TodoMVC 项目在不同的框架下包含许多 TodoMVC 实现,我下载了 1.1.0 版并提取出 Backbone.js + RequireJS 应用程序。点击这里下载该应用程序并解压下载到的 zip 文件。todo-mvc 的解压目录将是我们这个例子的根目录(root path),从现在起我将把这个目录引用为。 查看/index.html 的源代码,你会发现它仅仅包含了一个 script 标签(另外一个是当你使用 Internet Explorer 时引用的): index.html 引用脚本文件的代码

1
<script src="__PUBLIC__/lib/require.min.js" data-main="__PUBLIC__/main.js"></script>

其实,整个项目只需要引用 require.js 这个脚本文件。如果你在浏览器中运行这个项目,并且在你喜欢的(擅长的)调试工具的 network 标签中, 你就会发现浏览器同时也加载了其它的 JavaScript 文件: qq%e6%88%aa%e5%9b%be20161106072943 我们将用RequireJS Optimizer(RequireJS 优化器)来优化这个项目。根据已下载的说明文件,找到 r.js 并将其复制到目录。 jrburke 的r.js是一个能运行基于 AMD 的项目的命令行工具,但更重要的是,它包含 RequireJS Optimizer 允许我们对脚本文件(scripts)合并与压缩。 RequireJS Optimizer 有很多用处。它不仅能够优化单个 JavaScript 或单个 CSS 文件,它还可以优化整个项目或只是其中的一部分,甚至多页应用程序(multi-page application)。它还可以使用不同的缩小引擎(minification engines)或者干脆什么都不用(no minification at all),等等。本文无意于涵盖 RequireJS Optimizer 的所有可能性,在此仅演示它的一种用法。 正如我之前所提到的,我们将用到 Node.js 来运行优化器(optimizer)。用如下的命令运行它(optimizer): 运行 RequireJS Optimizer

1
$ node r.js -o build.js

我认为构建一个配置文件比在命令行中使用参数的可读性更高,因此我将采用这种方式。接下来我们就为项目创建一个/build.js 文件,并且包括以下的参数: /build.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
({
appDir: './src',
baseUrl: './',
dir: './dist',
modules: [
{
name: 'main'
},
{
name:'index'
}
],
fileExclusionRegExp: /^(rbuild)\.js$/,
optimizeCss: 'standard',
removeCombined: true,
paths: {
"jquery": "lib/jquery",
"underscore": "lib/underscore",
"backbone": "lib/backbone",
"widget":"js/components/widget",
"window":"js/components/window",
"canlendar":"js/components/canlendar",
"jquery.fullpage":"lib/jquery.fullPage",
"jquery.transition":"lib/jquery.transition.min",
"jquery.easing":"lib/jquery.easing.min",
"tips":"js/tips",
"velocity":"lib/velocity/velocity.min", //动画库velocity
"velocity-ui":"lib/velocity/velocity.ui.min",//动画库velocity ui
"jquery-ui":"http://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.min",//jqueryui 库js
"RGBaster":'lib/RGBaster',
"lkmusic":"js/lkmusic_visualizer",
"util":'js/util',
"webaudio":'js/webaudio',
"common":"js/common",
"jquery.emotion":'js/jquery.emotion',
"blogdetail":"js/blog_detail",
"blogindex":"js/blog_index",
"blogworks":"js/blog_works",
"message":"js/message",
"TimeLine":"js/components/TimeLine",
"harmerjs":"lib/hammer.min",
'jquery.color':'lib/jquery.colorAnimations',
'jquery.flashcolor':'js/jquery.flashcolor',
"H5":'js/H5',
"H5_loading":'js/H5_loading',
"H5ComponentBase":'js/H5ComponentBase',
"musicList":'js/musicList'

},
/*对于那些没有采用AMD规范编写。如果要加载它们的话,必须先定义它们的特征,这里使用shim这个参数来进行配置*/
shim: {
"underscore": {
deps: [],
exports: "_"
},
"backbone": {
deps: ["jquery", "underscore"],
exports: "Backbone"
},
'jquery.fullpage': {
deps: ['jquery'],
exports: 'jQuery.fn.fullpage'
},
'jquery.color': {
deps: ['jquery']
}
,
'jquery.flashcolor':{
deps: ['jquery']
},
'jquery.easing': {
deps: ['jquery'],
exports: 'jQuery.fn.easing'
}
,
'jquery.transition': {
deps: ['jquery'],
exports: 'jQuery.fn.transition'
},
"velocity": {
deps: [ "jquery" ]
},
// Optional, if you're using the UI pack:
"velocity-ui": {
deps: [ "velocity" ]
},
"RGBaster": {

},
"lkmusic": {

},
"common":{

}
,
"tips":{
deps: ['jquery'],
exports: 'jQuery.fn.tips'
},
"jquery.emotion":{
deps: ['jquery'],
exports: 'jQuery.fn.emotions'
},
"harmerjs":{

}
,

"H5_loading":{

},
"H5ComponentBase":{

},
"musicList":{

}
}
})

项目目录结构:

qq%e6%88%aa%e5%9b%be20161106072319 qq%e6%88%aa%e5%9b%be20161106072535

参数

描述

appDir

应用程序的目录(即)。在这个文件夹下的所有文件将会被复制到 dir 参数标注的文件夹下。

baseUrl

相对于 appDir,代表查找文件的锚点(that represents the anchor path for finding files)。

dir

这是一个输出目录,所有的应用程序文件将会被复制到该文件夹下。

modules

一个包含多个对象的数组。每个对象代表一个将被优化的模块(module)。

fileExclusionRegExp

任何与此规则匹配的文件或文件夹都将不会被复制到输出目录。由于我们把 r.js 和 build.js 放置在应用程序目录下,我们希望优化器(optimizer)排除这两个文件。 因此我们可以这样设置/^(rbuild)\.js$/。

optimizeCss

RequireJS Optimizer 会自动优化应用程序下的 CSS 文件。这个参数控制 CSS 最优化设置。允许的值: “none”, “standard”, “standard.keepLines”, “standard.keepComments”, “standard.keepComments.keepLines”。

removeCombined

如果为 true,优化器(optimizer)将从输出目录中删除已合并的文件。

paths

模块(modules)的相对目录。

shim

为那些没有使用 define()声名依赖关系及设置模块值的模块,配置依赖关系与“浏览器全局”出口的脚本。

现在我们来看看优化后的效果 qq%e6%88%aa%e5%9b%be20161106072716 js 请求直接减少为两个 其他两个 js 是外部引入的。从十多个请求降低到现在的两个!很给力有木有。今天就到这里!