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

前置知识

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);
相关推荐
前端工作日常6 分钟前
前端基建的幸存者偏差
前端·vue.js·前端框架
Electrolux14 分钟前
你敢信,不会点算法没准你赛尔号都玩不明白
前端·后端·算法
a cool fish(无名)1 小时前
rust-参考与借用
java·前端·rust
只有干货2 小时前
前端传字符串 后端比较date类型字段
前端
波波鱼દ ᵕ̈ ૩2 小时前
学习:JS[6]环境对象+回调函数+事件流+事件委托+其他事件+元素尺寸位置
前端·javascript·学习
climber11213 小时前
【Python Web】一文搞懂Flask框架:从入门到实战的完整指南
前端·python·flask
Watermelo6173 小时前
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
前端·javascript·vue.js·数据挖掘·数据分析·流程图·数据可视化
门前云梦3 小时前
ollama+open-webui本地部署自己的模型到d盘+两种open-webui部署方式(详细步骤+大量贴图)
前端·经验分享·笔记·语言模型·node.js·github·pip
Micro麦可乐3 小时前
前端拖拽排序实现详解:从原理到实践 - 附完整代码
前端·javascript·html5·拖拽排序·drop api·拖拽api
Watermelo6173 小时前
Web Worker:让前端飞起来的隐形引擎
前端·javascript·vue.js·数据挖掘·数据分析·node.js·es6