最近研究了下工做流,先说一下我司的状况,我司如今是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执行的状况,有条件的,仍是弄个开发机来调试比较好。