目标
js模块打包sass编译雪碧图css js 自动添加MD5后缀css js 文件自动替换到htmlcss js html压缩文件变更后自动运行使用@@include() 加载公共html模块如: 头部 底部
代码
使用框架 插件
gulp-css-spriter 雪碧图gulp-minify-css css 压缩gulp-md5-plus避免浏览器读取了旧的缓存文件,需要为其添加md5戳gulp-file-include 文件插入gulp-uglify js压缩webpack-stream js打包gulp-rev 对文件名加MD5后缀gulp-rev-collector 路径替换gulp-concat 多个文件合并为一个gulp-cssmin css压缩gulp-watch gulp.watch不监听文件的新建和删除。所以一个更好一点的方案是用一个插件 gulp-watchgulp-plumber 防止出错推出文件监控gulp-utilgulp-minify-html html压缩gulp-lessgulp-sassgulp-htmlmin html压缩
gulp任务流程
js 打包合并 -> 压缩 -> 加MD5戳 -> 插入替换html的文件 -> 发送到目标目录css less编译 雪碧图 -> 加MD5戳 ->压缩 -> 插入替换html的文件 -> 发送到目标目录html 头部顶部加载 -> 压缩 -> 目标路径将图片拷贝到目标目录
代码gulpfile
const gulp =
require(
'gulp');
const clean =
require(
'gulp-clean');
const fileinclude =
require(
'gulp-file-include');
const rev =
require(
'gulp-rev');
const revReplace =
require(
'gulp-rev-replace');
const uglify =
require(
'gulp-uglify');
const cssmin =
require(
'gulp-cssmin');
const spriter =
require(
'gulp-css-spriter');
const plumber =
require(
'gulp-plumber');
const htmlmin =
require(
'gulp-htmlmin');
const sass =
require(
'gulp-sass');
const runSequence =
require(
'run-sequence');
const webpackStream =
require(
'webpack-stream');
const named =
require(
'vinyl-named');
const path =
require(
'path');
const config = {
'ENV':
'dev',
'public': path.resolve(__dirname,
'../public'),
'view': path.resolve(__dirname,
'../views')
};
const webpackConfig = {
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader:
'babel-loader',
query: {
presets: [
'es2015']
}
}
],
externals:[
'$',
'zepoto']
}
};
const tempdir = path.resolve(__dirname,
'temp');
gulp.task(
'clean',
function () {
return gulp.src([config.
public, config.view, tempdir])
.pipe(clean({force:
true}));
});
gulp.task(
'fileinclude',
function () {
return gulp.src([
'html/*.html'])
.pipe(plumber())
.pipe(fileinclude({
prefix:
'@@',
basepath:
'@file'
}))
.pipe(gulp.dest(config.view));
});
gulp.task(
'copy:img',
function () {
return gulp.src(
'img/**/*')
.pipe(gulp.dest(path.join(config.
public,
'img')));
});
gulp.task(
'build:css',
function () {
const timestamp = +
new Date();
return gulp.src([
'css/*.css',
'css/*.scss'])
.pipe(plumber())
.pipe(rev())
.pipe(sass().on(
'error', sass.logError))
.pipe(spriter({
includeMode:
'implicit',
spriteSheet: config.
public +
'/img/spritesheet' + timestamp +
'.png',
pathToSpriteSheetFromCSS:
'../img/spritesheet' + timestamp +
'.png'
}))
.pipe(cssmin())
.pipe(gulp.dest(path.join(config.
public,
'css')))
.pipe(rev.manifest())
.pipe(gulp.dest(path.join(tempdir,
'rev/css')));
});
gulp.task(
'build:js',
function () {
return gulp.src(
'js/*.js')
.pipe(plumber())
.pipe(named())
.pipe(webpackStream(webpackConfig))
.pipe(rev())
.pipe(uglify())
.pipe(gulp.dest(path.join(config.
public,
'js')))
.pipe(rev.manifest())
.pipe(gulp.dest(path.join(tempdir,
'rev/js')));
});
gulp.task(
"revreplace",
function () {
const manifest = gulp.src(path.join(tempdir,
'rev/**/rev-manifest.json'));
const revReplaceOptions = {
manifest: manifest,
replaceInExtensions: [
'.js',
'.css',
'.html',
'.scss'],
modifyUnreved: (filename) => {
if (filename.indexOf(
'.js') > -
1) {
return '../js/' + filename;
}
if (filename.indexOf(
'.scss') > -
1) {
return '../css/' + filename;
}
},
modifyReved: (filename) => {
if (filename.indexOf(
'.js') > -
1) {
return '/js/' + filename;
}
if (filename.indexOf(
'.css') > -
1) {
return '/css/' + filename;
}
}
};
return gulp.src(config.view +
'/*.html')
.pipe(revReplace(revReplaceOptions))
.pipe(htmlmin({collapseWhitespace:
true}))
.pipe(gulp.dest(config.view));
});
const watchFiles = [
'js/**/*.js',
'css/*.css',
'css/*.sass',
'css/**/*.scss',
'html/**/*.html'];
gulp.task(
'watch',
function () {
gulp.watch(watchFiles,
function (event) {
gulp.start(
'default',
function () {
console.log(
'File ' + event.path +
' was ' + event.type +
', build finished');
});
});
});
gulp.task(
'dev', [
'default',
'watch']);
gulp.task(
'default',
function (done) {
runSequence(
'clean',
[
'fileinclude',
'copy:img',
'build:css',
'build:js'],
'revreplace',
done);
});
注
构建工具 只是辅助我们开发生产用的 不要应为这些繁琐的框架 配置 ,增加了项目的复杂度 使用和维护的难度第三方库不打包,单独使用link javascript 因为可以使用第三方的cdn 所有页面都回加载一个网站主题css模块化CSS我们应该时刻明确,我们是为 了方便管理,方便修改,方便多人合作,而不是简单的分割。如果说有什么建议,我想,CSS的模块化,应该尽量与HTML的模块化相一致。这里的一致说的是,无论是在文件的分割上,还是在CSS内容的分割上,与HTML的模块化一致
gulp任务
串行方式运行任务,亦即,任务依赖
默认情况下,任务会以最大的并发数同时运行 – 也就是说,它会不做任何等待地将所有的任务同时开起来。如果你希望创建一个有特定顺序的串行的任务链,你需要做两件事:
给它一个提示,用以告知任务在什么时候完成,而后,再给一个提示,用以告知某任务需要依赖另一个任务的完成。
gulp 的任务运行不能很好的控制顺序 使用run-sequence
gulp文件监控
gulp运行任务出错时 就会退出程序不再监控 使用gulp-plumber 防止css js 出错时退出
监控js css html img
任务default是一个完整的流程 文件的拷贝 压缩 打包 等 监控时应根据不同的文件变更 执行相应任务 这样效率更佳 但是每个一个文件变更导致其它任务也应执行,还是执行完整任务来的简单且不易出错 效率不行的话 就换电脑
自动创建页面
每一个页面具有共性:都会有一个头部和底部 都有一个和页面名相同的css,js文件 都会加载一个网站的base.css,base.js等 使用一个nodejs 脚本来完成这些。
命令形式 node new
const readline =
require(
'readline');
const fs =
require(
"fs") ;
let pagename = null;
//创建readline接口实例
const rl = readline.createInterface({
input:process.stdin,
output:process.stdout
});
rl.question(
"页面名是什么?",
function(answer){
rl.close();
pagename = answer;
if(fs.existsSync(__dirname + `/html/${pagename}.html`)){
console.log(`页面${pagename}已经存在`);
process.exit(
0);
}
let basehtml=`<!DOCTYPE html>
<html>
<head>
<title>base page</title>
<meta charset=
"utf-8"/>
<meta name=
'description' content=
''>
<meta name=
"viewport" content=
"width=device-width, initial-scale=1"/>
<meta name=
"keywords" content=
""/>
<meta name=
"author" content=
"" />
<link rel=
"icon" href=
"/favicon.ico" type=
"image/x-icon"/>
<link href=
"//cdn.bootcss.com/ionicons/2.0.1/css/ionicons.min.css" rel=
"stylesheet">
<link rel=
"stylesheet" type=
"text/css" href=
"../css/base.scss">
<link rel=
"stylesheet" type=
"text/css" href=
"../css/${pagename}.scss">
</head>
<body>
@@include(
'./common/head.html')
<div class=
'container'>
</div>
@@include(
'./common/foot.html')
<script
type=
"text/javascript" src=
'../js/base.js'></script>
<script
type=
"text/javascript" src=
'../js/${pagename}.js'></script>
</body>
</html>`;
fs.writeFile(__dirname + `/html/${pagename}.html`, basehtml, {flag:
'a'},
function (err) {
if(err) {
console.
error(err);
}
else {
console.log(`创建${pagename}.html`);
}
});
fs.writeFile(__dirname + `/css/${pagename}.scss`,
'', {flag:
'a'},
function (err) {
if(err) {
console.
error(err);
}
else {
console.log(`创建${pagename}.scss`);
}
});
fs.writeFile(__dirname + `/js/${pagename}.js`,
'', {flag:
'a'},
function (err) {
if(err) {
console.
error(err);
}
else {
console.log(`创建${pagename}.js`);
}
});
});
发现的问题
使用gulp-minify-html 后,ejs语法的 “<%=aa %> ” 出错:<%= aa=”” %=”“>
解决
换成 gulp-htmlmin换成 gulp-rev-replace 并且在build任务中将rev(添加MD5) 执行步骤放在less(编译前面);保证了名字还是.less时加入到rev-mainfest.json. 添加配置项 modifyUnreved: (filename) => { if (filename.indexOf('.js') > -1) { return '../js/' + filename; } if (filename.indexOf('.less') > -1) { return '../css/' + filename; } }, modifyReved: (filename) => { return '/' + filename }