IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    轩枫阁V3主题开发-构建篇

    ivan发表于 2016-08-31 16:39:08
    love 0

    前言

    本文将介绍如何将基于WP的项目,结合前端工作流tmt-workflow,实现开发、体验、部署上线流程,流程简单,自定义程度高。

    tmt-workflow

    tmt-workflow 是一个基于 Gulp(v4.0)、高效、跨平台(macOS & Win)、可定制的前端工作流程。

    介绍文章:tmt-workflow前端工作流

    目录结构

    themes/
    │
    ├─── _tasks/                  // tmt-workflow自带 Gulp 任务目录
    │   ├── TaskBuildDev.js       // gulp build_dev
    │   ├── TaskBuildDist.js      // gulp build_dist
    │   │
    ├──── xuanfeng-v3.0           // pc版主题
    │   ├── _tasks/
    │   │    ├── TaskBuildDev.js  // BuildDevAll 本地开发
    │   │    ├── TaskBuildDist.js // BuildDistAll 打包构建
    │   │    └── TaskBuildPub.js  // BuildPubAll 上线发布
    │   ├── dev/     // dev 本地构建目录
    │   ├── dist/    // dist 构建最终目录
    │   ├── src/     // 源代码目录
    │   │    ├── css/       // less源文件
    │   │    ├── html/      // html静态页面
    │   │    ├── js/        // js源文件
    │   │    ├── img/       // 图片目录
    │   │    ├── slice/     // 雪碧图目录
    │   │    ├── fonts/     // 代码高亮字体目录
    │   │    ├── media/     // 钢琴导航声音文件
    │   │    ├── index.php  // php源文件,修改后同步至外层
    │   │    ├── xxx.php
    │   │
    │   ├── gulpfile.js // gulp配置文件
    │   ├── index.php   // src目录生成的php文件
    │   ├── xxx.php     // php文件使用于主题
    │   │
    ├──── xuanfeng-v3.0-m       // 移动端主题,目录结构同上
    │
    │──── node_modules/         // node包文件,不同主题共用
    ├──── package.json          // tmt package配置
    └──── server.json           // 服务器信息配置

    自定义任务

    每个项目下都有对应的_tasks目录,用于自定义构建,因为tmt-workflow只能满足基本需求,如果情况需要特殊处理:

    • 修改src目录php文件时,处理至外层目录并刷新浏览器
    • 替换php文件中路径如./css、./img、./js
    • 资源文件添加版本号(.php、.mp3、.html不处理),替换为WP格式PHP路径
    • 复制fonts字体文件
    • FTP增量发布文件至服务器

    流程图

    builddevall

    builddistall

    本地环境 dev

    var del = require('del');
    var ejs = require('gulp-ejs');
    var less = require('gulp-less');
    var gulpif = require('gulp-if');
    var util = require('../../_tasks/lib/util');
    var ejshelper = require('tmt-ejs-helper');
    var bs = require('browser-sync').create();  // 自动刷新浏览器
    var lazyImageCSS = require('gulp-lazyimagecss');  // 自动为图片样式添加 宽/高/background-size 属性
    var postcss = require('gulp-postcss');   // CSS 预处理
    var postcssPxtorem = require('postcss-pxtorem'); // CSS 转换 `px` 为 `rem`
    var posthtml = require('gulp-posthtml');  // HTML 预处理
    var posthtmlPx2rem = require('posthtml-px2rem');  // HTML 内联 CSS 转换 `px` 为 `rem`
    var replace = require('gulp-replace');
    var localhost = getLocalHost();
    
    var paths = {
        src: {
            dir: './src',
            img: './src/img/**/*.{JPG,jpg,png,gif}',
            slice: './src/slice/**/*.png',
            js: './src/js/**/*.js',
            media: './src/media/**/*',
            fonts: './src/fonts/**/*',
            less: './src/css/style-*.less',
            lessAll: './src/css/**/*.less',
            html: ['./src/html/**/*.html', '!./src/html/_*/**.html', '!./src/html/_*/**/**.html'],
            htmlAll: './src/html/**/*.html',
            php: './src/*.php',
            phpAll: './src/*.php'
        },
        dev: {
            dir: './dev',
            css: './dev/css',
            html: './dev/html',
            php: './'
        }
    };
    
    function getLocalHost(){
        var interfaces = require('os').networkInterfaces();
        for(var devName in interfaces){
              var iface = interfaces[devName];
              for(var i=0;i<iface.length;i++){
                   var alias = iface[i];
                   if(alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal){
                         return 'http://' + alias.address + ':8080';
                   }
              }
        }
    }
    
    
    module.exports = function (gulp, config) {
    
        var lazyDir = config.lazyDir || ['../slice'];
    
        // 复制操作
        var copyHandler = function (type, file) {
            file = file || paths['src'][type];
    
            return gulp.src(file, {base: paths.src.dir})
                .pipe(gulp.dest(paths.dev.dir))
                .on('end', reloadHandler);
        };
    
        // 自动刷新
        var reloadHandler = function(){
            config.livereload && bs.reload();
        };
    
        // 清除目标目录
        function delDev() {
            return del([paths.dev.dir]);
        }
    
        function deletePhp() {
            return del(['./*.php', './*.html']);
        }
    
        // 复制操作 start
        function copyImg() {
            return copyHandler('img');
        }
    
        function copySlice() {
            return copyHandler('slice');
        }
    
        function copyJs() {
            return copyHandler('js');
        }
    
        function copyMedia() {
            return copyHandler('media');
        }
    
        function copyFonts() {
            return copyHandler('fonts');
        }
    
        function copyPhp(file) {
            return gulp.src(file)
                .pipe(gulp.dest(paths.dev.php))
                .on('end', reloadHandler);
        }
        // 复制操作 end
    
        // 编译 less
        function compileLess() {
            return gulp.src(paths.src.less)
                .pipe(less())
                .on('error', function (error) {
                    console.log(error.message);
                })
                .pipe(gulpif(
                    config.supportREM,
                    postcss([
                        postcssPxtorem({
                            root_value: '20', // 基准值 html{ font-size: 20px; }
                            prop_white_list: [], // 对所有 px 值生效
                            minPixelValue: 2 // 忽略 1px 值
                        })
                    ])
                ))
                .pipe(lazyImageCSS({imagePath: lazyDir}))
                .pipe(gulp.dest(paths.dev.css))
                .on('data', function () {
                })
                .on('end', reloadHandler)
        }
    
        // 编译 html
        function compileHtml() {
            return gulp.src(paths.src.html)
                .pipe(ejs(ejshelper()).on('error', function (error) {
                    console.log(error.message);
                }))
                .pipe(gulpif(
                    config.supportREM,
                    posthtml(
                        posthtmlPx2rem({
                            rootValue: 20,
                            minPixelValue: 2
                        })
                    ))
                )
                .pipe(gulp.dest(paths.dev.html))
                .on('data', function () {
                })
                .on('end', reloadHandler)
        }
    
        // 编译 php
        function compilePhp() {
            return gulp.src(paths.src.phpAll)
                .on('error', function (error) {
                    console.log(error.message);
                })
                .pipe(replace(/\.\/(css|js|img)/g, "<?php bloginfo('template_url'); ?>/dev/$1"))
                .pipe(gulp.dest(paths.dev.php))
                .on('data', function () {
                })
                .on('end', reloadHandler)
        }
    
        // 启动 livereload
        function startServer() {
            bs.init({
                server: paths.dev.dir,
                port: config['livereload']['port'] || 8080,
                startPath: config['livereload']['startPath'] || '/html',
                reloadDelay: 0,
                notify: {      //自定制livereload 提醒条
                    styles: [
                        "margin: 0",
                        "padding: 5px",
                        "position: fixed",
                        "font-size: 10px",
                        "z-index: 9999",
                        "bottom: 0px",
                        "right: 0px",
                        "border-radius: 0",
                        "border-top-left-radius: 5px",
                        "background-color: rgba(60,197,31,0.5)",
                        "color: white",
                        "text-align: center"
                    ]
                }
            });
        }
    
        var watchHandler = function (type, file) {
            file = file.replace(/\\/g,'/');
            var target = '';
            if(file.match(/^src[\/|\\](.*?)[\/|\\]/)){
                target = file.match(/^src[\/|\\](.*?)[\/|\\]/)[1];
            }else if(/\.php/.test(file)){
                target = 'php';
            }
    
            switch (target) {
                case 'img':
                    if (type === 'removed') {
                        var tmp = file.replace('src/', 'dev/');
                        del([tmp]);
                    } else {
                        copyHandler('img', file);
                    }
                    break;
    
                case 'slice':
                    if (type === 'removed') {
                        var tmp = file.replace('src/', 'dev/');
                        del([tmp]);
                    } else {
                        copyHandler('slice', file);
                    }
                    break;
    
                case 'js':
                    if (type === 'removed') {
                        var tmp = file.replace('src/', 'dev/');
                        del([tmp]);
                    } else {
                        copyHandler('js', file);
                    }
                    break;
    
                case 'media':
                    if (type === 'removed') {
                        var tmp = file.replace('src/', 'dev/');
                        del([tmp]);
                    } else {
                        copyHandler('media', file);
                    }
                    break;
    
                case 'css':
    
                    if (type === 'removed') {
                        var tmp = file.replace('src/', 'dev/').replace('.less', '.css');
                        del([tmp]);
                    } else {
                        compileLess();
                    }
                    break;
    
                case 'html':
                    if (type === 'removed') {
                        var tmp = file.replace('src/', 'dev/');
                        del([tmp]).then(function () {
                            util.loadPlugin('BuildDev');
                        });
                    } else {
                        compileHtml();
                    }
    
                    if (type === 'add') {
                        setTimeout(function () {
                            util.loadPlugin('BuildDev');
                        }, 500);
                    }
                    break;
    
                case 'php':
                    if (type === 'removed') {
                        var tmp = file.replace('src/', './');
                        del([tmp]).then(function () {
                            util.loadPlugin('BuildDev');
                        });
                    } else if (type === 'add') {
                        copyPhp(file);
                    } else {
                        compilePhp();
                    }
                    break;
            }
    
        };
    
        // 监听文件
        function watch(cb) {
            var watcher = gulp.watch([
                    paths.src.img,
                    paths.src.slice,
                    paths.src.js,
                    paths.src.media,
                    paths.src.lessAll,
                    paths.src.htmlAll,
                    paths.src.phpAll
                ],
                {ignored: /[\/\\]\./}
            );
    
            watcher
                .on('change', function (file) {
                    util.log(file + ' has been changed');
                    watchHandler('changed', file);
                })
                .on('add', function (file) {
                    util.log(file + ' has been added');
                    watchHandler('add', file);
                })
                .on('unlink', function (file) {
                    util.log(file + ' is deleted');
                    watchHandler('removed', file);
                });
    
            cb();
        }
    
        // 加载插件
        function loadPlugin(cb) {
            util.loadPlugin('build_dev');
            cb();
        }
    
        // 注册 build_dev 任务
        gulp.task('BuildDevAll', gulp.series(
            delDev,
            deletePhp,
            gulp.parallel(
                copyImg,
                copySlice,
                copyJs,
                copyMedia,
                copyFonts,
                compileLess,
                compileHtml,
                compilePhp
            ),
            gulp.parallel(
                watch,
                loadPlugin
            ),
            startServer
        ));
    };

     

    体验环境 dist

    var webpack = require('webpack-stream');
    var del = require('del');
    var watch = require('gulp-watch');
    var fs = require('fs');
    var path = require('path');
    var RevAll = require('gulp-rev-all');
    var revDel = require('gulp-rev-delete-original');
    var concat = require('gulp-concat');
    var uglify = require('gulp-uglify');
    var replace = require('gulp-replace');
    var minifyHTML = require('gulp-minify-html');
    var wrap = require("gulp-wrap");
    
    // 目录结构
    var paths = {
        src: {
            dir: './src',
            html: './src/*.html',
            js: ['./src/js/**/*.js'],
            php: './src/*.*',
            fonts: './src/fonts/**',
            indexJs: ['./src/js/lib/lazyload.js', './src/js/lib/template.js', './src/js/lib/sns_share.js', './src/js/piano-play.js', './src/js/piano.js', './src/js/public.js'],
            singleJs: ['./src/js/lib/jquery.nav.js', './src/js/lib/animatescroll.js']
        },
        dist: {
            dir: './dist/',
            js : './dist/js/',
            css: './dist/css/',
            html: './dist/html/',
            php: './dist/*.*'
        },
        publish:{
            js: "<?php bloginfo(\'template_url\'); ?>/dist/js/",
            css: "<?php bloginfo(\'template_url\'); ?>/dist/css/",
            img: "<?php bloginfo(\'template_url\'); ?>/dist/img/",
            login: '" . get_bloginfo("template_url") . "/dist/css/'
        }
    };
    
    // 文件版本号处理
    var revAll = new RevAll({
        debug: false,
        dontRenameFile: ['.html', '.php', '.mp3', '.ogg'],
        replacer: function(fragment, replaceRegExp, newReference, referencedFile) {
            if(regStr.indexOf('.js') > -1){
                newReference = newReference.replace(/(.\/)*js\//,'');
                var _content = '$1' + paths.publish.js + newReference + '$3$4';
    
                fragment.contents = fragment.contents.replace(replaceRegExp, _content);
            }
            else if(regStr.indexOf('.css') > -1){
                newReference = newReference.replace(/(.\/)*css\//,'');
                // 登录页面样式文件处理
                if(regStr.indexOf('style\\-login') > -1){
                    fragment.contents = fragment.contents.replace(replaceRegExp, '$1' + paths.publish.login + newReference + '$3$4');
                }else{
                    fragment.contents = fragment.contents.replace(replaceRegExp, '$1' + paths.publish.css + newReference + '$3$4');
                }
            }
            else if((regStr.indexOf('.jpg') > -1 || regStr.indexOf('.png') > -1) && !/background/gi.test(fragment.contents)){
                newReference = newReference.replace(/(.\/)*img\//,'');
                fragment.contents = fragment.contents.replace(replaceRegExp, '$1' + paths.publish.img + newReference + '$3$4');
            }
            fragment.contents = fragment.contents.replace(replaceRegExp, '$1' + newReference + '$3$4');
        },
        hashLength: 8,
    });
    
    module.exports = function (gulp, config) {
    
        function delDist(){
            return del([paths.dist.dir]);
        }
    
        // 复制php等到dev目录
        function copyPhp(){
            return gulp.src(paths.src.php)
                    // .pipe(minifyHTML({
                    //     // quotes: true,
                    //     // conditionals: true, // IE
                    //     comments: false,
                    //     // empty: true,
                    //     // spare: true,
                    // }))
                    .pipe(gulp.dest(paths.dist.dir));
        }
    
        // 复制终php至主题目录
        function copyPhpDist(){
            return gulp.src('./dist/*.*')
                    .pipe(gulp.dest('./'));
        }
    
        function copyFonts() {
            return gulp.src(paths.src.fonts)
                    .pipe(gulp.dest('./dist/fonts/'));
        }
    
        // 合并压缩js
        function concatIndexJs(cb){
            gulp.src(paths.src.indexJs)
                    .pipe(concat('index.js'))
                    .pipe(uglify())
                    .pipe(gulp.dest(paths.dist.js))
                    .on('end', function(){
                        cb();
                    });
        }
        function concatSingleJs(cb){
            gulp.src(paths.src.singleJs)
                    .pipe(concat('single.js'))
                    .pipe(uglify())
                    .pipe(gulp.dest(paths.dist.js))
                    .on('end', function(){
                        cb();
                    });
        }
    
        // 删除重复的PHP文件
        function delPhpDist(){
            return del([paths.dist.php]);
        }
    
        //注册 BuildDistAll 任务
        gulp.task('BuildDistAll',gulp.series(
            delDist,
            gulp.parallel(
                'build_dist',
                copyPhp,
                copyFonts,
                concatIndexJs,
                concatSingleJs
            ),
            function(cb){
                gulp.src(['./dist/**/*', '!**/*.html'])
                    .pipe(revAll.revision())
                    .pipe(gulp.dest('./dist'))
                    .pipe(revDel({
                        exclude: /(.html|.htm|.php)$/
                    }))
                    .pipe(gulp.dest('./dist'))
                    .pipe(revAll.manifestFile())
                    .pipe(gulp.dest('./dist'))
                    .on('end', function () {
                        cb();
                    });
            },
            copyPhpDist,
            delPhpDist
        ));
    }

    上线发布 publish

    var GulpSSH = require('gulp-ssh');
    var replace = require('gulp-replace');
    var gutil = require('gulp-util');
    var ftpConfig = require('../../server.json').publish;
    var vftp = require('vinyl-ftp');
    
    // 目录结构
    var paths = {
        dist: {
            dir: './dist/',
            php : './*.*',
            src: './src/**',
            dist: './dist/**'
        },
        publish:{
            dir: '/domains/xuanfengge.com/public_html/wp-content/themes/xuanfeng-3.0/',
            php: '/domains/xuanfengge.com/public_html/wp-content/themes/xuanfeng-3.0/',
            src: '/domains/xuanfengge.com/public_html/wp-content/themes/xuanfeng-3.0/src/',
            dist: '/domains/xuanfengge.com/public_html/wp-content/themes/xuanfeng-3.0/dist/'
        }
    };
    
    // ftp配置
    var deploy = vftp.create({
        host: ftpConfig.host,
        user: ftpConfig.user,
        password: ftpConfig.password,
        port: 21,
        parallel: 10,
        log: gutil.log,
    });
    
    // 发布资源
    module.exports = function (gulp, config) {
    
        // 复制dist资源目录
        function copyDist(){
            return gulp
                .src(paths.dist.dist)
                .pipe(deploy.newer(paths.publish.dist))
                .pipe(deploy.dest(paths.publish.dist));
        }
    
        // 复制php
        function copyPhp(){
            return gulp.src(paths.dist.php)
                .pipe(deploy.newer(paths.publish.php))
                .pipe(deploy.dest(paths.publish.php));
        }
    
        // 复制src目录
        function copySrc(){
            return gulp
                .src(paths.dist.src)
                .pipe(deploy.newer(paths.publish.src))
                .pipe(deploy.dest(paths.publish.src));
        }
    
        // 强制更新版本号
        function copyVersion(){
            return gulp
                .src(['./footer.php', './header.php'])
                .pipe(deploy.dest(paths.publish.php));
        }
    
        //注册 BuildPublishAll 任务
        gulp.task('BuildPubAll', gulp.series(
            'BuildDistAll',
            copyDist,
            copyPhp,
            copySrc,
            copyVersion
        ));
    }

    增量发布

    增量发布使用vinyl-ftp提供的newer方法判断文件是否已更新,是否进行上传替换。



沪ICP备19023445号-2号
友情链接