Node脚手架编写初学者教程

Node脚手架编写初学者教程

完整的脚手架代码前端

编写你的第一个脚手架

前言

随着NodeJs的崛起,现代前端工程已经变得愈来愈复杂。前端框架如雨后春笋。从Backbone,Ember,Knockout,Spine,Batman框架的崛起到Angular,React,Vue平分天下,咱们经历太多代码风格的变革。vue

不可避免学习新的框架,复杂的环境又让初学者很难入手。就拿React来讲,咱们要使用Babel,Webpack等模块辅助编译,咱们还须要Redux,Immutable,Mocha,Jest,Antd或者其余第三方包(如eslint,lodash,moment,debug,uuid,request,co,koa等)辅助业务需求。node

目录结构愈来愈复杂,为了让每一个项目使用的统一的技术和目录结构,各大模块纷纷推出了本身的脚手架工具,好比redux-cli,create-react-app,vue-cli等。如今就让咱们以any-cli为例,编写本身的脚手架工具吧。react

核心原理

yoeman搭建项目须要提供yoeman-generatoryoeman-generator本质上就是一个具有完整文件结构的模板,用户须要手动地把这些模板下载到本地,而后yoeman就会根据这些模板自动生成各类不一样的项目。git

vue-cli提供了至关丰富的选项和设定功能,可是其本质也是从远程仓库把不一样的模版拉取到本地,而并不是是什么“本地生成”的黑科技。程序员

这样看来,思路也就有了——首先创建不一样的模板,而后脚手架根据用户的指令引用模板生成实际项目。github

模板既能够内置在脚手架当中,也能够部署在远程仓库。vue-cli

  • 内置在脚手架中,使用node file操做来把模板克隆到本地。npm

    优势是不用新建仓库保存模板。尤为是有多项目模板时候,好比init pcinit mobile分别生成两个不一样项目,咱们只须要一个仓库保存脚手架便可。编程

    第二个优势:不管脚手架仍是模板变动,只须要提交一次。

  • 部署在远程仓库,使用git clone把项目克隆到本地。

    优势是每次模板有代码变动时,无需让用户本地升级脚手架。

    若是模板内置在脚手架里,每次模板变动,由于是在同一仓库,因此用户须要升级脚手架。而部署在远程仓库则不一样,咱们只须要git clone便可获取最新模板。

总体流程

按照标准惯例,先看下总体流程(github不支持流程图flow类型展现,好搓,害的我又把流程代码改为这种挫样式)

添加模板->输入模板名->是否有重名模板?-添加成功:给出提示

删除模板->输入模板名->是否有模板?-删除成功:给出提示

模板列表->列出全部模板

初始化模板-输入模板名-是否有模板?-输入模块名-克隆远程仓库到本地模块-切换分支:给出提示复制代码

技术要点

process.cwd()与__dirname

命令都位于脚手架中,而执行命令的地方经常在模板项目中。

好比脚手架路径是/usr/local/lib/node_modules/any-cli/lib/,执行全局脚手架命令路径是/Users/admin/test/

想要脚手架代码想读脚手架目录下的a.js文件写入模板项目(执行全局脚手架命令位置)b.js中,那么readFile的路径为path.resolve(__dirname,'a.js'),writeFile路径为path.resolve(process.cwd(),'b.js')。就这么简单。

bin

许多npm模块有可执行文件但愿被安装到全局系统路径。

须要在package.json中提供一个bin字段,它是一个命令名称到文件路径的映射。以下:

"bin": {
    "any": "./bin/any"
},复制代码

这样会把any命令和本地可执行文件./bin/any创建映射。也就是说,当你在命令行执行any命令时,会执行./bin/any可执行文件。

  • 全局安装,npm将会使用符号连接把这些文件连接到/usr/local/bin目录下,系统的二进制命令所有在这里。

  • 若是是本地安装,会连接到./node_modules/.bin目录下。只有当前目录运行any命令时,才会生效。

若是你只有一个可执行文件,那么它的名字应该和包名相同,此时只须要提供这个文件路径(字符串),好比:

{
    "name": "any-cli",
    "version": "1.2.5",
    "bin": "./bin/any"
}复制代码

等同于:

{
    "name": "any-cli",
    "version": "1.2.5",
    "bin": {
        "any-cli": "./bin/any"
    }
}复制代码
  • 本地目录连接到全局模块

    npm link能够把本地目录连接到全局模块下。

    对于开发模块者而言,这算是最有价值的命令了。好比咱们开发any-cli模块时,须要在命令行中使用any来测试咱们的代码(开发中没有发布,也就没法全局安装模块)。不要担忧,使用npm link一切变得很是容易。

    好比咱们any-cli项目package.json里,有一条命令以下:

    "bin": {
          "any": "./bin/any"
      },复制代码

    命令行中使用npm link

    $ npm link复制代码

    获得如下结果

    /usr/local/bin/any -> /usr/local/lib/node_modules/any-cli/bin/any
      /usr/local/lib/node_modules/any-cli -> /Users/lihongji/work/any-cli复制代码

    分别进入/usr/local/bin与/usr/local/lib/node_modules目录下查看。咱们发现里面分别多了any可执行文件与any-cli目录。
    这样,每次本地仓库有改动时,全局命令也随之更新。咱们就能够边开发边测试了

  • 本地目录引用全局模块

    若是你还有其余模块any-cli-test依赖于any-cli模块,你可使用以下命令把全局any连接到当前模块下。

    $ cd ~/work/any-cli-test
      $ npm link any-cli # 把全局模式的模块连接到本地复制代码

    npm link test 命令会去/usr/local/lib/node_modules目录下查找 any-cli的模块,找到这个模块后把/usr/local/lib/node_modules/any-cli 的目录连接到当前any-cli-test下的./node_modules/any-cli 目录上。

    如今任何 test 模块上的改动都会直接映射到 test-example 上来。

