如何开发一个前端CLI脚手架工具,并发布npm,为团队提效

1,什么是CLI工具

CLI(命令行界面)工具是一种允许用户通过文本命令与计算机程序或操作系统进行交互的软件。CLI工具通常用于执行特定任务、管理系统设置、运行脚本或处理文件。与图形用户界面(GUI)相比,CLI工具通常更轻量、更快速,并且可以轻松地在不同平台上使用。CLI工具在软件开发、系统管理和自动化任务中非常常见。

在现代软件开发中,命令行界面(CLI)工具以其高效、灵活的特点深受开发者喜爱。其中,脚手架工具作为一种特定类型的CLI应用,能够快速生成项目基础结构,极大地简化开发流程,提升工作效率。本文将带领你从构思到实现,逐步构建一个自定义的CLI脚手架工具。

2,CLI工具能为我们做什么

我们在项目开发时,经常会用到一些cli工具,比如vue-clinpm init等等,这些CLI工具我们常常用做项目初始化、代码检查、模板创建等交互相对简单,且重复性较多的工作。

3,开发CLI工具需要了解的前置知识

commander:

提供了用户命令行输入和参数解析的工具,具体使用可以参考我写的这篇文章

commander.js 入门指南:构建强大的命令行界面 (全网最全教程)

inquirer:

一个强大的用户与命令行交互的工具,具体使用可以参考我写的这篇文章 inquirer.js 构建交互式命令行工具,全网详细 inquirer.js中文教程

fs-extra:

fs-extra是对标准fs模块的扩展,它不仅包含了所有原生fs模块的方法,而且还添加了许多实用的功能,如复制、移动、删除文件/目录等。这些方法都支持Promise,使得我们可以用同步或异步的方式轻松处理文件。具体使用可以参考我写的这篇文章,深入浅出fs-extra:Node.js文件操作的瑞士军刀

chalk:

可以实现好看的日志输出等

4,从零开始搭建一个cli工具

工具介绍:

团队使用zustand 做状态管理工具,为了简化zustand 文件的创建,我开发了这个cli工具,zustand-cli

zustand-cli 是一个命令行工具,用于快速生成 Zustand 状态管理模板。它可以帮助您轻松创建基于 JavaScript 或 TypeScript 的 Zustand 存储和使用文件。通过使用 zustand-cli,您可以节省时间并保持项目结构的一致性。

主要功能:

  1. 自动生成 Zustand 存储模板(支持 JavaScript 和 TypeScript)。
  2. 可选生成 Zustand 使用文件(支持 JavaScript 和 TypeScript)。
  3. 简化状态管理文件的创建过程。
  4. 快速入门,无需额外配置。

使用方法:

  1. 在命令行中运行 zustand new
  2. 选择您要生成的模板类型(JavaScript 或 TypeScript)。
  3. 根据提示选择是否生成使用文件。
  4. 自动生成的文件将在当前目录中创建。
js 复制代码
NOLANKYWU-MB1:sh nolan$ zustand new
? Which template do you want to generate? TypeScript
? Do you want to generate a usage file? Yes
Created zustandTemplateTS.ts
Created zustandUseTemplateTS.tsx

关于zustand 的介绍,有兴趣的可以看我这篇文章,Zustand 状态库:轻便、简洁、强大的 React 状态管理工具

开始

在开始之前,你需要确保你的开发环境中已经安装了Node.js和npm(Node.js的包管理器)。这是因为我们将使用Node.js来构建我们的CLI工具。

js 复制代码
mkdir zustand-cli && cd zustand-cli // 创建仓库目录
npm init // 初始化 package.json
npm install -g typescript // 安装全局 TypeScript
tsc --init // 初始化 tsconfig.json

然后分别安装commander,inquirer,fs-extra,chalk等依赖

js 复制代码
npm install commander inquirer fs-extra chalk

在项目文件夹中创建一个名为index.js的文件,这将是我们CLI工具的起点。 项目目录如下

其中 zustandTemplateJS.js,zustandTemplateTS.ts,zustandUseTemplateJS.jsx,zustandUseTemplateTS.tsx都是模版文件,

./bin/index.js 文件代码如下

js 复制代码
#!/usr/bin/env node
import { program } from 'commander';
import inquirer from 'inquirer';
import fs from 'fs-extra';
import chalk from 'chalk';
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';

