【记一忘三二】脚手架学习

前置知识

ShellCMDBash的区别

Shell 是计算机操作系统中的一个用户界面,用于让用户与操作系统进行交互。它是一个命令行解释器,接收用户输入的命令,解释并执行这些命令,然后将结果返回给用户。 Shell 分为两种方式:

  • GUI(Graphical User Interface)是图形用户界面,它可以在计算机屏幕上显示图形界面,让用户与计算机进行交互。
    • 文件管理器:用户可以查看、创建、修改和删除文件。
  • CLI(Command Line Interface)是命令行界面,它使用命令行来与计算机进行交互,命令行界面通常使用文本输入和输出。
    • CMD:是 Windows 操作系统的默认命令行界面,它提供了许多命令来管理文件和目录,执行程序,启动应用程序等。
      • CMD 窗口中输入 cnpm 命令,优先在当前目录下寻找 是否存在 cnpm.cmd 文件
    • Bash:是 LinuxmacOS 操作系统的默认命令行界面,它提供了许多命令来管理文件和目录,执行程序,启动应用程序等。

WindowsLinux 执行 js文件的区别

Windows

通过 cmd 可执行文件执行js文件

Linux

通过 \#!/usr/bin/env node 用指定脚本的解释器

bash 复制代码
#!/usr/bin/env node
js 复制代码
#!/usr/bin/env node

console.log(22)

Windows 使用全局使用 npm包

如何全局安装 npm包

  1. 打开 cmd 命令行窗口
  2. 输入 npm install -g cnpm
  3. 下载 cnpm 包到全局 nodejsnode_modules 目录下
  4. 扫描 package.json 文件,判断是否存在 bin 属性
    • 如果存在 bin 属性

      json 复制代码
      {
        "bin": {
          "cnpm": "bin/cnpm.js"
        }
      }
      • nodejs 文件夹创建 cnpm.cmd 文件 、 cnpm 文件

      • cnpm.cmd 文件 :由于在 Windows 系统下,无法直接运行 js 文件,所以需要创建一个 cmd 文件,将 node 运行 js 文件的命令写入 cmd 文件中

        判断 nodejs 文件夹下是否存在 node.exe 文件,如果存在,则使用 node.exe 执行 cnpm.js 文件,否则通过 node 命令在全局环境中寻找 node.ext 执行 cnpm.js 文件

      • cnpm 文件:软链接至 cnpm.cmd 文件,主要方便用户输入 cnpm 命令时,通过cnpm文件软链接至cnpm.cmd 文件,如何执行 cnpm.cmd 文件。 测试得知:在 CMD 窗口输入 cnpm 命令时,并不会通过 cnpm 文件寻找 cnpm.cmd 文件,而是会直接执行 cnpm.cmd 文件,所以在 CMD 窗口cnpm 文件没有意义。cnpm 文件的存在是为了做兼容处理,有些 Shll 窗口支持通过 cnpm 文件软链接至 cnpm.cmd 文件(暂未发现)。

如何执行全局 npm包

  1. 输入 cnpm --version 命令
  2. 在当前目录查找是否存在 cnpm.cmd 文件
  3. Path 全局环境变量所有目录路径中查找是否存在 cnpm.cmd 文件
  4. 执行 cnpm.cmd 文件,在 cnpm.cmd 文件中,通过 node 命令执行 cnpm.js 文件`

脚手架的入门

自定义命令安装至全局

js 复制代码
#!/usr/bin/env node

console.log(222)
json 复制代码
{
  "name": "hc",
  "version": "1.0.0",
  "bin": {
    "hc": "./bin/index.js"
  }
}
shell 复制代码
# 安装全局脚手架
npm link

# 卸载全局脚手架
npm uninstall hc -g

在执行npm link命令时,需要控制台进入项目目录

脚手架尝试

原生实现

js 复制代码
#!/usr/bin/env node

const process = require('node:process')
const packageJson = require('../package.json')

const command = process.argv[2]

// 全局选项
if (/^(--|-)/.test(command)) {
  const option = command.replace(/(--|-)/, '')
  if (['v', 'V', 'version'].includes(option)) {
    console.log(`版本号:${packageJson.version}`)
  }
}
else {
  if (command === 'init') {
    let [option, value] = process.argv.slice(3)
    option = option.replace(/(--|-)/, '')
    console.log(`项目初始化:${value}`)
  }
}

yargs

js 复制代码
#!/usr/bin/env node

import process from 'node:process'
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'


const cli = yargs(hideBin(process.argv))

cli
    .scriptName('hc')
    .strict()
    .wrap(cli.terminalWidth())
    .version('0.0.1')
    .help()
    .usage('hc [命令] [参数] [选项]')
    .command({
        command: 'init <name>',
        describe: '初始化项目',
        builder: (yargs) => {
            return yargs
                .usage('hc init  [参数] [选项]')
                .positional('name', {
                    describe: '项目名称',
                    type: 'string',
                    demandOption: true,
                })
                .option('force', {
                    alias: 'f',
                    describe: '强制覆盖同名项目',
                    type: 'boolean',
                    default: false,
                })
                .version(false)
        },
        handler({ name, force }) {
            if (force) {
                console.log('强制覆盖同名项目')
            }
            console.log(`初始化项目:${name}`)
        },
    })
    .option('debug', {
        describe: '开启调试模式',
        type: 'boolean',
        default: false,
        alias: 'd',
    })
    .alias('h', 'help')
    .alias('v', 'version')
    .group(["help", "version", "debug"], "全局选项")
    .demandCommand(1, '请输入命令')
    .fail((msg, error) => {
        if (error) {
            throw error
        }
        console.error(msg)
        process.exit(1)
    })
    .argv

commander

js 复制代码
import process from 'node:process';
import { Command } from 'commander';

const program = new Command();

program
    .name('hc')
    .version('0.0.1', "-V,--version", "显示版本号")
    .option('-d, --debug', '是否显示调试信息')
    .helpOption('-h, --help', '显示帮助信息')
    .description("一个用于快速创建项目模板的命令行工具")


program
    .command("init")
    .argument("[projectName]", "项目名")
    .option("-f, --force", "是否强制初始化")
    .description("初始化项目")
    .action((projectName, options) => {
        if (options.force) {
            console.log("强制初始化项目");
        }
        console.log("初始化项目:", projectName);
    })


const serveProgram = new Command("serve");

serveProgram
    .description("服务管理")

serveProgram
    .command("start")
    .argument("[port]", "端口号", 3000)
    .description("启动项目")
    .action((port) => {
        console.log("启动服务,端口号:" + port);
    });


program
    .command("install", "下载依赖", {
        executableFile: "./install.js",
        hidden: true
    })
    .alias("i")


program
    .argument("<command>", "默认命令")
    .action((command) => {
        console.log("执行命令:" + command);
    });

program.addCommand(serveProgram);
program.parse(process.argv);
相关推荐
GISer_Jing2 小时前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪3 小时前
CSS复习
前端·css
咖啡の猫5 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲7 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5818 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路8 小时前
GeoTools 读取影像元数据
前端
ssshooter9 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
Jerry9 小时前
Jetpack Compose 中的状态
前端
dae bal10 小时前
关于RSA和AES加密
前端·vue.js
柳杉10 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化