使用 cli,只需几秒就能出现一个模板?

1,039 阅读3分钟

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

大家好,我是小杜杜,继上篇讲的 10分钟,打造一个专属于你的cli ,我们已经完成了项目的下载,安装和运行。(新来的小伙伴可以先快看看(● ̄(エ) ̄●))

我们在项目开发中会遇到这样一种情况,就是在开发一些页面的时候会有相同模块,像这样

image.png

如引入的文件,固定的标签,组件等重复性的东西,除了复制粘贴,还有什么方法可以几秒就能实现呢?这时候我们可以使用cli,让他来帮助我们更快的实现

最终效果

我们先来看看最终的效果:

cli.gif

简单的说就是通过交互,自动实现文件的创建路由的配置这两个功能

小技巧

可以在本地使用 npm link 在本地上直接使用即可,不用发包~

项目

在这里使用我个人的 Ant-Design-Pro-V5 ,以此来讲解(不同的项目,要进行不同的配置哦~)

创建文件

我们先来想想创建文件需要做哪些步骤,首先我们需要定义这样一个模板,让其快速构建,然后将模板复制到自己的项目即可。

所以我们这里先建立一个文件,如:

WeChatde5d9605642dab3499c3c8675f2591a6.png

然后我们在通过遍历这个文件夹,用copyFile将文件复制出去

    const fileModule = resolve(__dirname, '../../module')
    const files = fs.readdirSync(fileModule).filter((v) => ![".git"].includes(v));

    // 遍历所需要的文件,执行复制
    files.map(async (item) => {
      const fromFileName = resolve(__dirname, `../../module/${item}`);
      const toFileName = resolve(__dirname, `${desc}/${item}`);
      fs.copyFile(fromFileName, toFileName, 0, () => {})
    })

在这里我们可以优化一下,我们可以判断一下创建的这个文件有没有创建,如果有,可以弹个框,告诉你,这个文件已经创建过了,是否要删除后重新引入,所以我们接下来讲解下如何删除文件

要删除文件,需要删除文件内的所有子文件,在删除目录文件,要使用 fs.unlinkSyncfs.rmdirSync这两个方法,再配合一些提示便可实现

  // desc:文件目录
  const files = fs.readdirSync(desc)
  files.map((item) => {
    fs.unlinkSync(`${desc}/${item}`)
  })
  fs.rmdirSync(desc)

详细代码

create.ts:

const inquirer = require("inquirer");
const { resolve } = require("path");
const fs = require("fs") ;
const { log } = require("../api"); 

const filePath = 'src/pages'

module.exports = async () => {
  console.log("path", resolve("."));
  create()
};

async function create(){
  // 项⽬名称
  const name = await inquirer.prompt([{
    type: 'input',
    message: '设置文件名😎😎😎',
    name: 'name',
  }])
  const desc = resolve(`./${filePath}/${name.name}`);
  log(desc)

  // 判断是否存在该文件,若存在则不提示
  const isFile = fs.existsSync(desc)
  if(isFile){
    deleteFile(desc)
    return
  }else{
    await require(`./routes`)(name.name);
    createFile(desc)
    return
  }
}

async function createFile(desc){
  try{
    // 新建文件夹
    fs.mkdirSync(desc)

    const fileModule = resolve(__dirname, '../../module')
    const files = fs.readdirSync(fileModule).filter((v) => ![".git"].includes(v));

    // 遍历所需要的文件,执行复制
    files.map(async (item) => {
      const fromFileName = resolve(__dirname, `../../module/${item}`);
      const toFileName = resolve(__dirname, `${desc}/${item}`);
      fs.copyFile(fromFileName, toFileName, 0, () => {})
    })

  } catch {
    log('创建失败', 'red')
  }
}

async function deleteFile(desc){
  log(desc)
  try{
    // 是否选择删除后重新建立
    const answer = await inquirer.prompt([{
      type: 'confirm',
      name: 'confirm',
      message: '当前文件已有此文件,是否选择删除后重新建立?',
      default: false
    }])
    console.log("answer", answer);
    if(answer.confirm){
       // 删除模块,需要先删除文件,在删除目录
      const files = fs.readdirSync(desc)
      files.map((item) => {
        fs.unlinkSync(`${desc}/${item}`)
      })
      fs.rmdirSync(desc)
      await require(`./routes`)(answer.name);
      createFile(desc)
    }else{
      create()
    }
  } catch {
    log('发生错误', 'red')
  }
}