async function main() {
  // 定义一个新的命令 "new",用于生成 Zustand 模板
  program
    .command('new')
    .description('Generate a new Zustand template')
    .action(async () => {
      // 定义要询问用户的问题
      const questions = [
        {
          type: 'list',
          name: 'fileType',
          message: 'Which template do you want to generate?',
          choices: ['TypeScript', 'JavaScript'],
        },
        {
          type: 'confirm',
          name: 'generateUsageFile',
          message: 'Do you want to generate a usage file?',
        },
      ];

      // 使用 inquirer 库向用户询问问题
      const answers = await inquirer.prompt(questions);
      const { fileType, generateUsageFile } = answers;
      const isTypeScript = fileType === 'TypeScript';

      // 根据用户选择的类型生成 Zustand 文件
      const templateFile = isTypeScript
        ? 'zustandTemplateTS.ts'
        : 'zustandTemplateJS.js';
      const templateContent = await fs.readFile(
        path.join(dirname(fileURLToPath(import.meta.url)), templateFile),
        'utf-8'
      );
      await fs.writeFile(templateFile, templateContent);
      console.log(chalk.green(`Created ${templateFile}`));

      // 如果用户选择生成使用文件,则生成相应的使用文件
      if (generateUsageFile) {
        const usageFile = isTypeScript
          ? 'zustandUseTemplateTS.tsx'
          : 'zustandUseTemplateJS.jsx';
        const usageContent = await fs.readFile(
          path.join(dirname(fileURLToPath(import.meta.url)), usageFile),
          'utf-8'
        );

        await fs.writeFile(usageFile, usageContent);
        console.log(chalk.green(`Created ${usageFile}`));
      }
    });

  // 解析命令行参数并执行程序
  program.parse(process.argv);
}

// 调用 main 函数
main();

这段代码定义了一个基础的CLI

接下来,修改你的package.json来识别CLI命令,并设置为使用ES模块:

json 复制代码
"bin": {
    "zustand": "./bin/index.js"
},
"type": "module"

这段代码是在 package.json 文件中定义的配置。它包含两个字段:bintype

  1. bin:这个字段用于指定一个或多个可执行的二进制文件,它们将在安装此 npm 包时被链接到全局或项目范围内的可执行路径。这对于创建命令行工具(CLI)非常有用。

    在这个例子中,bin 字段定义了一个名为 zustand 的命令行工具,它将在安装此包时链接到 ./bin/index.js 文件。这意味着用户可以在命令行中直接运行 zustand 命令,而无需指定完整的文件路径。当用户运行 zustand 时,实际上是在执行 ./bin/index.js 文件。

  2. type :这个字段用于指定项目中的模块类型。它可以是 "commonjs"(默认值)或 "module"

    在这个例子中,type 设置为 "module",这意味着项目中的所有 JavaScript 文件都将被视为 ECMAScript 模块(ESM)。这将允许你在项目中使用 ESM 语法,例如 importexport 语句。请注意,这需要 Node.js v12.20.0 或更高版本,并且在项目中使用 ESM 语法时,你可能需要调整你的构建和测试工具配置。

通过全局链接你的项目:

js 复制代码
npm link

npm link 是一个用于在本地开发和测试 Node.js 包(例如 CLI 工具)的实用命令。它允许你在本地安装和使用一个包,而无需将其发布到 npm 仓库。这样,你可以在将包发布到 npm 之前进行开发和测试。

npm link 的工作原理是创建一个符号链接(symlink),将你的包链接到全局 node_modules 文件夹。这意味着你可以在任何项目中使用这个包,就像它已经被全局安装一样。

要使用 npm link,请按照以下步骤操作:

  1. 在包的根目录中运行 npm link。这将创建一个指向包的符号链接,并将其添加到全局 node_modules 文件夹中。这样,你就可以在任何项目中使用这个包了。

  2. 如果你正在开发一个依赖于此包的项目,你可以在项目根目录中运行 npm link <package-name>。这将在项目的 node_modules 文件夹中创建一个指向全局符号链接的符号链接。这样,你就可以在项目中使用这个包,就像它已经被安装在项目中一样。

