前置知识
Shell、CMD、Bash的区别

Shell 是计算机操作系统中的一个用户界面,用于让用户与操作系统进行交互。它是一个命令行解释器,接收用户输入的命令,解释并执行这些命令,然后将结果返回给用户。 Shell 分为两种方式:
GUI:(Graphical User Interface)是图形用户界面,它可以在计算机屏幕上显示图形界面,让用户与计算机进行交互。- 文件管理器:用户可以查看、创建、修改和删除文件。
CLI:(Command Line Interface)是命令行界面,它使用命令行来与计算机进行交互,命令行界面通常使用文本输入和输出。CMD:是Windows操作系统的默认命令行界面,它提供了许多命令来管理文件和目录,执行程序,启动应用程序等。- 在
CMD窗口中输入cnpm命令,优先在当前目录下寻找 是否存在cnpm.cmd文件
- 在
Bash:是Linux和macOS操作系统的默认命令行界面,它提供了许多命令来管理文件和目录,执行程序,启动应用程序等。
Windows 和 Linux 执行 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包

- 打开
cmd命令行窗口 - 输入
npm install -g cnpm - 下载
cnpm包到全局nodejs的node_modules目录下 - 扫描
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包

- 输入
cnpm --version命令 - 在当前目录查找是否存在
cnpm.cmd文件 - 在
Path全局环境变量所有目录路径中查找是否存在cnpm.cmd文件 - 执行
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);