zoukankan      html  css  js  c++  java
  • 前端客户端自动构建

    构建原因

    • 规范代码所有代码构建前均会先进行规范审核,根据不同语言预设判断。
    • 提高效率将需要重复输入的有规律的设置,用自动化的方式添加。
    • 避免疏忽把默认需要操作的动作用程序代替,避免人为疏忽。
    • 提高性能把开发时的易于编辑的源码转化为访问时性能较高的结果。
    • 减少重复将重复调用的内容用程序的方式生成结果,避免访问负荷。
    • 板块化按板块开发,生成整体页面,用组装的方式实现。

    构建内容

    • 脚本*.js --> *.js, *.min.js, map/js.json
    • 样式*.css --> *.less, *.min.css, map/css.json
    • 模板views/.json --> views/.hbs, views/*.min.hbs, map/html.json
    • 图片*.[png|jpg|gif|svg|ico] --> *.[png|jpg|gif|svg|ico], map/img.json
    • 字体font/.[eot|ttf|woff|woff2|svg] --> font/.[eot|ttf|woff|woff2|svg]
    • 第三方bower.json --> bower.json, bower_components/*

    构建配置

    • 安装全局命令
    npm install gulp-cli -g
    npm install bower -g
    
    • 安装构建依赖
    cd node-m/static/auto
    npm install --no-save // 安装但不更新 package.json 和 package-lock.json 
    "bower": "^1.7.9",
    "browser-sync": "^2.11.0",
    "del": "^2.2.0",
    "gulp": "^3.9.0",
    "gulp-changed": "^1.3.0", // 用于判断文件是否更新
    "gulp-clean-css": "^2.0.9",
    "gulp-csslint": "^0.3.1",
    "gulp-eslint": "^4.0.0", // 更新至 4.0.0
    "gulp-hasher": "^0.1.0", // 生成文件 md5
    "gulp-htmllint": "0.0.11",
    "gulp-htmlmin": "^1.2.0",
    "gulp-include": "^2.0.2",
    "gulp-less": "^3.0.1",
    "gulp-lintspaces": "^0.4.1",
    "gulp-rename": "^1.2.2", // 更改后缀/增加前缀
    "gulp-uglify": "^1.4.1",
    "gulp-util": "^3.0.7", // 主要用于输出错误信息
    "gulp-watch": "^4.3.6",
    "htmllint": "^0.3.0",
    "merge-stream": "^1.0.0",
    "q": "^1.4.1",
    "run-sequence": "^1.1.5",
    "svgo": "^0.7.2",
    "through2": "^2.0.0" // 可读、可写流生成
    

    构建方式

    • 自动监听构建
    gulp watch // 监听所有资源
    
    • 全量重新构建
    gulp all // 生成所有资源(除第三方资源外)
    
    • 增量单独构建
    gulp tpl // 生成修改或新增模板
    gulp css // 生成修改或新增样式
    gulp js // 生成修改或新增脚本
    gulp img // 生成修改或新增图片
    gulp font // 生成修改或新增字体
    gulp bower // 生成修改或新增第三方资源
    
    • 全量单独构建
    gulp tplAll // 生成所有模板
    gulp cssAll // 生成所有样式
    gulp jsAll // 生成所有脚本
    gulp imgAll // 生成所有图片
    gulp fontAll // 生成所有字体
    gulp bowerAll // 生成所有第三方资源
    

    构建原理(图片)

    //pipe直接复制(svg 除外) 
    .pipe(svgProcess())
    .pipe(gulp.dest('../dest'))
    .pipe(hasher()) // 计算文件 md5
    .pipe(resouceMap(hasher.hashes, 'img')); // 生成后缀文件
    //svgProcesssvg 压缩 
    return through.obj(function(file, enc, cb) {
        if(file.path.match(/.svg$/)){
            (new svgo()).optimize(String(file.contents), function (result) {  // 使用 svgo 对象
                if (result.error) {
                    return cb(new gutil.PluginError('svgProcess', result.error));
                }
                file.contents = new Buffer(result.data); // 对文件内容重新赋值
                cb(null, file); // 继续往下流
            });
        }else{
            cb(null, file);
        }
    });
    
    //resouceMap对后缀文件对象进行排序生成 
    for(x in hashesRead){
        keyTemp.push(x);  // 已有文件
    }
    for(y in hashesWrite){
        keyTemp.push(y);  // 新增文件
    }
    keyTemp.sort();  // 文件名排序
    keyTemp.forEach(function(v,k){
        hashesTemp[v] = 'undefined' !== typeof hashesWrite[v] ? hashesWrite[v] : hashesRead[v]; // 排序后的对象
    });
    

    构建原理(脚本)

    //pipe生成未压缩和已压缩版本 
    .pipe(eslint({
        configFile: '.eslintrc' // eslint 配置文件
    }))
    .pipe(eslintReportor()) // 审核错误报告
    .on('error',errorProcess)
    .pipe(gulp.dest('../dest')) // 直接复制生成未压缩文件
    .pipe(browserSync.stream())
    .pipe(uglify({
        preserveComments: 'license' // 压缩,保留许可注释
    }))
    .on('error',errorProcess)
    .pipe(rename(function (path) {
        path.basename += ".min";  // 压缩文件增加前缀
    }))
    .pipe(gulp.dest('../dest'))
    .pipe(rename(function (path) {
        path.basename = path.basename.replace(/.min$/, ''); // 恢复原名
    }))
    .pipe(hasher())  // 以压缩版本生成后缀
    .pipe(resouceMap(hasher.hashes, 'js'));
    //eslintReportor审核通过继续,不通过输出错误信息 
    if(result.errorCount > 0 || result.warningCount > 0){ // 错误或警告数大于 0
        result.messages.forEach(function (issue) { // 错误信息循环输出
            lintReporter('eslint', result.filePath, issue.line, issue.column, issue.ruleId, issue.message, type[issue.severity]);
        });
    }
    if(result.errorCount < 1){
        cb(null, file);  // 没有错误,继续往下走
    }else{
        cb(); // 有错误,当前文件不再往下走
    }
    

    构建原理(样式)

    //pipe生成未压缩和已压缩版本 
    .pipe(lintspaces({
        indentation: 'spaces',  // 统一缩进
        spaces: 4
    }))
    .pipe(lintspacesReporter())  // 缩进错误输出
    .pipe(less())  // less 编译
    .on('error',errorProcess)
    .pipe(csslint('.csslintrc'))  // csslint 配置文件
    .pipe(csslintReporter())  // 审核错误报告
    .on('error',errorProcess)
    .pipe(cssImgHash())  // 增加图片后缀
    .pipe(gulp.dest('../dest'))  // 生成 css 文件
    .pipe(browserSync.stream())
    .pipe(hasher())
    .pipe(resouceMap(hasher.hashes, 'css'))
    .pipe(minifyCss({rebase: false}))  // 压缩样式,不处理路径
    .pipe(rename(function (path) {
        path.basename += ".min";
    }))
    //cssImgHash对所有引用图片添加后缀 
    contents = contents.replace(/url((["']?)([^)"']+?)1)/ig, function(match, quote, url){ // 匹配引用图片
        var result;
        var hashUrl = url.replace(/^//, '');
        hashUrl = hashUrl.substring(0, -1 != hashUrl.indexOf('?') ? hashUrl.indexOf('?') : hashUrl.length).replace(//|.|-/g, '_'); // 后缀字段
        if('undefined' != typeof hashes[hashUrl]){
            result = 'url(' + url + '?' + hashes[hashUrl] + ')';
        }else{
            result = match;
        }
        return result;
    });
    

    构建原理(模板组装)

    //pipe将 json 中的板块合并为 hbs 
    .pipe(concatLibs()) // 组装板块
    .pipe(htmlParser(false)) // 处理文档
    .pipe(rename({extname:".hbs"}))
    .pipe(htmllint({}, function(){}))
    .on('error',errorProcess)
    .pipe(htmllintReporter())
    .pipe(gulp.dest('../dest'))
    .pipe(htmlParser(true))
    .pipe(htmlmin({ // 压缩 html
        collapseWhitespace: true, // 空格处理
        processScripts: ['text/x-handlebars-template'], // 脚本标签中的模板
        removeComments: true, // 去除注释
        ignoreCustomFragments: [/\?{{.+?}}/] // 忽略变量
    }))
    .on('error',errorProcess)
    .pipe(rename(function (path) {
        path.basename += ".min";
    }))
    //concatLibs把板块连接,并更新相对路径 
    data = data.replace(/(['"])((?:..?/)+)/g, function(match, quote, url){
        return quote + path.relative(file.base, path.join(path.dirname(libFile), url)).replace(/\/g, '/') + '/';
    });
    
    

    构建原理(地址处理)

    //图片地址增加域名与后缀 
    reg.img = /<img[^>]*src="([^"]*)"[^>]*>/igm; // 普通图片
    reg.imgData = /<img[^>]*data="([^"]*)"[^>]*>/igm; // 延迟加载图片
    reg.ico = /<link[^>]*href="([^"]*.(ico|png))"[^>]*>/igm; // ico 图片 
    tempUrl = tempUrl.substring(0, -1 !== tempUrl.indexOf('?') ? tempUrl.indexOf('?') : tempUrl.length); // 去掉原有后缀
    var hashUrl = tempUrl.replace(//|.|-/g, '_'); // 统一字段字符
    tempUrl = '{{constant.url.resource}}' + tempUrl + '?{{hash.img.' + hashUrl+ '}}'; // 添加域名后缀
    //样式地址增加域名与后缀,放置在 head 里,压缩版本串联 
    var stylesReg = /({{#[^}]*?}}(?:
    ?
    )?)?<link(?:.*)rel="stylesheet"(?:[^>]*)/?>(?:
    ?
    )?({{/[^}]*?}}(?:
    ?
    )?)?/gim // 提取样式标签 
    contents = contents.replace(/({{{w+}}}s*)?(</head>)/, stylesTag + '$1$2'); // 放到 head 结束标签前 
    stylesUrl += styles[x].replace(stylesReg, '$1').trim()
        + minUrl + '?{{hash.' + hashKey + '.' + hashUrl + '}}' + (x >= stylesLength-1 ? '' : ',')
        + styles[x].replace(stylesReg, '$2').trim();  //连接为一条地址
    //脚本地址增加域名与后缀,放置在 body 最后面,压缩版本串联 
    var scriptsReg = /<script[^>]*>[^<]*</script>(
    ?
    )?/gim; // 提取脚本标签 
    var orderReg = /order="(-?d+)/i // 脚本顺序提取
    if(!toMin){
        var order = 10000;
        scripts = scripts.map(function(v){
            if(!v.match(orderReg)){
                v = v.replace('<script', '<script set-order="' + order + '"'); // 设置默认顺序
                order++;
            }
            return v;
        });
        scripts.sort(function(a,b){
            return parseInt(orderReg.exec(a)[1]) - parseInt(orderReg.exec(b)[1]); // 从小到大排序
        });
        scripts = scripts.map(function(v){
            v = v.replace(/sset-order="(d+)"/i, ''); // 删除增加的顺序属性
            return v;
        });
    }
    
  • 相关阅读:
    SVN同步版本库与网站目录2
    SVN同步版本库与网站目录
    vsftpd配置手册(实用)
    Yii中的CComponent应用实例
    js中文乱码
    yii CComponent组件 实例说明1
    try...cath...finally中的return什么时候执行
    Jmeter之Constant Timer与constant throughput timer的区别
    cookie、session、sessionid ,jsessionid 的区别
    性能测试基本概念
  • 原文地址:https://www.cnblogs.com/junhey/p/8981699.html
Copyright © 2011-2022 走看看