这种方法的优点是,你可以在不同的项目中使用同一个本地包,并在开发过程中立即看到更改的效果。这对于开发和测试新功能非常有用。

请注意,当你完成开发并准备好将包发布到 npm 时,你需要取消链接。要做到这一点,你可以在包的根目录中运行 npm unlink。如果你在项目中链接了这个包,你还需要在项目根目录中运行 npm unlink <package-name>,然后安装发布到 npm 的包版本,例如 npm install <package-name>

5,发布npm包

发布一个 npm 包涉及以下几个步骤:

  1. 创建一个 npm 账户 :首先,你需要在 npmjs.com 上创建一个账户(如果你还没有的话)。

  2. 登录到 npm :在你的命令行中运行 npm login,然后输入你的 npm 用户名、密码和电子邮件地址。这将使你的本地开发环境与你的 npm 账户相关联。

  3. 准备你的项目:确保你的项目具有以下内容:

    • 一个 package.json 文件,其中包含项目的名称、版本、描述、入口点(主文件)等信息。
    • 一个 .npmignore 文件(可选),用于指定在发布时应排除的文件。如果没有这个文件,npm 会根据 .gitignore 文件进行排除。
  4. 设置包名称和版本 :在 package.json 文件中设置你的包名称和版本。确保名称是唯一的,没有在 npm 上被其他包使用。版本应遵循 语义化版本(Semantic Versioning) 规范。

  5. 构建和测试你的包:在发布之前,确保你的包已经通过了所有测试,并已准备好发布。运行项目的构建脚本(如果有的话)以确保一切就绪。

  6. 发布包 :在你的项目根目录中运行 npm publish。这将把你的包上传到 npm 仓库,并使其可供其他人安装和使用。

  7. 更新和维护你的包 :在开发过程中,你可能需要发布新的版本。每次发布新版本时,请确保更新 package.json 文件中的版本号(遵循语义化版本规范),然后再次运行 npm publish

注意:如果你的包包含了原生模块或需要在发布前进行特定的构建步骤,请查看 npm 文档,以了解更多关于编译、构建和发布原生模块的详细信息。

我项目中的package.json 文件如下

json 复制代码
{
  "name": "@tencent/zustand-cli",
  "version": "1.0.5",
  "description": "CLI for generating zustand state management files",
  "main": "./bin/index.js",
  "type": "module",
  "keywords": [
    "zustand",
    "redux",
    "React",
    "state management",
    "state",
    "management",
    "cli"
  ],
  "scripts": {
    "start": "node bin/index.js"
  },
  "author": "nolankywu",
  "bin": {
    "zustand": "./bin/index.js"
  },
  "license": "ISC",
  "dependencies": {
    "chalk": "^5.3.0",
    "commander": "^12.0.0",
    "fs-extra": "^11.2.0",
    "inquirer": "^8.2.6",
    "keypress": "^0.2.1",
    "zustand": "^4.5.2"
  }
}

在登录npm后执行 npm publish 就可以把包发布到npm上啦

完整项目在我的GitHub上,欢迎fork:

github.com/tomato-wu/z...

npm 包的地址

www.npmjs.com/package/zus...

欢迎使用

相关推荐
Mike_jia1 分钟前
Icinga 2:开源监控领域的全能选手——从零构建企业级智能运维体系
前端
wuxuanok3 分钟前
Web前端开发-HTML、CSS
前端·css·html
Mike_jia3 分钟前
Dish:套接字监控领域的「听诊器」——轻量级网络健康守护神深度解析
前端
独立开阀者_FwtCoder12 分钟前
"页面白屏了?别慌!前端工程师必备的排查技巧和面试攻略"
java·前端·javascript
慧一居士12 分钟前
Vite 完整功能详解与 Vue 项目实战指南
前端·vue.js
南岸月明12 分钟前
不聊主业,聊聊你们眼中的副业是什么样的?
前端
Kevin在掘金9201417 分钟前
c#、.net、Fluent UI Blazor
前端
LovelyAqaurius18 分钟前
RSA加密算法:从数学魔法到现实守护
前端
Hilaku20 分钟前
说实话,React的开发体验,已经被Vue甩开几条街了
前端·javascript·vue.js
蛋黄蛋黄23 分钟前
微信表情怎么在自己的项目使用微信表情?-> [开源仓库]wechat-emoji
前端·github