requireJS实战

为什么需要requireJS

  • 减少网络请求数
  • 压缩js, css减轻服务器负担(当然了,小站点压缩不压缩问题不大)
  • 混淆代码,增加扒站的成本

代码结构

├── build.js // r.js 配置文件
├── r.js // 分发工具
├── src //本地开发目录
│   ├── css
│   │   ├── website.css
│   │   ├── reset.css
│   └── js
│   ├── app
│   │   ├── some_page.js //页面内前端实现逻辑
│   ├── common.js // 通用配置
│   ├── config.js // 用于后端传递数据到前端
│   ├── some_page.js // requireJS 的data-main 域所指定的文件,此文件主要调用通用配置+上面具体实现的some_page.js模块
│   ├── lib
│   │   ├── jquery
│   │   │   └── 1.8.3
│   │   │   └── jquery-1.8.3.js
│   │   ├── layer
│   │   │   ├── extend
│   │   │   │   └── layer.ext.js
│   │   │   ├── layer.min.js
│   │   │   └── skin
│   │   │   ├── default
│   │   │   │   ├── icon_ext.png
│   │   │   │   ├── textbg.png
│   │   │   │   ├── xubox_ico0.png
│   │   │   │   ├── xubox_loading0.gif
│   │   │   │   ├── xubox_loading00.gif
│   │   │   │   ├── xubox_loading1.gif
│   │   │   │   ├── xubox_loading3.gif
│   │   │   │   └── xubox_title0.png
│   │   │   ├── layer.css
│   │   │   └── layer.ext.css
│   │   └── webuploader
│   │   ├── README.md
│   │   ├── Uploader.swf
│   │   ├── webuploader.css
│   │   ├── webuploader.custom.js
│   │   ├── webuploader.custom.min.js
│   │   ├── webuploader.fis.js
│   │   ├── webuploader.flashonly.js
│   │   ├── webuploader.flashonly.min.js
│   │   ├── webuploader.html5only.js
│   │   ├── webuploader.html5only.min.js
│   │   ├── webuploader.js
│   │   ├── webuploader.min.js
│   │   ├── webuploader.noimage.js
│   │   ├── webuploader.noimage.min.js
│   │   ├── webuploader.nolog.js
│   │   ├── webuploader.nolog.min.js
│   │   ├── webuploader.withoutimage.js
│   │   └── webuploader.withoutimage.min.js
│   ├── other_page.js
├── dist //线上分发的目录
│   ├── css
│   │   ├── website.css //多个CSS同时也会压缩成一个
│   └── js
│   ├── some_page.js // 将所有依赖压缩在此文件内
├── img // 图片目录

压缩构建

首先上build.js内的配置内容

({
appDir: "./src",
baseUrl: 'js',
dir: "./dist",
paths: {
'app': 'app',
'jquery': 'lib/jquery/1.8.3/jquery-1.8.3',
'jquery.cxslide': 'lib/cxslide/jquery.cxslide',
'layer': 'lib/layer/layer.min',
'webuploader': 'lib/webuploader/webuploader.min',
'typeahead': 'lib/typeahead/typeahead.bundle.min',
'helper': 'helper',
'waterfall': 'lib/waterfall/waterfall.min',
'Handlebars': 'lib/handlebars/handlebars',
'validationengine': 'lib/validation_engine/jquery.validationEngine.min'
},
shim: {
'jquery.cxslide': ['jquery'],
'layer': ['jquery'],
},
removeCombined: true,
findNestedDependencies: true,
preserveLicenseComments: true, //保留相关的版权信息
modules: [
{
name: "some_page" //定义模块
}
]
})

压缩方面比较简单,直接使用requireJS提供的r.js就行了,命令如下

node r.js -o build.js

遇到的几个小坑

共享requireJS配置文件

目前是把通用配置放在 src/js/common.js 里面,然后在 src/js/some_page.js 里面引入,示例代码如下
src/js/some_page.js文件

requirejs(['./common'], function () {
requirejs(['app/homepage']); //页面内的具体逻辑代码放置在src/js/app/homepage.js里面
});

src/js/common.js 文件

requirejs.config({
baseUrl: '/src/js/lib',
shim: {
'jquery.cxslide': ['jquery'],
'layer': ['jquery'],
'webuploader': ['jquery'],
'typeahead': {
deps: ["jquery"],
exports: "Bloodhound"
},
'waterfall': ['jquery'],
'Handlebars': {
exports: 'Handlebars'
},
'validationengine' : ['jquery'],
'parallax' : ['jquery']
},
paths: {
'app': '../app',
'jquery': '../lib/jquery/1.8.3/jquery-1.8.3',
'jquery.cxslide': '../lib/cxslide/jquery.cxslide',
'layer': '../lib/layer/layer.min',
'webuploader': '../lib/webuploader/webuploader.min',
'typeahead': '../lib/typeahead/typeahead.bundle.min',
'helper': '../helper',
'waterfall': '../lib/waterfall/waterfall',
'Handlebars': '../lib/handlebars/handlebars',
'validationengine': '../lib/validation_engine/jquery.validationEngine.min',
'parallax': '../lib/parallax/parallax.js'
}
});

服务端向模块内传送数据

不知道为什么,requreJS官方文档里面我没有找到怎么处理这个问题,难道全部用ajax实现?现在查到的临时解决方案是这样的
建立 src/js/config.js 文件,作为中转,具体内容如下

define(function() {
return {};
});

然后在对应的页面模板上面给config模块传送服务端变量,示例如下

<html>
<head></head>
<body>
<div>some content</div>
</body>
<script>
define('config', function() {
return {
pic_id: '{{ $detail->id }}',
avatar: '{{ $userInfo['avatar'] }}',
add_to_album_url: '{{ URL::route('add_to_album') }}',
belongedAlbum: '{{ $isAddedUserAlbum }}',
delete_photo: '{{ URL::route('delete_photo') }}'
};
});
</script>
</html>

接着在需要服务端变量的地方,把config模块require进来就行,获取变量值直接config.[变量名]就可以拿到值了,如下所示

var config = require('config');

build.js 的一点不足

build.js 内需要把每一个需要压缩的模块都列出来后再执行压缩,这个比较麻烦,还没有找到特别好的方法。
对付小项目还行,大项目是一定需要一个完整的工具链来做前端静态文件的分发及版本控制。如果有知道方案的同学,麻烦告知,感谢!!!

还需努力完善

等后端代码完整从Laravel 4.2 迁移到 5.1 的时候再优化前端构建这一块的内容,目前暂时还够用。

巨人的肩膀

What is the preferred method for passing server data to a RequireJS module?
requirejs:让人迷惑的路径解析
Using r.js to Optimize Your RequireJS Project
前端优化:RequireJS Optimizer 的使用和配置方法(一)
前端优化:RequireJS Optimizer 的使用和配置方法(二)
How to load bootstrapped models in Backbone.js while using AMD (require.js)
r.js 配置文件 example.build.js 不完整注释