其余字段:engine与engineStrict

node7.6.0开始支持async,如何保证用户本地安装node7.6.0以上版本呢复制代码
  • engine
    你能够在本地安装node特定版本:

    "engines": { "install-node": "7.6.0" }复制代码

    安装后,在本地node_modules/.bin目录下会多一个node可执行文件。本地的任何node命令都会使用这个版本的node可执行文件。

    你能够指定工做的node的版本:

    { "engines" : { "node" : ">=0.10.3 <0.12" }="" }<="" code="">
        
        
        
    
       复制代码

    而且,像dependensies同样,若是你不指定版本或者指定“*”做为版本,那么全部版本的node均可以。

    若是指定一个engines字段,那么npm会须要node在里面,若是“engines”被省略,npm会假定它在node上工做。

    你也能够用engines字段来指定哪个npm版本能更好地初始化你的程序,如:

    { "engines" : { "npm" : "~1.0.20" } }复制代码

    除非用户设置engine-strict标记,这个字段只是建议值。

  • engineStrict
    若是你肯定你的模块必定不会运行在你指定版本以外的node或者npm上,你能够在package.json文件中设置engineStrict:true。它会重写用户的engine-strict设置。

第三方包:pre-commit/node-config/commander/chalk

这几个包分别用来处理提交执行脚本,全局配置文件管理与命令行处理。会在代码中一一讲解。

代码文件

建立any-cli项目

work$mkdir any-cli
work$cd any-cli
any-cli$git init && npm init复制代码

package.json内容

{
  "name": "any-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "pub": "npm version patch && npm publish",
    "pre-commit": "eslint src"
  },
  "author": "antgod",
  "devDependencies": {
    "eslint": "^3.16.1",
    "eslint-config-airbnb": "^12.0.0",
    "eslint-plugin-babel": "^3.0.0",
    "eslint-plugin-import": "^1.6.1",
    "eslint-plugin-jsx-a11y": "^2.0.1",
    "eslint-plugin-markdown": "*",
    "eslint-plugin-react": "^6.3.0",
    "eslint-tinker": "^0.3.2",
    "pre-commit": "^1.2.2"
  },
  "dependencies": {
    "chalk": "^1.1.3",
    "child_process": "^1.0.2",
    "commander": "^2.9.0",
    "prompt": "^1.0.0"
  },
  "engines": {
    "install-node": "7.6.0"
  },
  "pre-commit": [
    "pre-commit"
  ],
  "bin": {
    "any": "./bin/any"
  },
  "license": "ISC"
}复制代码
  • 字段bin下面配置被当作命令行可执行命令。指向/bin下面的any文件。
  • 字段engines用来当前目录安装7.6.0版本node,可直接使用async函数而无须要再使用co模块。
  • pre-commit用来作提交前代码检查,运行pre-commit脚本,也就是eslint。

    在根目录下创建/bin 文件夹,建立any文件(无后缀名)。这个 /bin/any是整个脚手架的入口文件,因此咱们首先对它进行编写。

# !/usr/bin/env node
const add = require('../src/command/add')
const list = require('../src/command/list')
const init = require('../src/command/init')
const del = require('../src/command/del')
const program = require('commander')
const { version } = require('../package')

// 定义当前版本
program
.version(version)

program.parse(process.argv)
if (!program.args.length) {
  program.help()
}复制代码

运行npm link,把当前项目连接到全局。这样就能够直接在命令行使用any命令测试/bin/any下面的代码

若是没有权限,请自行百度,使用chmod 777为usr/local目录添加权限复制代码
any-cli@npm link
any-cli@any复制代码

咱们继续在/bin/any中添加代码

// 定义使用方法
program
.command('add')
.description('add template')
.alias('a')
.action(add)

program
.command('del')
.description('Delete a template')
.alias('d')
.action(del)

program
.command('list')
.description('List all the templates')
.alias('l')
.action(list)

 program
.command('init')
.description('Generate a new project')
.alias('i')
.action(init)复制代码

command用来配置any命令的参数,alias配置缩写,action配置运行什么函数。其余就不用多说了吧,程序员你懂的。

commander 的具体使用方法在这里就不展开了,能够直接到 [官网][2] 去看详细的文档。复制代码

使用any命令,看到输出以下,证实入口文件已经编写完成了。

Usage: any [options] [command]


  Commands:

    add|a    add template
    del|d    Delete a template
    list|l   List all the templates
    init|i   Generate a new project

  Options:

    -h, --help     output usage information
    -V, --version  output the version number复制代码

接着,咱们建立src/command目录,下面分别建立刚才的4个参数所对应的文件。文件内容是具体业务代码(分别对应增删查初始化),在此不作介绍。请参考github连接。代码使用了函数式编程,须要有点函数式基础。

相关文章
相关标签/搜索