使用Gulp来实现Laravel4的Assets管理

The Problem

需要有一个自动化工具来管理 Assets (css,js,img etc..) , 具备以下功能

  • 支持编译 scss, coffee script, less 等语言;
  • 合并文件的能力, 把页面上所有的 css 和 js 各自合并为一个文件, 将极大提高网页的加载速度;
  • 压缩 css 和 js 的能力, 减少文件大小, 注意这里的压缩不只是去除空格和换行;
  • 支持 CDN 加速, 需要对每次修改的文件加版本号, 这是最有效的, 也是最合理的客户端样式更新方法;
  • 开发要足够简单;
  • 部署要足够简单;

有两个工具作为候选, 一个是 Grunt, 一个是 Gulp, 最后选择 Gulp , 因为其易用性, 并且是个新奇玩意, 此项目在 web 开发的开源世界中非常受欢迎, 虽然出现的时间只有短短的一年 (第一个提交 contra authored on Jul 4, 2013).

安装和配置 gulp.js

gulp.js 依赖于 nodejs, 如果你使用 Homestead 作为开发环境的话, 这些东西已经都装好了, 如果你还没有安装 Homestead 请看这里 Laravel 4 的 Homestead 开发环境部署 .

配置 package.json

在项目根目录下, 创建 package.json 并填入以下内容:

  1.   "devDependencies": { 
  2.     "del""^0.1.2"
  3.     "gulp""^3.8.7"
  4.     "gulp-asset-manifest""0.0.4"
  5.     "gulp-autoprefixer""0.0.10"
  6.     "gulp-concat""^2.3.4"
  7.     "gulp-minify-css""^0.3.7"
  8.     "gulp-rev""^1.1.0"
  9.     "gulp-sass""^0.7.3"
  10.     "gulp-uglify""^1.0.0" 
  11.   } 

关于里面每一个 package 的说明见以下注释:

  1.   "devDependencies": { 
  2.     "del""^0.1.2",            // 删除文件 
  3.     "gulp""^3.8.7",           // 主程序 
  4.     "gulp-asset-manifest""0.0.4"// 压缩 css  
  5.     "gulp-autoprefixer""0.0.10",  // 自动给 css3 属性加浏览器前缀, 如: `-webkit-` 
  6.     "gulp-concat""^2.3.4",        // 文件合并 
  7.     "gulp-minify-css""^0.3.7",    // // 压缩 css  
  8.     "gulp-rev""^1.1.0",           // 给文件加版本号, 如 `script-$version$.js` 
  9.     "gulp-sass""^0.7.3",      // 编译 scss 
  10.     "gulp-uglify""^1.0.0"     // 压缩 js 
  11.   } 

保存后在根目录下运行以下命令下载 package

  1. npm install 

Gulpfile.js

