/** * Yohobuy 构建脚本 * @author: xuqi<qi.xu@yoho.cn> * @date: 2016/4/25 */ 'use strict'; const path = require('path'); const gulp = require('gulp'); const gutil = require('gulp-util'); const ftp = require('gulp-ftp'); const os = require('os'); const postcss = require('gulp-postcss'); const sourcemaps = require('gulp-sourcemaps'); const cssnano = require('gulp-cssnano'); const scss = require('postcss-scss'); const webpack = require('webpack'); const WebpackDevServer = require('webpack-dev-server'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const UglifyJsParallelPlugin = require('webpack-uglify-parallel'); const webpackConfig = require('./webpack.config.js'); const env = { dev: Symbol('development'), pro: Symbol('production') }; const config = require('../package.json'); const ftpConfig = { host: '218.94.75.58', user: 'php', pass: 'yoho9646' }; const distRoot = `dist/${config.name}`; const dist = { js: `${distRoot}/${config.version}`, css: `${distRoot}/${config.version}`, assets: `${distRoot}/assets`, img: `${distRoot}/assets/img`, font: `${distRoot}/assets/font` }; /** * postcss plugins for both dev and pro * @parem et Symbol */ const postcssPlugin = (et) => { let sprites = { spritesmith: { padding: 8 }, filterBy(file) { // base64 的图片没有 url 过滤掉 if (file.url) { return Promise.resolve(); } return Promise.reject(); }, groupBy(file) { let group = file.url.split('/')[1]; let entry = path.basename(file.styleFilePath); file.retina = true; file.radio = 2; if (group) { group = entry + '.' + group; } return group ? Promise.resolve(group) : Promise.reject('yoho'); } }, assets, plugins; // assets & sprites config in both dev and pro if (et === env.pro) { assets = { loadPaths: [dist.img, dist.font], relativeTo: dist.css }; Object.assign(sprites, { basePath: dist.img, stylesheetPath: dist.css, spritePath: dist.img }); } else if (et === env.dev) { assets = { loadPaths: ['img/', 'font/'], relativeTo: 'css/' }; Object.assign(sprites, { basePath: 'img/', stylesheetPath: 'bundle/', spritePath: 'bundle/' }); } plugins = [ require('postcss-import')({ path: [path.join(__dirname, 'scss')], resolve(id) { let name = path.basename(id); if (!/^_/.test(name)) { id = path.dirname(id) + '/_' + name; } return id; } }), require('precss'), require('postcss-sprites').default(sprites), require('postcss-assets')(assets), require('postcss-calc'), require('postcss-pxtorem')({ rootValue: 40, unitPrecision: 5, // 保留5位小数字 minPixelValue: 2, // 小于 2 时,不转换 selectorBlackList: [], // 选择器黑名单,可以使用正则 propWhiteList: [] // 属性名称为空,表示替换所有属性的值 }), require('autoprefixer')({ browsers: ['> 1%'] }), // 可选 require('postcss-use')({ modules: ['postcss-clearfix', 'postcss-crip', 'postcss-short', 'postcss-center', 'postcss-position'] }) ]; if (et === env.pro) { plugins.push(require('postcss-cachebuster')({ imagesPath: `/${dist.img}`, cssPath: `/${dist.css}` })); } return plugins; }; // default gulp.task('default', ['postcss-dev', 'postcss-watch', 'webpack-dev-server']); // ge gulp.task('ge', ['postcss', 'webpack']); // dist gulp.task('dist', ['ge'], () => { const ftpstream = ftp(ftpConfig); return gulp.src('dist/**/') .pipe(ftpstream) .pipe(gutil.noop()); }); // postcss compile in dev gulp.task('postcss-dev', () => { return gulp.src(['scss/index.css', 'scss/common.css', 'scss/feature.css']) .pipe(sourcemaps.init()) .pipe(postcss(postcssPlugin(env.dev), { parser: require('postcss-scss') })) .pipe(sourcemaps.write('.')) .pipe(gulp.dest('bundle/')); }); // postcss file watch gulp.task('postcss-watch', () => { gulp.watch('scss/**/*.css', ['postcss-dev']); }); // copy assets gulp.task('assets', ['img', 'font']); // copy img gulp.task('img', () => { return gulp.src('img/**/*') .pipe(gulp.dest(dist.img)); }); // copy font gulp.task('font', () => { return gulp.src('font/**/*') .pipe(gulp.dest(dist.font)); }); // postcss compile in pro gulp.task('postcss', ['assets'], () => { return gulp.src(['scss/index.css', 'scss/common.css', 'scss/feature.css']) .pipe(postcss(postcssPlugin(env.pro), { parser: require('postcss-scss') })) .pipe(cssnano({ safe: true })) .pipe(gulp.dest(dist.css)); }); // webpack dev server gulp.task('webpack-dev-server', () => { const devConfig = Object.assign({}, webpackConfig, { devtool: '#inline-source-map', vue: { postcss: { plugins: postcssPlugin(env.dev), options: { parser: scss } }, autoprefixer: false, loaders: { css: ExtractTextPlugin.extract(['css?-url&sourceMap']) } }, postcss: { plugins: postcssPlugin(env.dev), options: { parser: scss } } }); devConfig.output.publicPath = 'http://localhost:5001/'; // 开发环境插件 devConfig.plugins.push( new ExtractTextPlugin('bundle/[name].css'), new webpack.HotModuleReplacementPlugin() ); devConfig.entry.libs.unshift(`webpack-dev-server/client?${devConfig.output.publicPath}`, 'webpack/hot/dev-server'); new WebpackDevServer(webpack(devConfig), { contentBase: '.', publicPath: devConfig.output.publicPath, hot: true, inline: true, quiet: true, clientLogLevel: 'error', compress: true, stats: { colors: true }, headers: { 'Access-Control-Allow-Origin': '*' } }).listen(5001, '0.0.0.0', (err) => { if (err) { throw new gutil.PluginError('webpack-dev-server', err); } gutil.log('[webpack-serve]', devConfig.output.publicPath); }); }); // webpack compile in pro gulp.task('webpack', ['assets'], (done) => { const proConfig = Object.assign({}, webpackConfig, { vue: { postcss: { plugins: postcssPlugin(env.pro), options: { parser: scss } }, autoprefixer: false, loaders: { css: ExtractTextPlugin.extract(['css?-url']) } }, postcss: { plugins: postcssPlugin(env.pro), options: { parser: scss } } }); proConfig.output.path = dist.js; // 生产环境插件 proConfig.plugins.push( new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new UglifyJsParallelPlugin({ workers: os.cpus().length }) ); webpack(proConfig, (err, stats) => { if (err) { throw new gutil.PluginError('webpack', err); } gutil.log('[webpack compile]:', stats.endTime - stats.startTime, 'ms'); done(); }); });