最近研究了下工做流,先說一下我司的狀況,我司如今是pc端用php直出,h5用vuejs構建,vuejs部分就不進行描述了,由於網上的構建方法都是很成熟的了。
如下是php直出,須要向後臺同窗提供html文件的構建方法。調試都是在本地調試的,調試完成後打包生成html交付給後臺同窗。javascript
http-server 模擬數據,調試ajaxphp
webpack 打包js,模塊化管理css
gulp打包css,壓縮css, 壓縮圖片html
|- apps //html文件 |- dist |- css //存放壓縮打包後的css |- js //webpack 自動打包的js |- images //壓縮後的圖片 //這裏還有打包後的html文件 |- mock //模擬數據,json |- ssi //生成的ssi頁面片 |- js //js源文件 |- common 公共模塊 |- 業務js |- css |- sass //sass源文件 |- common 公共sass函數 |- 業務css |- stylesheets //編譯後的css 開發時引入 compass編譯 |- images 原圖片
由於rev默認生成的版本號是加在靜態文件文件名上的,如main-d3id7340.js這樣會形成服務器上有n多的js,因此咱們但願生成main.js?v=233333這樣的版本號,在配合ssi就能很好的維護,之後若是隻涉及修改靜態文件的時候,就只用從新上傳靜態文件和ssi頁面片就能夠了,不須要再去改php中的引用,因此在網上找到了一個方法。vue
打開node_modulesgulp-revindex.jsjava
第133行 manifest[originalFile] = revisionedFile; 更新爲: manifest[originalFile] = originalFile + '?v=' + file.revHash;
打開nodemodulesgulp-revnodemodulesrev-pathindex.jsnode
10行 return filename + '-' + hash + ext; 更新爲: return filename + ext;
打開node_modulesgulp-rev-collectorindex.jsjquery
31行 if ( path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' ) !== path.basename(key) ) { 更新爲: if ( path.basename(json[key]).split('?')[0] !== path.basename(key) ) {
gulpfile.js以下webpack
var gulp = require('gulp'); var minicss = require('gulp-cssmin'); var useref = require('gulp-useref'); var imagemin = require('gulp-imagemin'); var pngquant = require('imagemin-pngquant'); var gulpif = require('gulp-if'); var yargs = require('yargs'); var rev = require("gulp-rev"); var revCollector = require("gulp-rev-collector"); var replace = require("gulp-replace"); var runSequence = require('run-sequence'); var output = "dist"; //獲取輸入的參數 var argv = yargs.argv, name = argv.name, type; if(argv.type == "pub"){ type = ""; }else if(argv.type == "test"){ type = ".test" } //合併html裏用到的css gulp.task('csscombine',function(){ return gulp.src('apps/'+name+'/*') .pipe(useref()) .pipe(gulpif('*.css', minicss())) .pipe(gulp.dest("dist")); }); //壓縮css,生成css版本號 gulp.task('css', function(){ return gulp.src('dist/css/'+name+'/*.css') .pipe(rev()) .pipe(gulp.dest('dist/css/'+name)) .pipe( rev.manifest() ) .pipe( gulp.dest( 'rev/css' ) ); }); //生成js版本號 gulp.task('js', function(){ return gulp.src('dist/js/'+name+'/*.js') .pipe(rev()) .pipe(gulp.dest('dist/js/'+name)) .pipe( rev.manifest() ) .pipe( gulp.dest( 'rev/js' ) ); }); //壓縮圖片 gulp.task("imagemin", function(){ return gulp.src('images/'+name+'/*') .pipe(imagemin({ progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()] })) .pipe(gulp.dest(output + '/images/'+name)); }) //生成cssi頁面片 gulp.task("cssi",function(){ return gulp.src(['rev/**/*.json','ssi/cssi/cssi.html']) .pipe(replace('{name}',name)) .pipe(replace('{type}',type)) .pipe( revCollector()) .pipe(gulp.dest("ssi/cssi/"+name)); }); //生成jsi頁面片 gulp.task("jsi", function(){ return gulp.src(['rev/**/*.json','ssi/jsi/jsi.html']) .pipe(replace('{name}',name)) .pipe(replace('{type}',type)) .pipe( revCollector()) .pipe(gulp.dest("ssi/jsi/"+name)); }); //替換html裏的路徑 gulp.task("replacehtml",function(){ var scriptReg = new RegExp("<script src.+"+name+".+script>","g"); var scriptResult = '<!--#include virtual="/ssi/jsi/'+name+'/jsi.html" -->'; var cssReg = new RegExp("<link .+ href=.+"+name+".+>","g"); var cssResult = '<!--#include virtual="/ssi/cssi/'+name+'/cssi.html" -->'; return gulp.src('dist/'+name+'.html') .pipe(replace(scriptReg,scriptResult)) .pipe(replace(cssReg,cssResult)) .pipe(replace('../../images/'+name+'/','//assets'+type+'.cm233.com/dist/images/'+name+'/')) .pipe(gulp.dest("dist")) }); //主函數,打包 gulp.task('package', function() { if(!argv.name){ console.log("請輸入打包項目"); return ; } if(!argv.type){ console.log("請輸入打包類型! pub-發佈 test-測試"); return ; } runSequence('csscombine', ['css','js','imagemin'], ['cssi','jsi'], 'replacehtml', function(){ console.log("打包成功") }); });
與網上一些不一樣的是,這個要求開發者輸入參數name和type,這樣每次打包的時候就不用把整個項目都打包了,只打包須要打包的項目。nginx
合併css部分,須要在html裏作下處理
<!-- build:css css/cm_share_h5/cm_share_h5.css --> <link type="text/css" rel="stylesheet" href="../../css/stylesheets/main.css"> <link type="text/css" rel="stylesheet" href="../../css/stylesheets/detail.css"> <!-- endbuild -->
生成ssi部分,要先建立模板文件,根據壓縮css和js時生成的版本號,把相應的名字和版本號替換掉,而後在html裏把引用腳本的路徑改成ssi引用便可
<link rel="stylesheet" href="//assets{type}.ganother.com/dist/css/{name}/{name}.css">
webpack.config.js,僅用於處理js模塊依賴
var webpack = require('webpack'); var fs = require('fs'); var path = require("path"); var srcDir = './' function getEntry() { var jsPath = path.resolve(srcDir, 'js/page'); var dirs = fs.readdirSync(jsPath); var matchs = [], files = {}; dirs.forEach(function (item) { matchs = item.match(/(.+)\.js$/); if (matchs) { files[matchs[1]] = path.resolve(srcDir, 'js/page', item); } }); return files; } module.exports = { devtool: "source-map", //生成sourcemap,便於開發調試 entry: getEntry(), //獲取項目入口js文件 output: { path: path.join(__dirname, "dist/js"), //文件輸出目錄 // publicPath: path.join("dist/js/"), //用於配置文件發佈路徑,如CDN或本地服務器 filename: "[name]/[name].js", //根據入口文件輸出的對應多個文件名 }, module: { //各類加載器,即讓各類文件格式可用require引用 loaders: [ { test: /\.js$/, loader: "babel"}, ] }, resolve: { //配置別名,在項目中可縮減引用路徑 alias: { jquery: path.resolve(srcDir, "dist/js/lib/jquery-1.12.4.min.js"), module: path.resolve(srcDir, "js/module") } }, externals: { // require("jquery") is external and available // on the global var jQuery "jquery": "jQuery" }, plugins: [ //js文件的壓縮 new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] };
http-server能夠用項目目錄生成的url模擬ajax請求(只有get),直接把json放在裏面,而後根據項目目錄的url就能夠訪問。可是交付的時候要記得換掉url,其實也能夠自動化一下,要與後臺約定好目錄結構,而後打包的時候用gulp替換。
在思考工做流的時候,思考最多的就是如何在php直出而且由後端同事寫模版文件的狀況下作好交付html和後期脫離後端同事進行靜態文件維護,好像除了用nginx ssi沒什麼其餘好辦法再不改模版文件的狀況下更換靜態文件(由於要加時間戳防止緩存)。本地調試仍是有不少不科學的地方,好比模擬數據這裏,可能更換成真實接口的數據會出現其它的意外狀況,填充模版後也可能會出現影響js執行的狀況,有條件的,仍是弄個開發機來調試比較好。