// gulp依赖
|
var gulp = require('gulp'),
|
// 生成css,js map图
|
sourcemaps = require('gulp-sourcemaps'),
|
// 错误处理
|
plumber = require('gulp-plumber'),
|
// html压缩
|
htmlmin = require('gulp-htmlmin'),
|
// 图片压缩
|
imagemin = require('gulp-imagemin'),
|
// CSS编译
|
sass = require('gulp-sass'),
|
minifycss = require('gulp-clean-css'),
|
autoprefixer = require('gulp-autoprefixer'),
|
// 脚本压缩
|
uglify = require('gulp-uglify'),
|
// 静态服务器
|
connect = require('gulp-connect'),
|
// 跨域代理
|
proxy = require('http-proxy-middleware'),
|
// ES6 转ES5
|
babel = require('gulp-babel'),
|
// 读写保存配置
|
fs = require("fs-extra"),
|
// 配合fs
|
path = require("path"),
|
// 配合watch增删改
|
watch = require('gulp-watch'),
|
// 配合watch增删改
|
batch = require('gulp-batch'),
|
// 任务同步并行
|
sequence = require('gulp-sequence'),
|
// 只修改改动的文件
|
changed = require('gulp-changed'),
|
// 生成样式脚本?的引入
|
md5 = require('gulp-md5-assets'),
|
// 删除文件
|
del = require('del');
|
|
// 加入二维码
|
var qrcode = require('qrcode-terminal');
|
// 用于获取本机信息
|
var os = require('os');
|
var ip = getNetwork().ip || "localhost";
|
|
var package = require('./package.json');
|
// 同步刷新
|
var browserSync = require('browser-sync').create();
|
var reload = browserSync.reload;
|
|
// 获取package的项目配置
|
var configName = package['projects'] && package['projects'][process.env.NODE_ENV] || 'app.json';
|
|
var app = require("./" + configName),
|
// 编译服务配置
|
distServer = app.distServer || {},
|
// 开发服务配置
|
devServer = app.devServer || {},
|
// 实时刷新,仅在开发模式
|
isDevLivereload = devServer.livereload == false ? false : true,
|
// 实时刷新,仅在编译模式
|
isDistLivereload = distServer.livereload == false ? false : true,
|
// 源文件目录
|
sourcePath = process.env.NODE_ENV ? process.env.NODE_ENV + '/src' : 'src',
|
// 源文件目录
|
sourceBuild = process.env.NODE_ENV ? process.env.NODE_ENV + '/dist' : 'dist';
|
|
// 配置编译的服务
|
var config = {
|
source: {
|
// 源文件目录
|
root: sourcePath,
|
// 源文件样式目录
|
css: [sourcePath + "/css/**/*.css"],
|
// style.css 源文件目录
|
scss: [sourcePath + '/scss/**/*.scss'],
|
// 源文件图片目录
|
images: [sourcePath + '/**/*.{png,jpg,gif,ico}'],
|
},
|
// 编译的输出路径
|
build: sourceBuild,
|
// 输出配置
|
output: {
|
// 输出的根目录
|
root: sourceBuild,
|
// 输出的样式目录
|
css: sourceBuild + '/css',
|
images: sourceBuild + '/'
|
},
|
watcher: {
|
rootRule: sourcePath + '/**',
|
moveRule: [sourcePath + '/**', '!**/*.{html,css,scss,less,md,png,jpg,gif,ico}', '!' + sourcePath + '/scss'],
|
jsRule: [sourcePath + '/**/*.js', '!' + sourcePath + '/js/bui.js', '!' + sourcePath + '/js/zepto.js', '!' + sourcePath + '/js/platform/**/*.js', '!' + sourcePath + '/js/plugins/**/*.js', '!' + sourcePath + '/**/*.min.js'],
|
htmlRule: [sourcePath + '/**/*.html'],
|
}
|
}
|
|
// 增加用户配置的忽略文件
|
if ("ignored" in app) {
|
config.source.scss = config.source.scss.concat(app.ignored);
|
config.source.css = config.source.css.concat(app.ignored);
|
config.source.images = config.source.images.concat(app.ignored);
|
config.watcher.moveRule = config.watcher.moveRule.concat(app.ignored);
|
config.watcher.jsRule = config.watcher.jsRule.concat(app.ignored);
|
config.watcher.htmlRule = config.watcher.htmlRule.concat(app.ignored);
|
}
|
|
// 获取本机IP
|
function getNetwork() {
|
let iptable = {},
|
ifaces = os.networkInterfaces();
|
|
for (let dev in ifaces) {
|
ifaces[dev].forEach(function(details, alias) {
|
if (details.family == 'IPv4') {
|
iptable[dev + (alias ? ':' + alias : '')] = details.address;
|
iptable["ip"] = details.address;
|
}
|
});
|
}
|
|
return iptable;
|
}
|
|
// 获取随机端口
|
function getRandomPort() {
|
let random = Math.random() * 10000 + 1000;
|
let randomPort = parseInt(random);
|
|
return randomPort;
|
}
|
|
// 获取端口并写入配置
|
function getServerPort() {
|
|
// 开发版运行端口
|
let devPort = getRandomPort();
|
// 编译版运行端口
|
let distPort = devPort + 2;
|
// 写入端口
|
if (!devServer.port) {
|
app.devServer.port = devPort;
|
fs.writeFileSync(path.resolve(configName), JSON.stringify(app, null, 2));
|
}
|
if (!distServer.port) {
|
app.distServer.port = distPort;
|
fs.writeFileSync(path.resolve(configName), JSON.stringify(app, null, 2));
|
}
|
|
return {
|
devPort: app.devServer.port,
|
distPort: app.distServer.port
|
}
|
}
|
|
|
// 清空文件,在最后构建的时候才加入这部
|
gulp.task('clean-dist', cb => {
|
return del([sourceBuild + '/**/*'], cb);
|
});
|
|
// sass 初始化的时候编译, 并生成sourcemap 便于调试
|
gulp.task('scss', function() {
|
|
return gulp.src(config.source.scss)
|
.pipe(changed(sourceBuild + '/css/'))
|
// 生成css对应的sourcemap
|
.pipe(sourcemaps.init())
|
.pipe(sass(app.sass).on('error', sass.logError))
|
.pipe(autoprefixer(app.autoprefixer))
|
.pipe(sourcemaps.write('./'))
|
.pipe(gulp.dest(sourceBuild + "/css"))
|
.pipe(gulp.dest(sourcePath + "/css"))
|
});
|
// sass 编译成压缩版本
|
gulp.task('scss-build', function() {
|
return gulp.src(config.source.scss)
|
.pipe(sass(app.sass).on('error', sass.logError))
|
.pipe(autoprefixer(app.autoprefixer))
|
.pipe(gulp.dest(sourceBuild + "/css"))
|
.pipe(gulp.dest(sourcePath + "/css"))
|
.pipe(minifycss(app.cleanCss))
|
.pipe(reload({ stream: true }));
|
});
|
// css 编译
|
gulp.task('css', function() {
|
// 编译style.scss文件
|
return gulp.src(config.source.css)
|
.pipe(changed(sourceBuild + '/css/'))
|
.pipe(gulp.dest(config.output.css))
|
// .pipe(md5(10, sourceBuild+"/**/*.html"))
|
// .pipe(reload({stream: true}));
|
})
|
|
// 改变的时候才执行压缩
|
gulp.task('css-minify', function() {
|
// 编译style.scss文件
|
return gulp.src(config.source.css)
|
// .pipe(changed(sourceBuild + '/css/'))
|
.pipe(minifycss(app.cleanCss))
|
.pipe(gulp.dest(config.output.css))
|
})
|
|
// 处理完JS文件后返回流
|
gulp.task('js-babel', function() {
|
|
return gulp.src(config.watcher.jsRule)
|
// error end task
|
.pipe(plumber({
|
errorHandler: function(error) {
|
console.log(error)
|
this.emit('end');
|
}
|
}))
|
// translate es5
|
.pipe(babel(app.babel))
|
.pipe(gulp.dest(config.output.root))
|
});
|
// 脚本 编译
|
gulp.task('js-minify', function() {
|
return gulp.src(config.watcher.jsRule)
|
// .pipe(changed(config.output.root))
|
// error end task
|
.pipe(plumber({
|
errorHandler: function(error) {
|
console.log(error)
|
this.emit('end');
|
}
|
}))
|
.pipe(babel(app.babel))
|
.pipe(uglify(app.uglify))
|
.pipe(gulp.dest(config.output.root))
|
.pipe(md5(10, sourceBuild + '/**/*.html'));
|
});
|
|
|
// 把bui需要的文件移动过去
|
gulp.task('move-bui', function() {
|
|
gulp.src([sourcePath + '/css/bui.css'])
|
.pipe(gulp.dest(sourceBuild + '/css/'))
|
gulp.src([sourcePath + '/js/bui.js'])
|
.pipe(gulp.dest(sourceBuild + '/js/'))
|
gulp.src([sourcePath + '/js/platform/*.js'])
|
.pipe(gulp.dest(sourceBuild + '/js/platform/'))
|
});
|
// move all file except pages/js/** .sass .md
|
gulp.task('move', function() {
|
return gulp.src(config.watcher.moveRule)
|
.pipe(changed(config.watcher.rootRule))
|
.pipe(gulp.dest(config.output.root));
|
});
|
|
// compress html
|
gulp.task('html', function() {
|
var options = app.htmlmin;
|
return gulp.src(config.watcher.htmlRule)
|
.pipe(changed(sourceBuild))
|
.pipe(plumber())
|
.pipe(htmlmin(options))
|
.pipe(gulp.dest(sourceBuild))
|
// .pipe(md5(10))
|
// .pipe(reload({stream: true}))
|
});
|
|
// compress image
|
gulp.task('images', function() {
|
// 有大图会很慢,默认不开启
|
if (app.imagemin) {
|
return gulp.src(config.source.images)
|
.pipe(changed(config.output.images))
|
.pipe(imagemin(app.imagemin))
|
.pipe(gulp.dest(config.output.images));
|
} else {
|
return gulp.src(config.source.images)
|
.pipe(changed(config.output.images))
|
.pipe(gulp.dest(config.output.images));
|
}
|
});
|
|
|
// 同步服务
|
gulp.task('server-sync', ['server-build'], function() {
|
var portObj = getServerPort();
|
|
let proxys = [];
|
if ("proxy" in app) {
|
let proxyObj = app["proxy"];
|
let keys = Object.keys(proxyObj);
|
|
keys.forEach(function(item, i) {
|
let proxyItem = proxy(item, proxyObj[item])
|
proxys.push(proxyItem);
|
})
|
}
|
|
// 起一个同步服务
|
browserSync.init({
|
ui: {
|
port: portObj.distPort + 1
|
},
|
server: {
|
baseDir: sourceBuild,
|
middleware: proxys
|
},
|
port: portObj.distPort,
|
ghostMode: false,
|
notify: false,
|
codeSync: isDistLivereload,
|
// plugins: ['bs-console-qrcode']
|
});
|
|
// 插入二维码,手机扫码调试
|
var qrurl = "http://" + ip + ":" + portObj.distPort + app.qrcode;
|
|
qrcode.generate(qrurl, { small: true });
|
console.log("手机扫码预览效果");
|
|
// 新增删除由插件负责
|
watch(config.watcher.rootRule)
|
.on('add', addFile)
|
.on('change', changeFile)
|
.on('unlink', function(file) {
|
//删除文件
|
let distFile = './' + sourceBuild + '/' + path.relative('./' + sourcePath, file); //计算相对路径
|
fs.existsSync(distFile) && fs.unlink(distFile);
|
console.warn(file, "deleted")
|
});
|
|
|
});
|
|
// 起一个src目录的server
|
gulp.task('server', function() {
|
var portObj = getServerPort();
|
|
let proxys = [];
|
if ("proxy" in app) {
|
let proxyObj = app["proxy"];
|
let keys = Object.keys(proxyObj);
|
|
keys.forEach(function(item, i) {
|
let proxyItem = proxy(item, proxyObj[item])
|
proxys.push(proxyItem);
|
})
|
}
|
|
// 起一个同步服务
|
browserSync.init({
|
ui: {
|
port: portObj.devPort + 1
|
},
|
server: {
|
baseDir: sourcePath,
|
middleware: proxys
|
},
|
port: portObj.devPort,
|
ghostMode: false,
|
codeSync: isDevLivereload
|
});
|
|
// 插入二维码,手机扫码调试
|
var qrurl = "http://" + ip + ":" + portObj.devPort + app.qrcode;
|
qrcode.generate(qrurl, { small: true });
|
|
});
|
|
// 监测新增
|
function addFile(file) {
|
console.log(file, "added");
|
gulp.src(file, { base: './' + sourcePath }) //指定这个文件
|
.pipe(gulp.dest('./' + sourceBuild))
|
|
|
}
|
// 监测新增
|
|
function changeFile(file) {
|
console.info(file, "changed");
|
|
let isJs = file.lastIndexOf(".js") > -1;
|
let isHtml = file.lastIndexOf(".html") > -1;
|
let isScss = file.lastIndexOf(".scss") > -1;
|
let isCss = file.lastIndexOf(".css") > -1;
|
|
if (isJs) {
|
gulp.src(file, { base: './' + sourcePath }) //指定这个文件
|
.pipe(plumber({
|
errorHandler: function(error) {
|
console.log(error)
|
this.emit('end');
|
}
|
}))
|
// translate es5
|
.pipe(babel(app.babel))
|
.pipe(gulp.dest('./' + sourceBuild))
|
.pipe(reload({ stream: true }))
|
.pipe(md5(10, sourceBuild + '/**/*.html'))
|
} else if (isScss) {
|
|
gulp.src(config.source.scss)
|
.pipe(changed(sourceBuild + '/css/'))
|
// 生成css对应的sourcemap
|
.pipe(sourcemaps.init())
|
.pipe(sass(app.sass).on('error', sass.logError))
|
.pipe(autoprefixer(app.autoprefixer))
|
.pipe(sourcemaps.write('./'))
|
.pipe(gulp.dest(sourceBuild + "/css"))
|
.pipe(gulp.dest(sourcePath + "/css"))
|
.pipe(reload({ stream: true }));
|
|
} else if (isHtml) {
|
|
gulp.src(file, { base: './' + sourcePath })
|
.pipe(plumber())
|
.pipe(htmlmin(app.htmlmin))
|
.pipe(gulp.dest('./' + sourceBuild))
|
.pipe(md5(10))
|
.pipe(reload({ stream: true }))
|
} else if (isCss) {
|
|
gulp.src(file, { base: './' + sourcePath })
|
.pipe(gulp.dest('./' + sourceBuild))
|
.pipe(md5(10, sourceBuild + "/**/*.html"))
|
.pipe(reload({ stream: true }))
|
} else {
|
gulp.src(file, { base: './' + sourcePath })
|
.pipe(gulp.dest('./' + sourceBuild))
|
.pipe(reload({ stream: true }))
|
}
|
|
}
|
|
|
// 编译任务以后,缺省任务的服务才能跑起来
|
gulp.task('build', sequence('clean-dist', 'move', 'move-bui', ['html'], ['css-minify'], ['images', 'scss-build'], ['js-minify']));
|
|
// 先编译再起服务,不需要每次都清除文件夹的内容 如果有scss目录,会在最后才生成, 如果没有,则以src/css/style.css 作为主要样式
|
gulp.task('server-build', sequence('move', 'move-bui', ['html'], ['css'], ['images', 'scss'], ['js-babel']));
|
|
// 注册缺省任务,启动服务,并且监听文件修改并且编译过去
|
gulp.task('dev', ['server-sync']);
|
|
gulp.task('default', ['dev']);
|