使用gulp实现前端自动化

目标

  • js模块打包
  • sass编译
  • 雪碧图
  • css js 自动添加MD5后缀
  • css js 文件自动替换到html
  • css js html压缩
  • 文件变更后自动运行
  • 使用@@include() 加载公共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',//dev or product
    'public': path.resolve(__dirname, '../public'),     //发布静态资源 css js img 路径
    'view': path.resolve(__dirname, '../views')         //发布'html路径'
};
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}));
});

//用于在html文件中直接include文件  并保存到目标路径
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')));
});

//css 压缩 文件名添加MD5
gulp.task('build:css', function () {
    const timestamp = +new Date();
    return gulp.src(['css/*.css', 'css/*.scss'])
        .pipe(plumber())
        .pipe(rev()) //添加MD5
        .pipe(sass().on('error', sass.logError))
        .pipe(spriter({
            includeMode: 'implicit',//explicit:默认不加入雪碧图,,implicit:默认加入雪碧图/* @meta {"spritesheet": {"include": true}} */
            spriteSheet: config.public + '/img/spritesheet' + timestamp + '.png',//img保存路径
            pathToSpriteSheetFromCSS: '../img/spritesheet' + timestamp + '.png'//在css文件中img的路径
        }))
        .pipe(cssmin()) //压缩
        .pipe(gulp.dest(path.join(config.public, 'css')))
        .pipe(rev.manifest())
        .pipe(gulp.dest(path.join(tempdir, 'rev/css')));
});

//js 打包 压缩 混淆 文件名添加MD5
gulp.task('build:js', function () {
    return gulp.src('js/*.js')
        .pipe(plumber())
        .pipe(named())
        .pipe(webpackStream(webpackConfig))
        .pipe(rev())  //添加MD5
        .pipe(uglify()) //压缩 混淆
        .pipe(gulp.dest(path.join(config.public, 'js')))
        .pipe(rev.manifest())
        .pipe(gulp.dest(path.join(tempdir, 'rev/js')));
});

// 将html的css js 引用路径 替换为  修改(增加MD5)后的路径   并压缩
gulp.task("revreplace", function () {
    const manifest = gulp.src(path.join(tempdir, 'rev/**/rev-manifest.json'));
    //noinspection JSUnusedGlobalSymbols
    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`);
      }
  });

});


发现的问题

  1. 使用gulp-minify-html 后,ejs语法的 “<%=aa %> ” 出错:<%= aa=”” %=”“>

解决

  1. 换成 gulp-htmlmin
  2. 换成 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
    }

猜你喜欢

转载自blog.csdn.net/blueblueuueew/article/details/53519319