Yargs 官方地址 https://github.com/yargs/yargs
以往每次建模块都需要手动创建觉得很繁琐, 看了公司项目的有自动化创建的工具, 参考了下, 是用到 Yargs, 能够自定义命令, 参数来处理问题. 通过学习 yargs, 顺便自己写一个自动化创建模块工具出来.
1. 步骤
第一步: 需要传递的参数
存在三个参数
file: 文件夹以及模块名 (必填)
path: 文件存放路径
type: 模板类型
第二步: 创建一个命令, 并且处理传入的参数
command(cmd, desc, [builder], [handler])
用 command 方法创建了一个命令, 将先前定义的参数放到 command 的 bulider 里面.
[handler] 处理传参.
第三步: 处理参数
1. 创建文件夹 2. 创建文件
第四步: 自定义模板
能够创建文件是不够的, 我们需要文件内容是我们定义好的模板内容, 所以我们先定义好模板.
第五步: 做一些体验优化, 创建文件提示, 重复文件提示
2. 目录
ReactTemplat,vueTemplate: 是自定义模板, 可以根据自己的模板内容, 结构来自定义.
cli.js: 用来创建命令, 并且将参数传给 start 文件处理.
start.js: 用来处理参数, 创建文件夹及文件, 利用 process 进程与用户进行交互.
handle.js: 处理文件的方法.
3. 帮助信息
- node ./tools/cli add -h // 显示帮助信息
- Options:
- --version Show version number [boolean]
- -h Show help [boolean]
- --file, -f create a file [required]
- --path, -p file path [default: ""]
- --type, -t file's type [choices:"vue","react"] [default:"vue"]
- Examples:
node tools/cli add -p views -f test -t vue 在 views 目录下创建一个 test 模板
4. 用法
node tools/cli add -f test -p views -t vue
在 views 目录下创建一个 test 模块, 模块类型是 vue.
新建模块时会先判断存放路径是否存在该文件夹.
遇到重复的模块可选是否需要覆盖
文件地址 https://github.com/pureZjr/addModule
- cli.js
- const argv = require('yargs')
- .command(
- 'add',
- 'create a file',
- function(yargs) {
- return yargs
- .option('file', {
- alias: 'f',
- describe: 'create a file'
- })
- .option('path', {
- alias: 'p',
- describe: 'file path',
- default: ''
- })
- .option('type', {
- alias: 't',
- describe: 'file's type',
- choices: ['vue', 'react'], // 现在有两个模板供选择, 可以根据自己的项目情况设计模板
- default: 'vue'
- })
- .demandOption(['file'], 'Please provide file to work with this tool')
- .example(
- 'node tools/cli add -p views -f test -t vue',
- '在 views 目录下创建一个 test 模板'
- )
- },
- function(argv) {
- // 根据参数, 创建模板
- start(argv)
- }
- )
- .help('h').argv
- start.js
- const handel = require('./handle')
- const colors = require('colors')
- const path = require('path')
- module.exports = async function(argv) {
- argv.file = argv.file.toString()
- const existPathFolder = await handel.existFolder(path.resolve(argv.path))
- const fileName =
- argv.file.substring(0, 1).toUpperCase() + argv.file.substring(1)
- let className = ''
- for (let i = 0; i <argv.file.length; i++) {
- if (/[A-Z]/.test(argv.file[i])) {
- className += '-'
- }
- className += argv.file[i].toLowerCase()
- }
- if (argv.path !== '') {
- argv.path += '/'
- }
- const filePath = path.resolve(argv.path) + '/' + fileName
- process.stdin.setEncoding('utf8')
- const createFileData = {
- filePath,
- fileName,
- className,
- type: argv.type
- }
- // 不存在 path 的文件夹
- if (!existPathFolder) {
- console.warn(
colors.green(` 是否创建 ${path.resolve(argv.path)} 文件夹?:y/n`)
- )
- process.stdin.on('data', async chunk => {
- chunk = chunk.replace(/[\s\n]/, '')
- if (chunk === 'y') {
- // 创建 path 文件夹
- await handel.createFolder(path.resolve(argv.path))
- // 创建组件文件夹
- await handel.createFolder(filePath)
- // 创建文件
- await handel.createFile(createFileData)
- process.exit()
- } else if (chunk === 'n') {
- process.exit()
- } else {
- console.warn(colors.red('请输入正确指令: y/n'))
- process.exit()
- }
- })
- } else {
- // 判断组件文件夹是否存在
- const existFileFolder = await handel.existFolder(filePath)
- if (existFileFolder) {
- console.warn(colors.green(`${fileName} 文件夹已存在, 是否覆盖?:y/n`))
- process.stdin.on('data', async chunk => {
- chunk = chunk.replace(/[\s\n]/, '')
- if (chunk === 'y') {
- // 创建组件文件夹
- await handel.createFolder(filePath)
- // 创建文件
- await handel.createFile(createFileData)
- process.exit()
- } else if (chunk === 'n') {
- process.exit()
- } else {
- console.warn(colors.red('请输入正确指令: y/n'))
- process.exit()
- }
- })
- } else {
- // 创建组件文件夹
- await handel.createFolder(filePath)
- // 创建文件
- await handel.createFile(createFileData)
- process.exit()
- }
- }
- }
- handle.js
- const fs = require('fs')
- const colors = require('colors')
- const path = require('path')
- module.exports = {
- existFolder: async function(path) {
- // 判断是否存在 argv.path 的文件夹
- return new Promise(function(resolve, reject) {
- return fs.exists(path, e => {
- resolve(e)
- })
- })
- },
- /**
- * 创建文件夹
- @param filePath 文件路径
- */
- createFolder: function(filePath) {
- return new Promise(function(resolve, reject) {
- fs.mkdir(filePath, function(err) {
- if (err) {
- if (err.errno === -2) {
- console.log(colors.red('找不到目录'))
- } else if (err.errno === -17) {
- }
- } else {
- console.log(colors.green('创建文件夹:'))
- console.log(colors.underline(`${filePath}`))
- }
- resolve()
- })
- })
- },
- /**
- * @param args:{
- * filePath 文件路径
- * fileName 文件名
- * className 样式名
- * type 文件类型
- * }
- */
- createFile: function({ filePath, fileName, className, type }) {
- const data = {
- fileName,
- filePath,
- className
- }
- // 模板路径
- switch (type) {
- case 'vue':
- data.templateFolderPath = path.join(__dirname, './VueTemplate')
- break
- case 'react':
- data.templateFolderPath = path.join(__dirname, './VueTemplate')
- break
- default:
- data.templateFolderPath = path.join(__dirname, './VueTemplate')
- }
- return new Promise(async (resolve, reject) => {
- await this.readAndWiteFile(data, resolve)
- })
- },
- /**
- * 读取模板内容并且写到新建文件里面
- * @param args:{
- * templateFolderPath 模板路径
- * fileName 文件名
- * filePath 文件路径
- * className 样式名字
- * }
- * @param resolve
- */
- readAndWiteFile: function(
- { templateFolderPath, fileName, filePath, className },
- resolve
- ) {
- fs.readdir(templateFolderPath, 'utf8', (err, files) => {
- if (err) {
- console.log(colors.red(err))
- return false
- }
- files.forEach(templateName => {
- const FileName = templateName
- .replace('TemplateName', fileName)
- .replace('.txt', '')
- // 1. 创建文件
- fs.createWriteStream(`${filePath}/${FileName}`)
- // 2. 读取, 写入模板内容
- const content = fs
- .readFileSync(`${templateFolderPath}/${templateName}`)
- .toString() // 读取模板文件
- .replace(/\${TemplateName}/g, FileName.split('.')[0])
- .replace(/\${template-name}/g, className) // 替换模板内容
- // 将 templateName 替换成对应的文件名
- fs.writeFileSync(`${filePath}/${FileName}`, content, 'utf8')
- console.log(colors.green('写入文件:'))
- console.log(colors.underline(`${filePath}/${FileName}`))
- })
- resolve()
- })
- }
- }
来源: https://juejin.im/post/5b3506fcf265da59921a1960