Skip to content

如何写一个脚手架

约 798 字大约 3 分钟

脚手架

2024-11-12

1. 5 分钟教你写一个脚手架

以下案例中的的脚手架已经发布 在 npm , 在本地可直接使用

npm create vue-custom@latest
pnpm create vue-custom@latest
yarn create vue-custom@latest

1.1 脚手架实践

该案例用最短的代码帮助你理解一个脚手架。

1. 初始化项目

mkdir create-vue-custom
cd create-vue-custom
touch index.js
mkdir scripts
cd scripts
touch build.mjs
pnpm init

此时文件结构应是如下:

- scripts
  - build.mjs
- index.js
- package.json

2. 添加依赖包

pnpm add esbuild
pnpm add kleur
pnpm add prompts
pnpm add zx

3. 编写脚手架


#!/usr/bin/env node
// 上面这行表示 这是一个可执行脚本,执行环境为 node

import prompts from 'prompts' // 交互提示库
import { exec, spawnSync } from 'node:child_process'  // node 子进程相关方法
import { red, green, bold } from 'kleur/colors' // 字体美化
const log = console.log

// 定义问题
const questions = [
  {
    type: 'text',
    name: 'projectName',
    message: '请输入工程名称',
  },
  {
    type: 'confirm',
    name: 'isTemplate',
    message: '是否使用内置模板',
    initial: true,
  },
  {
    type: (prev) => (prev ? 'select' : null),
    name: 'templateType',
    message: '请选择模板类型',
    choices: [
      { title: 'PC', value: 'pc', description: '这是一个默认的后台管理系统模板' },
      { title: 'H5', value: 'h5', description: '这是一个默认的H5系统模板' },
    ],
    initial: 0,
  },
]

// 这是个人的模板
const templateRepo = {
  pc: 'https://github.com/tuyongtao-T/vue3-admin-ts.git',
}

async function init() {
  try {
    log(green('准备执行脚手架命令...'))
    // 获取交互内容
    const result = await prompts(questions)

    // 如果采用模板就从远承拉取
    if (result.isTemplate) {
      log(green('准备拉取远程模板...'))

      // 使用系统拉取命令(这里也可以使用 download-git-repo等拉取git相关的工具)
      exec(`git clone ${templateRepo[result.templateType]} ${result.projectName}`)
    } else {
      // 如果不使用脚手架提供的模板则使用 create-vue脚手架
      log(green('准备切换到create-vue...'))
      const userAgent = process.env.npm_config_user_agent ?? ''
      const packageManager = /pnpm/.test(userAgent)
        ? 'pnpm'
        : /yarn/.test(userAgent)
          ? 'yarn'
          : /bun/.test(userAgent)
            ? 'bun'
            : 'npm'

      // 执行create-vue脚手架命令
      spawnSync(`${packageManager}`, ['create', 'vue@latest', result.projectName], { stdio: 'inherit' })
    }

  } catch (error) {
    console.log(error)
  }
}

init().catch((error) => {
  log(bold(error))
  process.exit(1)
}).finally(() => {
  log(green('创建成功...'))
})

4. 对脚本进行构建(非必要)

这里使用 esbuild 进行构建。 在 scripts/build.cjs 中添加内容:

import * as esbuild from "esbuild";

await esbuild.build({
  bundle: true,
  entryPoints: ["index.js"],
  outfile: "outfile.cjs",
  format: "cjs",
  platform: "node",
  target: "node14",
});

5. 在 package.json 中添加相关命令

  "name": "create-vue-custom",
  "version": "0.0.1",
  "type": "module",
  "bin": {
    "custom-cli": "outfile.cjs"
  },
   "files": [
    "outfile.cjs"
  ],
   "scripts": {
    "build": "zx ./scripts/build.mjs"
  },

6. 打包发布

pnpm build

npm login
npm publish

至此你已经把你的脚手架发布在 npm 上了, 可让其他人来下载使用。 git 仓库

2. 工欲善其事必先利其器

命令行交互工具

  • Prompts.js(https://chinabigpan.github.io/prompts_docs_cn/)

  • Inquirer.js

  • command.js :交互+参数解析

参数解析

  • parseArgs(node:util):node17+

  • minimist

  • arg

  • command.js :交互+参数解析

命令行输出美化

  • kleur
  • chalk
  • cli-color
  • ansi-color
  • colorette
  • kolorist
  • ora(进度转轮)

node 子进程调用

  • cross-spawn
  • node:child_process

系统路径处理

  • fileURLToPath(node:url)
  • slash
  • Path

数据读取与处理

  • deepmerge
  • read-pkg
  • fs.readFile

模板引擎

检测包管理和版本管理

  • semver
  • standard-version
  • which
  • execa
  • update-notifier

语言环境判断

  • Intl.getCanonicalLocales(node)

3. 参考资料

写给 5 年前端妹子的三万字脚手架教程

© 2024 图图 📧 email