我们开发时使用vue的话,一般不会是自己去配置相关的配置,而是会直接使用vue-cli工具,使用react时会用create-react-app,这里我们来试着搭建一个自己的脚手架工具
就我现在所会的搭建方法,
- 将模板放到github仓库中,通过执行命令来将github上的代码拉取到本地
- 使用yeoman-generator,将模板放在generator中,通过yo来将generator中的模板拉取到本地
所以简单来说,就是将代码放到某个地方,在需要的时候将代码拉取到本地,但除了将相关文件拉取到本地外,用过脚手架的同学肯定知道,在初始化的时候,脚手架会提出一些问题,根据我们输入选择的不同,最终的配置也有所不同,所以脚手架并非简单的git clone和yo <name>就可以解决的
第二种搭建的方法我之前写的一个npm包generator-wxfile已经有用过了,在1.1.2版本中通过使用yeoman-generator来拉取文件,使用co-prompt来向用户提出配置问题,根据用户键入将相应的文件拉取到本地,并且修改文件中部分内容
这里我要采用第一种搭建的方法
这里我要用到几个npm包
inquirer:用于向用户提出问题和获取回答
chalk:改变命令行打印内容的样式
child_process:用于执行命令行的指令
commander:用于定义自己的命令
初始化脚手架
这里首先初始化自己的脚手架
1 2 3
| mkdir scav-cli cd scav-cli npm init
|
初始化之后,在package.json中把相应的开发依赖写入
1 2 3 4 5 6
| "dependencies": { "chalk": "^3.0.0", "child_process": "^1.0.2", "commander": "^4.1.1", "inquirer": "^7.0.4" },
|
将相关的npm包下载到node_modules中,接下来就开始脚手架的相关搭建,在bin文件夹中创建scav.js文件用于定义相关命令
定义相关命令
首先将定义脚手架的文件路径,将相关的依赖包引入,定义脚手架的版本
1 2 3 4 5 6 7 8 9 10 11
| #!/usr/bin/env node --harmony 'use strict'
process.env.NODE_PATH = __dirname + '/../node_modules/'
const program = require('commander')
program.version(require('../package').version)
program.usage('<command>')
|
给脚手架定义初始化的命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| program .command('init') .description('init a vue-based project') .alias('i') .action(()=>{ console.log('我是初始化的方法') })
program.parse(process.argv)
|
在根目录下执行下面的命令
出现如图情况就说明配置成功
为了在全局使用,在package.json中添加bin相关配置
1 2 3
| "bin": { "scav": "bin/scav.js" },
|
然后使用npm link链接到全局,就可以直接在命令行使用scav init了,如图
在最后添加命令没有被定义的操作
1 2 3 4 5
|
if (program.args.length) { program.help() }
|
我们可以在判断之前将program.args打印出来
1
| console.log('program.args: ', program.args);
|
可以看到,init被处理了,所以program.args里没有init,而ttt没被定义,没有被处理,所以被写入program.args中
编写具体操作
接下来就详细定义相关的初始化方法了,我们在根目录下创建一个command文件夹用来存放命令相关操作的文件,创建一个init.js来写初始化相关操作
接下来编写init.js,引入相关的依赖包,导出一个方法供scav.js调用
1 2 3 4 5 6 7 8 9 10 11
| const inquirer = require('inquirer') const chalk =require('chalk') const {exec} = require('child_process') chalk.level = 3
module.exports = ()=>{ console.log(chalk.green('开始初始化文件')) console.log(chalk.gray('初始化中...')) console.log(chalk.green('初始化完成')) }
|
在init.js文件中调用init.js文件
1 2 3 4 5 6 7
| program .command('init') .description('init a vue-based project') .alias('i') .action(()=>{ require('../command/init.js')() })
|
再执行初始化命令试试,如图就成功了
接下来使用inquirer来提问用户项目名,如果项目名为空,则给出提示并让用户重新输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| module.exports = ()=>{ console.log(chalk.green('开始初始化文件')) inquirer.prompt([{ type:'input', message:'your projectName:', name:'projectName', validate:(val)=>{ if(val===""){ return chalk.red('项目名不能为空,请重新输入') } return true } }]).then(answer=>{ console.log(chalk.gray('初始化中...')) console.log(chalk.green('初始化完成')) }) }
|
效果如图
接下来通过child_process中的exec来执行git clone命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| module.exports = ()=>{ inquirer.prompt([{ type:'input', message:'your projectName:', name:'projectName', validate:(val)=>{ if(val===""){ return chalk.red('项目名不能为空,请重新输入') } return true } }]).then(answer=>{ console.log(chalk.green('开始初始化文件\n')) console.log(chalk.gray('初始化中...')) const gitUrl = 'https://github.com/QZEming/vue-temp.git' exec(`git clone ${gitUrl} ${answer.projectName}`,(error,stdout,stderr)=>{ if (error) { console.log(chalk.red(error)) process.exit() } console.log(chalk.green('初始化完成')) process.exit() }) }) }
|
出现如图情况就配置成功了
发现本地多了一个文件夹
修改生成的文件
但是打开package.json,发现name是vue-temp,这可不符合我们的预期,所以我们要引入一个fs模块,通过fs模块来读写这个package.json,将之前输入的项目名写入,通过process.cwd()来获取当前命令行执行的路径,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| const fs = require('fs') module.exports = ()=>{ inquirer.prompt([{ type:'input', message:'your projectName:', name:'projectName', validate:(val)=>{ if(val===""){ return chalk.red('项目名不能为空,请重新输入') } return true } }]).then(answer=>{ console.log(chalk.green('开始初始化文件\n')) console.log(chalk.gray('初始化中...')) const gitUrl = 'https://github.com/QZEming/vue-temp.git' exec(`git clone ${gitUrl} ${answer.projectName}`,(error,stdout,stderr)=>{ if (error) { console.log(chalk.red('拷贝文件失败')) process.exit() } fs.readFile(`${process.cwd()}/${answer.projectName}/package.json`,(err,data)=>{ if(error){ console.log(chalk.red('读取文件失败')) process.exit() } data= JSON.parse(data.toString()) data.name = answer.projectName fs.writeFile(`${process.cwd()}/${answer.projectName}/package.json`,JSON.stringify(data,"","\t"),err=>{ if(err){ console.log(chalk.red('写入文件失败')) process.exit() } console.log(chalk.green('初始化完成')) process.exit() }) }) }) }) }
|
打开package.json发现与我们输入的项目名一样即修改成功
npm发布的相关内容可见前端工程化 发布一个自动生成微信开发文件的npm包
我已经发布了这个脚手架到npm上,相关代码放在github上,也可以npm i scav-cli -g试试相关的内容