【笔记】Node.js 开发 CLI 工具

【笔记】Node.js 开发 CLI 工具

文章目录

一、简介

1.Node.js

Node.js 是一种让你可以再服务器运行 JavaScript 的运行环境。它不是编程语言,也不是框架,而是一个基于浏览器引擎的工具

核心概念

  • 本质:运行 JavaScript 的环境(类似浏览器,但在服务器上运行)
  • 基础:基于 Chrome V8 Engine(谷歌浏览器的 JS 引擎)
  • 用途:开发后端服务、API、工具脚本等

解决了什么问题

在 Node.js 出现之前:

  • JavaScript 只能在浏览器中运行
  • 后端通常用 Java、Python、PHP 等

Node.js 出现后:

  • 前后端都可以用 JavaScript
  • 开发效率更高(统一语言)

核心特点

  • 非阻塞 I/O(异步)
  • 单线程但高性能

2.CLI

CLI(Command-Line interface),中文叫命令行界面,是一种通过输入文本命令来操作计算机的方式,与图形界面(GUI)相对。

CLI 能做什么

  • 文件管理(创建、删除、移动)
  • 网络操作(下载、请求 API)
  • 开发工具(运行代码、构建项目)
  • 包管理(安装依赖)

优点

  • 更快(无需鼠标操作)
  • 可脚本化(自动化任务)
  • 更强控制能力
  • 资源占用低

3.create-node-cli

create-node-cli 是一个脚手架工具,用来快速创建一个 Node.js 的 CLI 项目模板。一条命令,帮你生成一个完整的命令行工具项目结构。

官方文档:https://www.npmjs.com/package/create-node-cli

使用方法:

bash 复制代码
#Recommended.自动下载最新版本,只执行,不安装
npx create-node-cli

#OR an alternative global install.全局安装占空间,版本可能过时
npm install -g create-node-cli

二、案例:generate-web-component

用于自动生成前端 web 组件代码模板

1.执行 create-node-cli

2.配置项

npm 中的 npm link 是一个用于本地开发调试包的命令。核心作用是把你本地写的包,像 "全局安装" 一样,在其他项目中直接使用。

正常流程:

  1. 写一个 npm 包
  2. 发布到 npm
  3. 在另一个项目中安装

问题:

  • 发布流程慢
  • 每改一次都要重新发布
  • 调试效率很低

npm link 可以实现本地实时调试

基本使用步骤

  • my-lib:你写的包
  • my-app:需要使用这个包的项目

第一步:在 my-lib 中执行

bash 复制代码
cd my-lib
npm link

把 my-lib 注册成一个全局可用的包

第二步:在使用项目里执行

bash 复制代码
cd my-app
npm link my-lib

把 my-lib 链接到当前项目的 node_modules

如何取消 link

bash 复制代码
npm unlink my-lib

#或者在全局
npm unlink -g my-lib

4.编写模板代码

javascript 复制代码
export default class ExampleComponent extends HTMLElement {
    static get observedAttributes() {
        return []
    }

    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
    }

    connectedCallback() {

    }

    disconnectedCallback() {

    }

    attributeChangedCallback() {

    }
}

customElements.define('example-component', ExampleComponent);

5.CLI 入参配置

6.编写 generateWebComponent 工具

javascript 复制代码
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

function includesUppercase(str) {
    return /[A-Z]/.test(str);
}

function includesDashOrUnderscore(str) {
    return /[-_]/.test(str);
}

function convertToTagReadyString(str) {
    // 1.假如输入的名称是 mycomponent
    if (!includesUppercase(str) && !includesDashOrUnderscore(str)) {
        console.log('输入的名称的格式不正确,请使用大驼峰、短横线或蛇形命名法。');
        process.exit(1);
    }

    // 2.假如输入的名称包含_或者-
    if (includesDashOrUnderscore(str)) {
        return str.split('_').join('-').toLowerCase();
    }

    // 3.其他格式 MyComponent / myComponent / MyShinyComponent
    str = str.replace(/[A-Z]/g, (match) => {
        return "-" + match;
    });

    if (str.startsWith('-')) {
        str = str.substring(1);
    }

    return str.toLowerCase();

}

export default async function (name, destination) {
    fs.readFile(
        path.join(__dirname, '../templates', 'ExampleComponent.js'),
        'utf-8',
        (err, data) => {
            if (err) {
                throw err;
            }

            // 2.创建目录(放这里也更安全)
            if (!fs.existsSync(destination)) {
                fs.mkdirSync(destination, { recursive: true });
                console.log(`创建了一个文件夹${destination}`);
            }

            // 3.处理文件名
            let filename;
            if (name.includes('.')) {
                filename = name.split('.')[0];
            } else {
                filename = name;
            }

            const tagName = convertToTagReadyString(filename);
            const componentName = filename.includes('-')
                ? filename.replace('-', '_')
                : filename;

            // 4.替换模板内容
            const newData = data
                .replace(/ExampleComponent/g, componentName)
                .replace(/example-component/g, tagName);

            destination = destination.endsWith('/')
                ? destination.slice(0, -1)
                : destination;

            name = name.includes('.') ? name : (name + '.js');

            // 5.写入文件
            fs.writeFile(`${destination}/${name}`, newData, (err) => {
                if (err) {
                    throw err;
                }
                console.log(`已经在${destination}文件夹中创建了一个文件${name}`);
            });
        }
    );
}

7.index.js 引入 generateWebComponent

index.js 是整个命令行工具的可执行入口:用户安装本包后,通过 package.json 里的 bin 配置的 generate-web-component 或 gwc 命令运行的就是这份脚本。

8.验证


相关推荐
不会聊天真君6472 小时前
pgsql笔记
数据库·笔记
Yu_Lijing2 小时前
基于C++的《Head First设计模式》笔记——MVC模式
c++·笔记·设计模式
如雨随行20202 小时前
【Vim】学习笔记(10)tips-3
笔记·学习·vim
周周不一样3 小时前
Android基础笔记1
android·笔记·gitee
星川皆无恙3 小时前
Transformer学习笔记:从 Attention 核心理论到机器翻译代码项目学习实战
大数据·pytorch·笔记·深度学习·神经网络·自然语言处理·transformer
421!3 小时前
C语言学习笔记——10(结构体)
c语言·开发语言·笔记·stm32·学习·算法
不只会拍照的程序猿3 小时前
《嵌入式AI筑基笔记04:python函数与模块01—从C的刻板到Python的灵动》
c语言·开发语言·笔记·python
1104.北光c°3 小时前
Leetcode146 LRU缓存的三种写法 【hot100算法个人笔记】【java写法】
java·开发语言·笔记·算法·leetcode·hot100·lru缓存
Hello_Embed13 小时前
嵌入式上位机开发入门(三):TCP 编程 —— Server 端实现
笔记·单片机·网络协议·tcp/ip·嵌入式