如何结合require和backbone.js

require.js+backbone 使用r.js 回压缩,本地不压缩,生产环境压缩 的实现方式 - JavaScript当前位置:& &&&require.js+backbone 使用r.js 回压缩,本地不压缩require.js+backbone 使用r.js 回压缩,本地不压缩,生产环境压缩 的实现方式&&网友分享于:&&浏览:0次require.js+backbone 使用r.js 来压缩,本地不压缩,生产环境压缩 的实现方式requie.js 和backbone.js 这里就不说了,可以去看官方文档,都很详细!
但是使用require.js 默认带的压缩方式感觉不是很方便,所以本文主要讲 利用r.js压缩,来实现本地不压缩,生产环境压缩
r.js 是运行在node上的,默认使用UglifyJS。UglifyJS真的很好用,那为什么说默认的方式 不是很方便呢?
r.js 单独压缩一个文件也很好用的,但在实际项目中,总不能一个一个压吧!因此r.js提供了一种多文件的压缩方式
,使用一个叫bulid.js 的配置文件来配置模块,这样可以压缩多个模块。
但是,问题有几个:
1.要维护一个配置文件,模块越多,越不好维护。当然也可写个自动生成配置文件的脚本,个人感觉也不好用,因为第二个问题。
2.压缩后,会生成整个文件夹压缩后的完整副本,这样你就要提交两个js的文件夹到你的代码库里了。而且压缩后的文件夹里存在代码的冗余,因为所有的代码都会根据层层依赖关系被压缩的一个入口文件中,加载是只需加载入口文件就行了,但其他的文件也被压缩了,被复制到了新的文件夹内。
3.压缩时每次都全部压缩,效率很低!可能也能实现部分压缩,不过我没找到合适的方法。
4.本地使用未压缩的,压缩后提交,不能保证100%的压缩正确(配置里的依赖万一出错了),这样需要提交到测试环境才能发现。
问题说完了,有能解决的欢迎回复。下面说说我的实现方式。window开发环境&&node环境&&apache需要开启rewrite和eTag。
首先大概说下原理:
总共分两步,1是合并;2是压缩;
1.利用apche的.htaccess文件将请求的入口文件(main.js) 重定向到一个php脚本里(本地环境里)。在这个脚本里来判断是否需要合并(这里说的只是合并,不是压缩),如果需要,利用r.js在另一个目录合并成一个main.dev.js ,然后根据所依赖的文件修改时间来生成eTag的token,设置eTag,并将内容输出。如果不需要合并(通过eTag来判断),则直接返回304,去读之前的缓存。.这样本地加载的即为合并但未压缩的js文件,便于调试.
2.这个main.dev.js 并不需要提交的你的代码库,只保留在本地就行。这是还需要另一个php脚本,通过一个批处理来调用。脚本的作用是把main.dev.js再相同的目录压缩出一个main.js,这里也需要根居main.js是否存在和main.js 与main.dev.js 的文件修改时间做比较,来判断是否压缩。压缩好的main.js 即使要提交到代码库里的(从main.dev.js 到main.js 相当于是单个文件压缩,没有依赖关系,这样出错的概率就很小很小了.很好的解决了上述提出的问题)。
下面来说下具体的实现方式:
1.目录结构是这样的:
简单解释下&
左边是js的目录结构图,lib是放核心框架的,如jquery等;common是放入自己写的公用模块,如弹出遮罩层等。app即应用的代码了,main是入口文件,product是放置合并过和压缩过的,文件名和main里的相同。其他的就是backbone的目录结构了,可能还有些不全面,这里先不考虑。
右边是压缩脚本的目录,r.js 即require.js 提供的压缩js脚本,compile.bat 调用压缩脚本的批处理文件,combine.php 合并代码的PHP脚本,conplile.php 是压缩代码的脚本,notmodified.php 是判断是否需要合并,原理是利用所依赖的文件修改时间生成Etag的token,combine_css.php 是合并css的脚本,讲完js压缩后再说。
2.了解了目录的结构和基本原理,剩下的就是贴代码了。
html的的引入:
&script data-main=&&?=$jsServer?&js/app/product/spc& src=&&?=$jsServer?&js/lib/require-2.1.14.min.js?v=&?=$ver?&&&&/script&程序的入口是js/app/product/spc,这个文件是由js/app/mian/spc.js经过合并和压缩的到的,即在生产环境使用的。
在本地环境的话,就要靠.htaccess这个文件了
# 将js/app/product/spc.js 重定向到combine.php这个脚本里,并将product替换为main,
# 即js/app/mian/spc.js 这个真正的入口文件路径作为参数传过去
rewriteCond %{REQUEST_FILENAME} ^(.*)product(.*\.js)$
rewriteCond %1main%2 -f
RewriteRule ^(.*)product(.*\.js)$ autocompile/combine.php?f=$1main$2 [B,L]
#css的合并,和上面的一样,只不过对应处理的脚本不同
rewriteCond %{REQUEST_FILENAME} ^(.*)product(.*\.css)$
rewriteCond %1main%2 -f
RewriteRule ^(.*)product(.*\.css)$ autocompile/combine_css.php?f=$1main$2 [L]
#如果xxx.(js||css)有对应的xxx.dev.(js||css) 则将重定向到.dev.js或.dev.css
#这个是给已经合并和已经压缩好的js或css 来用的
#比如lib/jquery.js,你在本地可以下载对应的debug版,修改文件名为jquery.dev.js ,这样本地也可以调试jquery了
rewriteCond %{REQUEST_FILENAME} ^(.*)\.(js|css)$
rewriteCond %1.dev.%2 -f
RewriteRule ^(.*)\.(js|css)$ $1.dev.$2 [L]
下面就是关键combine.php了
include 'notmodified.php';
define('BASE', dirname(__FILE__));
$file_main = BASE.'/../'.$_GET['f'];
$file_config = BASE.'/../js/config.js'; //require.js 的公用配置文件
$comment_reg_exp = '/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/m';
//匹配注释的正则
$js_require_reg_exp = '/[^.]\s*require\s*\(\s*[\&\']([^\'\&\s]+)[\&\']\s*\)/';
//提取依赖文件的正则
$exclude_reg_exp = '/\s*exclude\s*:\s*(\[.*?\])/s';
//提取依赖文件但不需要合并压缩的正则
$alias_reg_exp = '/\s*paths\s*:\s*(\{.*?\})/s';
//提取有别名文件的正则
$data_dep_file = array($file_main, $file_config);
//所依赖文件的数组,包括自身和config文件
$data_ex_dep_file = array();
//不需压缩的依赖文件数组
$data_alias_file = '';
//有别名的的文件字符串
if(file_exists($file_config)){
$text_config = file_get_contents($file_config);
$text_config = preg_replace($comment_reg_exp, '', $text_config);
//去掉注释
preg_match_all($exclude_reg_exp, $text_config, $matches);
if(isset($matches[1][0])){
//取出不需压缩的依赖文件配置
$data_ex_dep_file = json_decode(str_replace(&\n&,'',str_replace(& &, &&, str_replace(&'&, '&', $matches[1][0]))), true);
preg_match_all($alias_reg_exp, $text_config, $matches);
if(isset($matches[1][0])){
//取出有别名的真正文件配置
$data_alias_file = str_replace(&\n&,'',str_replace(& &, &&, str_replace(&'&, '&', $matches[1][0])));
function get_true_path($alias){
//取出有别名的的真正文件名
global $data_alias_
$alias_escape = str_replace('.','\.', str_replace('/','\/',$alias));
$regExp ='/'.$alias_escape.':&(.*?)&/';
preg_match_all($regExp, $data_alias_file, $matches);
if(isset($matches[1][0])){
return $matches[1][0];
function get_dep_files($file_name){
global $js_require_reg_exp, $data_dep_file, $data_ex_dep_file, $comment_reg_
if(file_exists($file_name)){
$text_main = file_get_contents($file_name);
$text_main = preg_replace($comment_reg_exp, '', $text_main);
preg_match_all($js_require_reg_exp, $text_main, $matches);
if(isset($matches[1]) && is_array($matches[1]) && count($matches[1]) & 0){
//取出依赖文件
foreach($matches[1] as $v){
$v = trim($v);
$v_true = get_true_path($v);
$v_path = BASE.'/../js/'.$v_true.(strrchr($v, '.') == '.js' ? '' : '.js');
//所依赖的文件的完整路径
if(!in_array($v, $data_ex_dep_file) && !in_array($v_path, $data_dep_file)){
$data_dep_file[] = $v_
get_dep_files($v_path); //递归取出依赖文件
get_dep_files($file_main);
$ext = strrchr($file_main, '.');
$file_name = basename($file_main, $ext);
$file_source = 'app/main/'.$file_
$file_output = BASE.'/../js/app/product/'.$file_name.'.dev.js';
if(file_exists($file_output) && notmodified($data_dep_file)){
//判断是否需要压缩,如果没有修改过,会返回304,去读缓存
exec('node r.js -o mainConfigFile='.BASE.'/../js/config.js baseUrl='.BASE.'/../js/ name='.$file_source.' out='.$file_output.' optimize=none');
//使用node 压缩,生成dev文件,optimize=none 是只合并的意思
header('Content-Type: application/javascript');
echo file_get_contents($file_output);
下面是notmodified.php
function notmodified($files = array()){
$s = '';
if(is_string($files)){
$files = array($files);
if($files){
foreach($files as $f){
$s .= filemtime($f); //拼接所依赖文件修改时间,用来生成eTag的token
$etag = sprintf('%08x', crc32($s));
header(&ETag: \&$etag\&&);//输出eTag
if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && strpos($_SERVER['HTTP_IF_NONE_MATCH'], $etag)){
header('HTTP/1.1 304 Not Modified');// 如果没有修改过,则返回304,去读缓存
下面看下入口文件main/spc.js
require([javascriptServer+&js/config.js&], function(){// 加载公用的配置文件后,再开始定义模块。javascriptServer是全局变量,放置js的域名,如果 是本域,则不用写
require(['app/main/spc']);
define(function(require){
&use strict&;
var app = require('app/views/app');
new app();
下面看公用配置文件config.js到此已经完成大部分工作了,还剩下最后上生产的压缩工作
requirejs.config({
baseUrl: typeof(javascriptServer) === 'undefined' ? '' : javascriptServer
+ 'js/',
jquery: 'lib/jquery-1.11.1.min',
underscore: 'lib/underscore-1.6.min',
backbone: 'lib/backbone-1.1.2.min'
useStrict: true,
exclude: ['jquery', 'underscore', 'backbone'],//不需要合并的文件,使用r.js 进行合并或压缩时,读此配置文件:node r.js -o mainConfigFile='.BASE.'/../js/config.js ......
shim: { /*目前backbone和underscore都已支持amd!如果是不支持的版本,则需要下面的配置。
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
underscore: {
exports: '_'
先看批处理 compile.bat,很简单
php compile.php &../js/app/product&
php compile.php &../css/product&
再看compile.php,也很简单
define('BASE', dirname(__FILE__));
if($argc == 1){
compile(BASE);
compile(BASE.'/'.$argv[1]);
function compile($dir){
$h = opendir($dir);
while(($f = readdir($h)) !== false){
if($f == '.' || $f == '..'){
$f = $dir.'/'.$f;
if(is_dir($f)){
compile($f);
}else if(substr($f, -7) == '.dev.js'){//压js
$ext = strrchr($f, '.');
$out = substr($f, 0, -7).'.js';
if(!file_exists($out) || filemtime($f) & filemtime($out)){
system('node r.js -o mainConfigFile='.BASE.'/../js/config.js baseUrl='.BASE.'/../js/ name=app/product/'.basename($f, $ext).' out='.$out);
}else if(substr($f, -8) == '.dev.css'){//压css
$out = substr($f, 0, -8).'.css';
if(!file_exists($out) || filemtime($f) & filemtime($out)){
system('node r.js -o cssIn='.$f.' out='.$out.' optimizeCss=standard');
closedir($h);
最后要说下,其实这个套路有两个可以容忍小bug,平时需要注意下。
1.如果(往前)修改了本地时间后,再进行压缩,可能会导致压缩失败。
& 解决办法:把时间调正确后,删除produt/xxx.js ,重新从版本库里更新,再进行压缩。其实注意下压缩时不要修改本地时间就可以了。
2.如果ctrl+F5 或清空缓存的话,即使文件没有修改,也会重新合并,因为eTag 被清除了!
& 解决办法:这个问题其实不用管,如果是没修改的被重新压缩了,不提交就可以了,提交了也没太大关系!
& &目前只能先忍着,如果有好的方法,欢迎指导。
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有如何结合require和backbone_百度知道如何结合require和backbone_百度知道&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!&&&&一个结合了require.js+backbone的例子,适合初学者
一个结合了require.js+backbone的例子,适合初学者
一个结合了require.js+backbone的例子,适合初学者
若举报审核通过,可奖励20下载分
被举报人:
dingmm1990
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
开发技术下载排行

我要回帖

更多关于 backbone和require 的文章

 

随机推荐