NodeJS: 从零开始做一个类似vue-cli的简单脚手架

1.安装node

你需要安装node。安装好后可以通过 node -v 查看node版本。

2.创建文件与初始化

我用的是Mac(windows同理),在终端,任意目录下,执行下面命令:

mkdir my-cli
cd my-cli
npm init -y

3.创建项目结构

mkdir bin script docs
touch index.js REDEAD.md bin/my-cli.js script/init.js

4.安装必要包

npm install chalk co-prompt co commander download-git-repo inquirer ora --save-dev

包说明:
download-git-repo
commander
chalk
co-prompt
co
inquirer
ora

5.修改package.json

在package.json文件中加入bin命令

{
  "name": "my-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "bin": {
    "my-cli": "./bin/my-cli.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chalk": "^4.1.0",
    "co": "^4.6.0",
    "co-prompt": "^1.0.0",
    "commander": "^7.1.0",
    "download-git-repo": "^3.0.2",
    "inquirer": "^8.0.0",
    "ora": "^5.4.0"
  }
}

6.其他辅助文件配置

新建 .editorconfig.gitignore等文件

touch .editorconfig .gitignore .npmrc

.editorconfig

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

.gitignore

.DS_Store
node_modules
/dist

# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

.npmrc

save-exact=true

至此,项目结构如下:

项目结构

7.编写内容

bin/my-cli.js 是主文件,作为整个脚本运行的入口。

index.js我们作为主要内容文件。

bin/my-cli.js

#!/usr/bin/env node
require('../index')

注意:文件开头需要加上 #! /usr/bin/env node,用来说运行环境。

index.js


const {
    resolve
} = require("path")
const program = require("commander")
const packageJson = require("./package.json")

const res = command => resolve(__dirname, 'script/', command)

process.env.NODE_PATH = __dirname + "/node_modules"

console.log(process.env.NODE_PATH, res("init"))

program
    .version(packageJson.version)

program
    .usage("<command>")

program
    .command("init")
    .description("Generate a new node project")
    .alias("i")
    .action(() => {
        require(res("init"))
    })

program.parse(process.argv)


// 判断终端上输入出来bin中的命令是否还有其他值,如果没有终端会直接输出help
if (!program.args || program.args.length === 0) {
    program.help()
}

script/init.js是运行 my-cli init时,执行的内容,如下:

const inquirer = require("inquirer");
const program = require("commander");
const chalk = require("chalk");
const download = require("download-git-repo");
const ora = require("ora");
const spinner = ora("Downloading please wait......");
const fs = require("fs");
const path = require("path");
const option = program.parse(process.argv).args[0];
const defaultName = typeof option === "string" ? option : "my-app";

const questionList = [{
  type: 'input',
  name: 'Project name',
  message: 'Project name',
  default: defaultName,
  filter(val) {
    return val.trim()
  },
  validate(val) {
    const validate = (val.trim().split(" ")).length === 1
    return validate || 'Project name is not allowed to have spaces ';
  },
  transformer(val) {
    return chalk.blue(val);
  }
}, {
  type: 'input',
  name: 'description',
  message: 'Project description',
  default: '这是一个项目',
  validate(val) {
    return true;
  },
  transformer(val) {
    return chalk.blue(val);
  }
}, {
  type: 'input',
  name: 'author',
  message: 'Author',
  default: 'author',
  validate(val) {
    return true;
  },
  transformer(val) {
    return chalk.blue(val);
  }
}, {
  type: "list",
  name: "program type",
  message: "程序类型",
  choices: [
    "Nodejs",
    "Typescript"
  ],
  default: "nodejs",
  filter: function(val) {
    return val.toLowerCase();
  }
}]

// 根据用户选择的语言去配置对应的配置文件
inquirer.prompt(questionList).then(answers => {
  console.log(answers)
  spinner.start();
  setTimeout(() => {
    spinner.stop();
    console.log(chalk.red("项目初始化成功"));
  }, 500)
})

8.调试

在运行代码时,需要本地调试,可通过下面命令的形式调试。

node ./bin/my-cli.js

例:

node ./bin/my-cli.js

9.全局安装

我们进入npm全局安装的文件里:

cd /usr/local/lib/node_modules

注意:我的是mac,如果你是window此方式不能进去,你需要自己寻找一下具体目录。

我们可以看到目前我们全局安装的npm包,如下:

全局已经安装的npm包

在我们 my-cli 目录下执行:

npm install -g

每当你修改内容时,需要再次npm install -g,否则内容将不会生效

这时,我们可以看到全局安装npm包的目录下多了我们的脚手架:

/usr/local/lib/node_modules

然后,我们找到任意目录执行:

my-cli

就可以看到命令行对于我们脚手架的提示了:

my-cli

然后我们执行我们的脚手架的安装命令:

my-cli init
my-cli init

由于本程序最后我只是做个简单的输出演示操作,故此没有任何文件产生。

10.将编写好的cli发布到npm中

参考:发布一个 npm 包,构建自己的第三方库

11.cli脚手架的使用

命令行输入my-cli查看帮助

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342