一块儿来构建前端工具链吧~(新建项目)

      很久没有更新博客了。。。不知不觉作前端已过去一年有余了,渐渐发现如今入门前端的门槛愈来愈高了,须要学习的东西也多了很多,工做中效率也愈来愈慢,那么提升本身的打码速度也就愈加的重要了,而做为程序员的咱们也应该把和业务无关的东西提取出来,让它自动化,简单化,这样才能事半功倍。因而便有了我作工具链的想法,通过两个版本的迭代,npm上也有3千多的下载了,也算是稳定了下来,这个系列我就来一步步的讲述整个工具链的始末吧~css

      首先,先贴上github地址 nuts工具链,(求关注 (☆_☆))在文档中记录了如何使用,在这里我就再也不赘述了,咱们就从一个个的命令开始吧。html

建立新项目

      个人工具链是基于gulp开发的,因此在运行的时候须要gulp命令进行操做,今天就来介绍一下 create 这个命令是如何实现的。首先看这个命令的用法:前端

gulp create --name xxxx

       通常来讲咱们的项目的目录组成是由 html文件,js文件和css文件以及图片字体等静态资源组成的,那么咱们在建立新项目的时候也就应该拥有这些内容了。那么这整个是怎么开始运行起来的呢?这就要从开始输入命令行的时候提及来了,在这个命令行中,create 关键字是一个任务,而这个任务接收 -- 结尾的参数,而且拿到参数的内容已交给后续的程序处理,image这其实就是整个库的结构了,而最外层的gulpfile.js 文件就是咱们项目的配置文件了,由于使用的是gulp3.X的版本,因此必须存在这个gulpfile文件才能正常运行gulp任务,而在这个文件中我也仅仅是引入了 controller 文件而且运行其中的 run 方法,剩下的仅仅是提供一个config的配置对象而已,那么这个 run 方法又是作什么的呢?node

exports.run = ()=> {
    fs.readdirSync('./nuts/tasks/').forEach((files) => {
        if (/(\.(js)$)/i.test(path.extname(files))) {
            require('./tasks/' + files);
        }
    });
};

在这个方法中我循环加载了tasks文件夹下的全部文件,也就是说tasks文件夹下的每个文件都是一个任务,同时为了支持ES6的代码,nuts中使用了webpack做为打包工具,下面这个方法返回的就是一个最基础的webpack配置:webpack

// webpack的配置文件,通常状况下不须要修改
exports.webpackConfig = (dev)=> {
    return {
        watch: false,
        module: {
            loaders: [
                {
                    test: /\.js$/, loader: 'babel-loader', exclude: './node_modules/',
                    query: {
                        presets: ['es2015']
                    }
                }
            ]
        },
        plugins: (dev == 'dev') ? [] : [new webpack.optimize.UglifyJsPlugin()]
    }
};

而整个命令行会接收多少参数呢?端口号,项目名称,打包版本等等,这么多的参数,我选择采用一个对象来进行保存,这样便于管理和替换:git

/**
 * 经过命令行传入的参数,在这里进行缓存,方便后面调用。
 */
exports.arguments = ()=> {
    let inputArgv = minimist(process.argv.slice(2));
    return {
        _name: inputArgv.name || inputArgv.dir,
        _port: inputArgv.port,
        _clean: inputArgv.clean,
        _dev: inputArgv.dev,
        _build: inputArgv.build,
        _create: inputArgv.create,
        _ver: inputArgv.ver,
        _include: inputArgv.include
    };
};

这段代码中的 minmist 方法是一个第三方的库,这是一个可让node接收命令行参数的库,虽然功能简单,可是够用就行了~况且它还特别的小~程序员

      其实这个流程总结下来就是由 minmist 接收命令行中传来的参数,而后交给 controller文件去处理,而后再将各个参数传给不一样的tasks去处理的流程,只不过,在这个当中,我作了一些针对本身的处理。下面咱们看看这个 create 命令里面究竟作了些什么~github

packages._core.task('create', () => {

    let proName = controller.arguments()._name || defaultName(),
        devDir  = `${controller.config.sourceDir}/${proName}`;

    if (!!path.basename(proName)) {
        fs.exists(devDir, (exists) => {
            if (exists) {
                console.log('警告!!!您要建立的项目已经存在!');
            } else {
                createProject('nuts/templets', devDir, path.basename(proName));
            }
        });
    } else {
        console.log('警告!!!这是一个须要完整路径的项目!');
    }
});

      在这个任务初始化的时候咱们首先初始化两个参数,一个是须要建立的项目名称 proName,以及这个项目相对的路径 devDir,而后检查这个项目是否已经建立,若是不存在的话就调用 createProject 方法来进行建立。web

/**
 * 建立新项目的函数
 * @param templet
 * @param devDir   项目路径
 * @param name     项目名称
 */
function createProject(templet, devDir, name) {

    var letter_name = name.replace(/\_(\w)/g, (all, letter)=> {
        return letter.toUpperCase();
    });

    packages._core.src(`${templet}/index.html`)
        .pipe(packages._replace('@@main', name))
        .pipe(packages._core.dest(`${devDir}/`));

    packages._core.src(`${templet}/scss/main.scss`)
        .pipe(packages._rename(`${name}.scss`))
        .pipe(packages._core.dest(`${devDir}/scss`));

    packages._core.src(`${templet}/js/main.tmpl`)
        .pipe(packages._replace({
            '@@project_name': name,
            '@@author': controller.config.author,
            '@@date': time,
            '@@project': letter_name.replace(/(\w)/, v=> v.toUpperCase()),
            '@@letter': letter_name
        }))
        .pipe(packages._rename(`${name}.js`))
        .pipe(packages._core.dest(`${devDir}/js`));

    // 建立图片和字体文件夹
    mkdirs(path.resolve(__dirname, `../../${devDir}/`), (err)=>{
        if (err) {
            console.log(err);
        }
        fs.mkdirSync(path.resolve(__dirname, `../../${devDir}/images`));
        fs.mkdirSync(path.resolve(__dirname, `../../${devDir}/font`));
    });
    console.log(name + '项目建立完成!!!');
}

     这个方法接受3个参数,可是使用者只能传入后两个参数,我要作的就是建立html文件,js文件和scss文件以及images和font两个文件夹,同时在输出这些文件的时候我也会根据配置文件中的设置去替换模板中的关键字,其中须要注意的就是node在建立文件夹的时候须要若是父文件夹不存在时则会抛出错误,那么这个时候就须要递归的建立缺失的文件夹了,因此我写了 mkdirs 方法来解决这个问题。npm

     在tasks同级的目录下有个util目录,里面放着一些非任务的脚本,一般是用来处理诸如此类的问题的:

/**
 * 建立多层文件夹 异步
 * Created by fuhuixiang on 16-9-1.
 */

const fs   = require('fs'),
      path = require('path');

module.exports = (dirpath, callback)=> {
    mkdirs(dirpath, ()=> {
        callback();
    });
};

// 异步文件夹建立 递归方法
function mkdirs(dirpath, _callback) {
    fs.exists(dirpath, (exists)=> {
        if (exists) {
            _callback(dirpath);
        } else {
            //尝试建立父目录,而后再建立当前目录
            mkdirs(path.dirname(dirpath), ()=> {
                fs.mkdir(dirpath, _callback);
            });
        }
    });
}

      经过这样一个简单的递归方式,就能够循环的建立文件夹了,到此create命令中的两点,建立文件和替换关键字的功能点都实现了,下面就是真正的使用了~下篇我将介绍真正使用最多的dev命令~

gulp create ---name test1

gulp create ---name 2016/test1
相关文章
相关标签/搜索