在根目录下创建文件 Gulpfile.js , 填入以下内容:

 
  1. var gulp = require('gulp'); 
  2. var sass = require('gulp-sass'); 
  3. var autoprefixer = require('gulp-autoprefixer'); 
  4. var uglify = require('gulp-uglify'); 
  5. var concat = require('gulp-concat'); 
  6. var rev = require('gulp-rev'); 
  7. var del = require('del'); 
  8. var filename = require('gulp-asset-manifest'); 
  9. var minifycss = require('gulp-minify-css'); 
  10.  
  11. // Paths to your asset files 
  12. var paths = { 
  13.     frontend: { 
  14.         scripts: [ 
  15.             'app/assets/js/jquery.min.js'
  16.             'app/assets/js/bootstrap.min.js'
  17.             'app/assets/js/moment.min.js'
  18.             'app/assets/js/zh-cn.min.js'
  19.             'app/assets/js/emojify.min.js'
  20.             'app/assets/js/jquery.scrollUp.js'
  21.             'app/assets/js/jquery.pjax.js'
  22.             'app/assets/js/nprogress.js'
  23.             'app/assets/js/jquery.autosize.min.js'
  24.             'app/assets/js/prism.js'
  25.             'app/assets/js/jquery.textcomplete.js'
  26.             'app/assets/js/emoji.js'
  27.             'app/assets/js/ekko-lightbox.js'
  28.             'app/assets/js/main.js'
  29.         ], 
  30.         styles: [ 
  31.             'app/assets/css/bootstrap.min.css'
  32.             'app/assets/css/font-awesome.min.css'
  33.             'app/assets/css/main.css'
  34.             'app/assets/css/markdown.css'
  35.             'app/assets/css/nprogress.css'
  36.             'app/assets/css/prism.css'
  37.         ] 
  38.     } 
  39.  
  40. // CSS task 
  41. gulp.task('css'function() { 
  42.  
  43.     // Convert scss first 
  44.     gulp.src('app/assets/sass/**/*.scss'
  45.         .pipe(sass()) 
  46.         .pipe(autoprefixer('last 10 version')) 
  47.         .pipe(gulp.dest('app/assets/css')); 
  48.  
  49.     // Cleanup old assets 
  50.     del(['public/assets/css/styles-*.css'], function (err) {}); 
  51.  
  52.     // Prefix, compress and concat the CSS assets 
  53.     // Afterwards add the MD5 hash to the filename 
  54.     gulp.src(paths.frontend.styles) 
  55.         .pipe(concat('styles.css')) 
  56.         .pipe(rev()) 
  57.         .pipe(filename({ bundleName: 'frontend.styles' })) // This will create/update the assets.json file 
  58.         .pipe(minifycss()) 
  59.         .pipe(gulp.dest('public/assets/css')); 
  60. }); 
  61.  
  62. // JavaScript task 
  63. gulp.task('js'function() { 
  64.     // Cleanup old assets 
  65.     del(['public/assets/js/scripts-*.js'], function (err) {}); 
  66.  
  67.     // Concat and uglify the JavaScript assets 
  68.     // Afterwards add the MD5 hash to the filename 
  69.     gulp.src(paths.frontend.scripts) 
  70.         .pipe(concat('scripts.js')) 
  71.         .pipe(uglify()) 
  72.         .pipe(rev()) 
  73.         .pipe(filename({ bundleName: 'frontend.scripts' })) // This will create/update the assets.json file 
  74.         .pipe(gulp.dest('public/assets/js')); 
  75. }); 
  76.  
  77. gulp.task('build', ['css''js']); 
  78.  
  79. gulp.task('watch'function(){ 
  80.     gulp.watch('app/assets/sass/**/*.scss', ['css']); 
  81.     gulp.watch('app/assets/css/**/*.css', ['css']); 
  82.     gulp.watch('app/assets/js/**/*.js', ['js']); 
  83. }); 
  84.  
  85. // The default task (called when you run `gulp` from cli) 
  86. gulp.task('default', ['build''watch']); 

关于上面代码的一些解释:

  1. // 第一部分是引入 package 
  2. var gulp = require('gulp'); 
  3. ... 中间省略一堆 
  4. var minifycss = require('gulp-minify-css'); 
  5.  
  6. // 手动来设置这些文件, 这样的话会我们可以控制其合并文件时候 
  7. // 的顺序, 以后要加入某个 js 或者 css 的时候都在此添加 
  8. var paths = { 
  9.     frontend: { 
  10.         scripts: [ 
  11.             'app/assets/js/jquery.min.js'
  12.             ... 中间省略一堆 
  13.             'app/assets/js/main.js'
  14.         ], 
  15.         styles: [ 
  16.             'app/assets/css/bootstrap.min.css'
  17.             ... 中间省略一堆 
  18.             'app/assets/css/prism.css'
  19.         ] 
  20.     } 
  21.  
  22. // CSS task 
  23. gulp.task('css'function() { 
  24.  
  25.     // 先编译 scss  
  26.     gulp.src('app/assets/sass/**/*.scss'
  27.         .pipe(sass()) 
  28.         .pipe(autoprefixer('last 10 version')) 
  29.         .pipe(gulp.dest('app/assets/css')); 
  30.  
  31.     // 清除之前的文件 
  32.     del(['public/assets/css/styles-*.css'], function (err) {}); 
  33.  
  34.     gulp.src(paths.frontend.styles)     // 处理scc 文件 
  35.         .pipe(concat('styles.css'))     // 合并 
  36.         .pipe(rev())                    // 加版本号 
  37.         .pipe(filename({ bundleName: 'frontend.styles' })) // 生成 asset_manifest.json 文件 
  38.         .pipe(minifycss())              // 压缩 
  39.         .pipe(gulp.dest('public/assets/css'));  // 存放到 `public/assets/css` 文件夹 
  40. }); 
  41.  
  42. // JavaScript task 
  43. gulp.task('js'function() { 
  44.     // 清除之前的文件 
  45.     del(['public/assets/js/scripts-*.js'], function (err) {}); 
  46.  
  47.     gulp.src(paths.frontend.scripts)    // 处理 js 文件列表 
  48.         .pipe(concat('scripts.js'))     // 合并 
  49.         .pipe(uglify())                 // 压缩   
  50.         .pipe(rev())                    // 加版本号 
  51.         .pipe(filename({ bundleName: 'frontend.scripts' })) // 生成 asset_manifest.json 文件 
  52.         .pipe(gulp.dest('public/assets/js'));   // 存放到 `public/assets/js` 文件夹 
  53. }); 
  54.  
  55. // 设置 build 任务, 此任务调用上面定义的 css 和  js 任务 
  56. gulp.task('build', ['css''js']); 
  57.  
  58. // 设置 build 任务, 方便开发, css 和 js 文件一修改, 立刻进行重新编译 
  59. gulp.task('watch'function(){ 
  60.     gulp.watch('app/assets/sass/**/*.scss', ['css']); 
  61.     gulp.watch('app/assets/css/**/*.css', ['css']); 
  62.     gulp.watch('app/assets/js/**/*.js', ['js']); 
  63. }); 
  64.  
  65. // 默认命令行运行 `gulp` 的时候开始执行 build 和 watch 任务 
  66. gulp.task('default', ['build''watch']); 

asset_manifest.json 文件

保存完上面文件后, 当我们在命令行下运行

gulp build 

后, 就会在 public/assets/jspublic/assets/css 生成最终会在模版里面使用的文件, 文件名: * styles-$version$.css * scripts-$version$.js

其中 $version$ 是变量, 每一次文件修改的时候, 都会不一样, 类似于 scripts-39eb8a9a.jsstyles-7c717f38.css.

问题: $version$ 会随着文件修改而变化, 模版里该怎么来引用他们?

asset_manifest.json 文件的作用就是为了解决这个问题, 每一次文件一修改, 作为各种操作后, gulp-asset-manifest 插件会把修改后的文件名存放到此文件里面, 类似于这样:

  1.     "frontend.scripts":[ 
  2.         "scripts-39eb8a9a.js" 
  3.     ], 
  4.     "frontend.styles":[ 
  5.         "styles-7c717f38.css" 
  6.     ] 

那么接下需要做的事情就是写一个 php 脚本来读取并解析此文件, 获取最终处理好的 css 和 js 文件名, 并在模版里面引用.

Laravel4 的 asset-manager Package

asset-manager 正是做了上面最后谈到的 一个 php 脚本 所做的事, 原始的项目在这里 modbase/asset-manager , 可惜只支持 Laravel4.1, 原作者已经不再维护, 只能自己 folk 一份, 并做了些许修改 summerblue/asset-manager .

Composer 安装 asset-manager

使用 repository 来安装, 在 composer.json 里面加入:

  1. "repositories": [ 
  2.         { 
  3.             "type""vcs"
  4.             "url""https://github.com/summerblue/asset-manager" 
  5.         } 
  6.     ],  

在 require 节点下添加

"summerblue/asset-manager": "0.2.*" 

修改后如下图:

然后

composer update 

修改 app/config/app.php, 在 providers 数组里面添加:

'Modbase\AssetManager\AssetManagerServiceProvider' 

至此部署完成, 接下来讲讲怎么使用.

一般使用

在修改 css 和 js 之前, 先在项目根目录下命令行执行 gulp :

➜  phphub git:(master) ✗ gulp [07:45:45] Using gulpfile ~/Projects/phphub.org/phphub/Gulpfile.js [07:45:45] Starting 'css'... [07:45:45] Finished 'css' after 12 ms [07:45:45] Starting 'js'... [07:45:45] Finished 'js' after 10 ms [07:45:45] Starting 'build'... [07:45:45] Finished 'build' after 5.17 μs [07:45:45] Starting 'watch'... [07:45:45] Finished 'watch' after 14 ms [07:45:45] Starting 'default'... [07:45:45] Finished 'default' after 5 μs [07:45:47] Starting 'css'... [07:45:47] Finished 'css' after 4.12 ms [07:45:47] Starting 'css'... [07:45:47] Finished 'css' after 4.13 ms 

请让此命令行一直保持执行着, 因为 TA 正在监控着你的文件修改.

需要添加 css 和 js 文件的话, 请到 Gulpfile.js 里面的 paths 选项下添加, 并重启 gulp 的监控.

添加 .gitignore 文件

修改根目录下的 . gitignore 文件, 添加这几行:

public/assets/css/* public/assets/js/* asset_manifest.json 

这些是 gulp 的产生物, 不需要入版本.

生产环境下的部署

生产环境下, 每一次修改 assets 的话, 都需要执行此命令:

gulp build 

如果是使用 envoy 进行远程部署的话, 只需要添加多一个 task :

@task('assets:publish')     cd /var/www/phphub     git pull origin master     gulp build @endtask 

允许本地命令行下运行一条命令进行部署:

envoy run assets:publish

转载请注明:代码家园 » 使用Gulp来实现Laravel4的Assets管理

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)