创建路由

我们先来看看在V5中的路由:

image.png

我们可以看到,文件的大概结构就是这样,其实不难发现,我们并不好去动这个路由,所以我们可以单独创建一个路由模块,之后在手动的去添加到项目中

效果:

image.png

我们以脚手架创建的文件为routesChildren.ts在这里我们需要注意两个点

  • 没有routesChildren.ts 我们直接添加即可
  • routesChildren.ts 这个文件的时候我们需要读取其文件,在进行拼接

注:fs.readFile 和 fs.writeFile 要求的都是字符串,所以这里我将export default截取了下

当我们创建完之后,需要手动的把 routesChildren.ts 引入到routes

    async function create(nameFile){
      const desc = resolve(`./${filePath}`);
      const isFile = fs.existsSync(desc)
      const toFileName = resolve(__dirname, desc);

      // 写
      const start = `export default`

      if(isFile){
        fs.readFile(toFileName, 'utf8', async (err, data) => {
          try{
            const arr = JSON.parse(data.substring(14, data.length).trim())
            const routerArr = await routerConfig(nameFile)
            const res = [...arr, ...routerArr]

            fs.writeFile(toFileName, `${start} ${JSON.stringify(res)}`, (err) => {
              log('🚗🚗🚗路由创建成功')
            })

          }catch{
            log('文本格式不对,请查看格式')
          }
        })
      }else{
        const routerArr = await routerConfig(nameFile)
        // 如果没有
        fs.writeFile(toFileName, `${start} ${JSON.stringify(routerArr)}`, (err) => {
          log('🚗🚗🚗路由创建成功')
        })
      }
    }

详细代码

const inquirer = require("inquirer");
const { resolve } = require("path");
const fs = require("fs") ;
const { log } = require("../api"); 

const filePath = 'config/routesChildren.ts'


module.exports = async (name) => {
  console.log("path", resolve("."));
  create(name)
};

async function create(nameFile){
  const desc = resolve(`./${filePath}`);
  const isFile = fs.existsSync(desc)
  const toFileName = resolve(__dirname, desc);

  // 写
  const start = `export default`

  if(isFile){
    fs.readFile(toFileName, 'utf8', async (err, data) => {
      try{
        const arr = JSON.parse(data.substring(14, data.length).trim())
        const routerArr = await routerConfig(nameFile)
        const res = [...arr, ...routerArr]

        fs.writeFile(toFileName, `${start} ${JSON.stringify(res)}`, (err) => {
          log('🚗🚗🚗路由创建成功')
        })
         
      }catch{
        log('文本格式不对,请查看格式')
      }
    })
  }else{
    const routerArr = await routerConfig(nameFile)
    // 如果没有
    fs.writeFile(toFileName, `${start} ${JSON.stringify(routerArr)}`, (err) => {
      log('🚗🚗🚗路由创建成功')
    })
  }
}

async function routerConfig(nameFile){
  const name = await inquirer.prompt([{
    type: 'input',
    message: '请设置路由名称',
    name: 'name',
  }])
  console.log("answer", name.name);
  const icon = await inquirer.prompt([{
    type: 'input',
    message: '请设置icon名称',
    name: 'name',
    default: 'FireOutlined'
  }])
  console.log("answer", icon.name);

  return [
    {
      path: `/${nameFile}`,
      name: name.name,
      icon: icon.name,
      component: `./${nameFile}`,
    }
  ]
}

实现效果

image.png

讨论

本章中主要讲解了下如何使用 cli 创建页面,当然这个功能并不只是创建页面,也可以弄一些在项目中常用的模板,这样可能通过几秒一个模板就创建出来,是不是非常快速的一个方法?

欢迎大家留言讨论,另外附上代码地址,供大家参观,如果有帮助,给个小小的Star,支持下~~

git 地址: domesy-cli

其他好文: