gulp动态生成html内的css、js版本号

一、功能(解放生产力,提高团队开发效率):

1、通过gulp命令行方式动态切换环境变量的值;

2、自动给html引入的css,js文件批量添加版本号;

 

二、操作流程:

该流程基于npm命令安装包,假设你的电脑环境已经安装了node环境。

1、切换到项目所在根目录,执行npm init 生成package.json文件;

2、执行  npm install -g gulp@3.9.1  全局安装gulp;

3、依次执行

npm install --save-dev gulp-rev
npm install --save-dev gulp-rev-collector
npm install --save-dev run-sequence
npm install --save-dev minimist

4、在根目录下创建gulpfile.js文件,该文件主要用于指定要执行什么任务以达到我们想要的效果;(具体逻辑参考下面的gulpfile.js)

 

5、执行gulp --env test --dir demo(--env【必填】 后面的参数表示要切换到哪个环境,--dir demo【非必填】后面的参数表示要以哪个目录下的同名文件为准);

<link rel="stylesheet" href="../css/default-803a7fe4ae.css">
<script src="../js/app-3a0d844594.js"></script>

很显然这不是我们需要的效果;

修改插件配置,因插件版本更新,更改的行数可能会略有差异

1、路径 node_modules/gulp-rev/index.js

第135行 manifest[originalFile] = revisionedFile;

更改为 manifest[originalFile] = originalFile + '?v=' + file.revHash;

2、路径 node_modules/gulp-rev-collector/index.js

第40行 var cleanReplacement = path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' );

更改为 var cleanReplacement=path.basename(json[key]).split('?')[0];

第173行 regexp: new RegExp( prefixDelim + pattern, 'g' ),

更改为 regexp: new RegExp( prefixDelim + pattern+'(\\?v=\\w{10})?', 'g' ),

3、路径 node_modules/rev-path/index.js

第9行 return modifyFilename(pth, (filename, ext) => `${filename}-${hash}${ext}`);

更改为 return modifyFilename(pth, (filename, ext) => `${filename}${ext}`);

6、操作实例:

纵向文件夹顺序:a ->b
a/css/index.css
b/css/index.css
--------------------
操作1:修改a/css/index.css文件后,执行 gulp --test 。
结果:a/css/index.html的引入a/css/index.css文件版本号不变。
------------------------------
操作2:修改a/css/index.css文件后,执行 gulp --test --dir a 。
结果:a、b文件下引用的index.css版本号都同步改变。


7、参考文档:https://www.jianshu.com/p/2e554161b930

 

 

 

 

 

gulpfile.js

//引入gulp和gulp插件,

var gulp = require('gulp'),

    runSequence = require('run-sequence'),

    rev = require('gulp-rev'),

    revCollector = require('gulp-rev-collector');

    minimist = require('minimist')

const fs = require('fs');

const path = require('path');

var env = ""; //环境变量
var dir = ""; //这个参数表示当不同目录下存在同名的js或者css(比如carnival/css/index.css,womensDay/css/index.css)文件时,最终以哪个目录下的为准;
var allDirs = getAllDirs(); // 获取当前所有的目录
var envs = ["dev", "test", "pre", "release"]; //对应的各个环境变量的值 (从env.js文件获取)

