封装一个自己的前端脚手架cli工具(二)
上一节 我们编写了第一个 cli 的命令 mycli create <project> 来创建项目,这一节我们根据项目结构丰富一个新建页面的命令 mycli newPage <pageName>。具体请参照上一节
需要的依赖
commander、fs-extra、inquirer、@babel/parser、@babel/traverse、@babel/generator
$ npm install commander
$ npm install fs-extra
$ npm install inquirer
$ npm install --save @babel/parser
$ npm install --save @babel/traverse
$ npm install --save @babel/generator
一、编写 mycli newPage <pageName> 命令
先在 bin/cli.js 文件中添加 commander 命令
#! /usr/bin/env node
const {
Command} = require('commander');
const program = new Command()
// 定义创建项目
program
.command('create <projectName>')
.description('create a new project, 创建一个新项目')
.option('-f, --force', '如果创建的目录存在则直接覆盖')
.action((name, option) => {
// 引入create.js 模块并传递参数
require('../lib/create')(name, option)
})
// 新建页面,并添加type、store、route等配置
program
.command('newPage <pageName>')
.description('创建新页面,并配置type、store、route')
.action((pageName) => {
// 引入newPage.js 模块并传递参数
require('../lib/newPage')(pageName)
})
// 配置版本信息
program
.version(`v${
require('../package.json').version}`)
.description('使用说明')
.usage('<command> [option]')
program.parse(process.argv)
与编写创建项目的命令类似,如果需要添加其他配置,可以自行配置
二、编写命令逻辑
1.创建 newPage.js 文件
在 mycli / lib 下创建newPage.js 文件,与 create.js 文件类似,通过交互式命令行的形式,获得用户的答案。这里根据 umi 模板的结构,我们需要先获取到每一个子项目的文件夹名称
// 模板文件结构
project
|— config
|— mock
|— node_modules
|— src
|— locales
|— pages
|— childproject1
|— component
|— config
|— models
|— connect.d.ts
|— pages
|— anypages
|— index.tsx
|— index.less
|— route
|— service
|— type
|— index.ts
|— childproject2
|— public
|— package.json
|— README.md
|— tsconfig.json
因为这种特殊的目录结构,我们先要获取子项目的目录,用来给用户选择,是在哪一个子项目中添加新页面。使用 fs-extra.readdirSync() 得到一个子项目名称的列表
使用 inquirer 中的 rawlist 类型,可以让用户进行选择式的交互
// lib/newPage.js
const path = require('path');
const extra = require('fs-extra'); // fs-extra 是 node fs 的扩展
const inquirer = require('inquirer'); // 命令行交互
const chalk = require('chalk'); // ‘粉笔’ 用于设置终端字体颜色的库(下载4.x版本)
module.exports = async function (name) {
const cwd = process.cwd(); // 项目根目录地址
const targetAir = path.join(cwd, 'src', 'pages'); // 需要创建的目录地址
// 读取项目文件夹目录
const projectCatalogue = extra.readdirSync(targetAir)
// 交互式提问获取用户选择的项目
const inquirerAnswer = await inquirer.prompt({
name: 'chooseProject',
type: 'rawlist',
message: '请选择需要添加页面的项目文件夹:',
choices: [...projectCatalogue]
})
console.log(inquirerAnswer)
}
这里就可以得到用户的答案,用作接下来的操作。
我们现在分析一下路由文件
// 模板中 route.ts 内容
module.exports = [
{
path: '/', redirect: '/adjustTheRecord' },
{
path: '/adjustTheRecord',
exact: true,
name: '商品价格列表',
component: "@/pages/testProject/pages/adjustTheRecord",
layout: {
hideNav: true
}
}
];
由此结构我们添加新路由则需要按照这个模板增加,我们尝试添加一个testPage的路由
{
path: '/testPage',
exact: true,
name: '测试新增页面',
component: '@/pages/testProject/pages/testPage',
layout: {
hideNav: true,
}
}
path: '/testPage',
component: '@/pages/testProject/pages/testPage'
从上面的代码分析,path 和 component 中的 ‘testPage’ 可以从 mycli newPage <pageName> 命令获取到页面名称,component 中的 ‘testProject’ 可以从 inquirerAnswer 用户的回答中获得,这里还有一个 name 的值 ‘测试新增页面’,也需要通过用户输入来获取,所以再添加一个 inquirer 询问
// lib/newPage.js
// 询问用户新路由页面名称
const inquirerAnswerOfName = await inquirer.prompt({
name: 'inputRouteName',
type: 'input',
message: '请输入新页面路由名称:',
validate: (value) => {
// 只含有汉字、数字、字母、下划线,下划线位置不限
const reg = new RegExp(/^[a-zA-Z0-9_\u4e00-\u9fff]+$/)
if (value.match(reg)) {
return true
}
return '请输入汉字、数字、字母、下划线,下划线位置不限'
}
})
这样,我们就可以获得所有需要的值了,接下来需要判断现有的子项目下是否已有同名的页面如果没有才继续创建的工作
// lib/newPage.js
// 判断页面文件是否存在
if (extra.existsSync(path.join(projectDir, 'pages', name))) {
return console.log(`页面 ${
chalk.green(name)} 已存在`)
}
2.创建 NewPageGenerator.js 文件
判断用户想创建的页面不存在后,就可以开始创建的工作了,在 lib 文件夹下创建 NewPageGenerator.js 文件
// NewPageGenerator.js
const path = require('path');
const child_process = require('child_process');
const extra = require('fs-extra'); // fs-extra 是 node fs 的扩展
class NewPageGenerator {
constructor(name

本篇博客详细介绍了如何在自定义的前端脚手架CLI工具mycli中添加新建页面的命令myclinewPage。通过使用commander、fs-extra、inquirer等库,实现了交互式创建页面、读取路由文件、添加新路由、创建页面文件夹、拉取模板代码、生成type类型约束文件和models文件等功能。主要难点在于理解和操作AST语法树。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



