基本的vue3-cli模板包创建

52 阅读3分钟

实现总结

通过 package.json 的 bin 字段 注册全局命令,

并且 index.js 设置为可执行 node 脚本

通过npm link 与本地npm创建链接,供本地全局使用

当用户运行 vue3-zhb-cli 时,自动执行 index.js

它复制模板并生成项目。

实现步骤

1. 创建以下文件结构

vue3-zhb-cli/
  ├─ templates/
  │ │ └─ vue-basic/       ← 模板项目文件(你想你的初始化项目是什么样的都在这里面写)		  
	│	│	│	├─ src            ← 黄色区域内都是项目模板文件
	│	│	│	│  ├─ App.vue
	│	│	│	│  └─ main.js
	│	│	│	├─ index.html
	│	│	│	├─ package.json   ← 里面你要用的依赖都自己配置好,不然模板构建完成无法运行
	│	│	│	└─ vite.config.js ← 里面你要用的依赖都自己配置好,不然模板构建完成无法运行
  ├─ index.js             ← CLI 主入口(命令逻辑)
  └─ package.json         ← 声明 CLI 命令名(bin 字段)

2. 编写index.js 文件内容( #!/usr/bin/env node 这行代码是关键!在index顶部声明为可执行命令)

// vue3-zhb-cli下的index.js文件(使用时将此行删除)
#!/usr/bin/env node

const inquirer = require('inquirer')
const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const { execSync } = require('child_process')

// 模板路径
const templatePath = path.join(__dirname, 'templates', 'vue-basic')

console.log(chalk.cyan('Welcome to Vue3 ZHB CLI! 🚀'))

async function run() {
  try {
    // 交互式输入项目名
    const { projectName } = await inquirer.prompt([
      {
        type: 'input',
        name: 'projectName',
        message: 'Enter the project name:',
        validate: input => (input ? true : 'Project name is required!'),
      },
    ])

    const projectDir = path.join(process.cwd(), projectName)

    if (fs.existsSync(projectDir)) {
      console.log(chalk.red(`The directory ${projectName} already exists.`))
      return
    }

    // 创建目录
    fs.mkdirSync(projectDir)

    // 拷贝模板文件
    const copyRecursiveSync = (src, dest) => {
      const stats = fs.statSync(src)
      if (stats.isDirectory()) {
        // 不在目标目录再次创建顶层文件夹
        if (!fs.existsSync(dest)) fs.mkdirSync(dest)
        fs.readdirSync(src).forEach(child => {
          copyRecursiveSync(path.join(src, child), path.join(dest, child))
        })
      } else {
        fs.copyFileSync(src, dest)
      }
    }

    copyRecursiveSync(templatePath, projectDir)

    console.log(chalk.green(`Project ${projectName} created successfully!`))
    //检测用户用的是npm\pnpm\yarn
    const detectPackageManager = () => {
      const candidates = [
        { cmd: 'pnpm --version', pm: 'pnpm' },
        { cmd: 'npx pnpm --version', pm: 'pnpm-npx' },
        { cmd: 'yarn --version', pm: 'yarn' },
        { cmd: 'npx yarn --version', pm: 'yarn-npx' },
      ]

      for (const { cmd, pm } of candidates) {
        try {
          execSync(cmd, { stdio: 'ignore' })
          return pm
        } catch {}
      }

      return 'npm'
    }
    const packageManager = detectPackageManager()
    const installCommand = {
      pnpm: 'pnpm install',
      'pnpm-npx': 'npx pnpm install',
      yarn: 'yarn install',
      'yarn-npx': 'npx yarn install',
      npm: 'npm install',
    }[packageManager]
    // 安装依赖
    console.log(`Installing dependencies with ${packageManager}...`)
    execSync(installCommand, { cwd: projectDir, stdio: 'inherit' })
    //不同依赖包生成不同提示
    let runCommand
    switch (packageManager) {
      case 'yarn':
        runCommand = 'yarn dev'
        break
      case 'pnpm':
        runCommand = 'pnpm dev'
        break
      default:
        runCommand = 'npm run dev'
    }

    console.log(chalk.green(`🎉 Project ${projectName} created successfully!`))
    console.log(
      chalk.blue(`To get started:\n  cd ${projectName}\n  ${runCommand}`)
    )
  } catch (err) {
    console.error(chalk.red(err.message))
  }
}

run()
// vue3-zhb-cli下的package.json文件
{
  "name": "vue3-zhb-cli",
  "version": "1.0.0",
  "bin": {
    "vue3-zhb-cli": "index.js" 
    //1. 这里是重点,通过cmd将执行的命令与vue3-zhb-cli下的index.js进行 
    //  关联即可将声明为可执行命令的index.js执行
    //2. 这里vue3-zhb-cli你想执行什么命令构建项目,就改为什么
    //  如:"a-b": "index.js","x-y-z": "index.js"
  },                           
  "dependencies": {
    "inquirer": "^8.2.0",
    "chalk": "^4.1.2"
  },
  "devDependencies": {}
}

3. 执行 npm link 可以在全局使用,将vue3-zhb-cli构建命令与全局的npm包进行关联

npm link把本地开发的 npm 包“全局安装”并创建符号链接,让你可以像使用正式 npm 包一样使用自己写的 CLI 或库,而不需要每次都发布到 npm。

简单说就是:

  • 你的本地包(CLI 或库) → 在全局创建一个 软链接
  • 你可以在任何地方直接执行命令或 require() 你的包

npm link工作原理

  1. CLI 项目的 package.json 中有 bin 字段,例如:
"bin": {
  "vue3-zhb-cli": "index.js"
}
  1. npm link 会在全局 node_modules/.bin 下创建一个 可执行符号链接,指向你的 index.js
  2. 命令行执行 vue3-zhb-cli 时,就会调用你本地项目的 index.js

4. 在vue3-zhb-cli根目录执行 npm install 安装交互相关依赖

5. 现在你可以去执行任意位置中执行 vue3-zhb-cli (自定义的命令),来构建你定义好模板的vue3项目了

如有错误,请各位指出。