// 接受命令行参数
var knownOptions = {
    string: 'env,dir', // 接收的命令行参数
    default: { env: "release", dir: allDirs }
};
var options = minimist(process.argv.slice(2), knownOptions);
env = options.env;
//  由于活动目录下的js或者css文件夹下的某些js,css文件会有同名冲突,所以加了一个dir参数来表示以哪个为准;
//  (例如,carnival/css/index.css,跟womensDay/css/index.css,在构建的时候最终以womensDay[按遍历顺序,最后push进数组]的为准,这时候你修改carnival/css/index.css这个文件,
// 之后进行构建,是不生效的,这个时候我们可以指定以carnival为准,那么修改carnival/css/index.css这个文件后重新构建是可以生效的)
dir = options.dir;
if (process.argv.indexOf("--env") < 0 || process.argv.indexOf("--env") > 0 && process.argv.length < 4) {
    return console.error("请输入环境变量,例如:gulp --env test");
}
if (process.argv.indexOf("--dir") > 0 && process.argv.length < 6) {
    return console.error("请正确的目录参数名,例如:gulp --dir demo");
}
if (envs.indexOf(env) < 0) {
    return console.error("环境变量值不存在,请输入正确的环境变量的值!");
}
if (dir) {
    if (typeof dir == "string") {
        if (allDirs.indexOf(dir) >= 0) {
            allDirs.splice(allDirs.indexOf(dir), 1)
            allDirs.push(dir)
        } else {
            return console.error("目录名不存在,请输入正确的目录名");
        }
    }
}
var fileData = "";
// 读取env.js文件,动态修改env变量(这个修改方式只适用于环境变量那行只有类似这段文本var env ="test",否则的话就按照你的算法自己处理它,修改下面的方法就可以了)
fs.readFile('js/env.js', function (err, data) {
    if (err) {
        return console.error(err);
    }
    var dataStr = data.toString();
    dataStr.trim().split('\n').forEach(function (v, i) {
        if (/varenv=/.test(v.replace(/\s*/g,""))) {// 这里切换环境变量的值,先去除所有空格,再进行正则表达式的比较
            fileData += 'var env = "' + env + '";' + "\n"
        } else {
            fileData += v + "\n";
        }
    })
    // 将文本内容重新写入env.js
    fs.writeFile('js/env.js', fileData, (err) => {
        if (err) throw err;
    });
})

function getAllDirs(mypath = '.') {
    var excluedeDirs = [".vscode", "js", "css", "node_modules", "rev"] //排除的文件夹(只保留每个活动目录对应的名字,这些文件夹下对应的html文件里的js,css才需要动态修改版本号)

    const items = fs.readdirSync(mypath);

    let result = [];

    // 遍历当前目录中所有的文件和文件夹

    items.map(item => {

        let temp = path.join(mypath, item);
        // 若当前的为文件夹

        if (fs.statSync(temp).isDirectory()) {
            if (excluedeDirs.indexOf(item) < 0) {
                result.push(item); // 存储当前文件夹的名字
            }

        }

    });
    return result;
}

var revHtmls = [];
//定义css、js源文件路径
var cssSrc = ['css/*.css'];
var jsSrc = ['js/*.js'];
allDirs.forEach(function (item, index) {
    //Html替换css、js文件版本
    gulp.task('revHtml' + (index + 1), function () {

        return gulp.src(['rev/**/*.json', item + '/*.html']) // 这里的View/*.html是项目html文件路径,如果gulpfile.js和html文件同在一级目录下,修改为return gulp.src(['rev/**/*.json', '*.html']);

            .pipe(revCollector())

            .pipe(gulp.dest(item));// 注意这里是生成的新的html文件,如果设置为你的项目html文件所在文件夹,会覆盖旧的html文件,若上面的View/*.html修改了,这里也要相应修改,如果gulpfile.js和html文件同在一级目录下,修改为  .pipe(gulp.dest(''));

    });
    revHtmls.push('revHtml' + (index + 1))
    cssSrc.push(item + '/css/*.css')
    jsSrc.push(item + '/js/*.js')
})
// //清空目标文件
// gulp.task('cleanDst', function () {
//     return gulp.src(['rev'], { read: false })
//         .pipe(clean());
// });

// //检查js语法
// gulp.task('jslint', function () {
//     return gulp.src(jsSrc)
//         .pipe(jshint())
//         .pipe(jshint.reporter('default'));
// });

//CSS生成文件hash编码并生成 rev-manifest.json文件名对照映射

gulp.task('revCss', function () {

    return gulp.src(cssSrc)

        .pipe(rev())

        .pipe(rev.manifest())

        .pipe(gulp.dest('rev/css'));

});

//js生成文件hash编码并生成 rev-manifest.json文件名对照映射

gulp.task('revJs', function () {

    return gulp.src(jsSrc)

        .pipe(rev())

        .pipe(rev.manifest())

        .pipe(gulp.dest('rev/js'));

});


//开发构建
gulp.task('default', function (done) {
    condition = false;
    runSequence(['revCss'],  //需要说明的是,用gulp.run也可以实现以上所有任务的执行,只是gulp.run是最大限度的并行执行这些任务,而在添加版本号时需要串行执行(顺序执行)这些任务,故使用了runSequence.
        ['revJs'], revHtmls, done)

});

 

上一篇:前端构建的初步尝试


下一篇:nodejs sftp上传