目的
同じ機能を構築し、繰り返しプロジェクトを解決するためには、ある程度必要なカスタマイズで、民営化の設定
デザイン
問題
なぜ、既製の足場の生成を使わないのでしょうか?
- あなたが使用している場合
vue
やreact
足場のプロジェクトは、プロジェクトを作成している可能性があり後でも、コンフィギュレーションのシリーズを必要とし、表示スタイルを変更し、実際に問題を解決していません。そして、唯一、自分の枠組みを生成することができます足場のそれぞれは、他のプロジェクトがサポートされていません。例えば、vue-cli
生成するreact
プロジェクトを、それは不可能です。
なぜ、ちょうど同じプロジェクトを複製しませんか?
- 既存のプロジェクト・ロジック・コードの相関が非常に強く、いくつかのコードベースのプロジェクトの環境があるかもしれない、このプロジェクトは、直接エンジニアリングプロジェクトの大量の名前を変更コピーしました。環境間違いを見つけるのは簡単ではありません。
全体的なアイデア
必要な機能を完了するには、主に二つのモジュールを実装する必要があります
- ツール --cli
- テンプレート --template
cli
:ツールとユーザーとの対話が知りたいユーザーのニーズの一部です。
template
:プロジェクトテンプレートは、あなたが自由に自分自身をカスタマイズすることができます。
するように設計
- テンプレートとツールは、それぞれが別々の維持、分離します
cli
テンプレートのレンダリング、ダウンロード、テンプレートの一覧を取得する責任を負います- テンプレートを削除するには、独自の修正を加えることができ、新しいバージョンのパッケージを再発行する必要はありません
- テンプレートにプロジェクトロジックは、テンプレートは、民営化の特性を設計することができ、
CLI作業フローチャート
アウトを設定
コードの使用がされて
typescript
実装され、プロジェクトのアドレスの特定のコードを見ることができ charmingsong-CLIを記事では、多くのコードで満たされている説明していない、それはコードの主要な機能ブロックのいくつかを記録します
ディレクトリ構造
.
├── .DS_Store
├── .eslintrc.json
├── .gitignore
├── .npmignore ├── .npmrc ├── README.md ├── cs-config.json ├── package-lock.json ├── package.json ├── src │ ├── index.ts │ ├── libs │ │ ├── inquirer.ts │ │ ├── program.ts │ │ └── tools.ts │ ├── typing.d.ts │ └── utils │ └── logger.ts ├── tsconfig.json └── yarn.lock
-
tsconfig.json
:Tsの設定ファイルは、あなたが特定の設定を学ぶために公式サイトをチェックすることができます。 -
package.json
// ... "scripts": { "build": "tsc", // 打包 "dev": "tsc -w", // 开发调试 "eslint": "eslint src --ext .ts", // eslint 检查以 .ts 为后缀的文件 // ... }, "bin": { "cs": "bin/index.js" // 全局安装(npm i -g xxx) 全局运行时执行的文件 然后全局就可以使用命令 cs }, "husky": { "hooks": { "pre-commit": "npm run eslint" // 主要是为了在提交commit的时候检测代码是否符合标准,如果感兴趣可以了解一下husky } }, // ... > [husky](https://github.com/typicode/husky)
-
src/
:コードファイルのディレクトリ-
index.ts
:マスターファイル#!/usr/bin/env node // ...
グローバル不可欠なインストールと操作に加え、ファイルの先頭に
#!/usr/bin/env node
即時実行時にこのマシンを使用するnode
環境ファイルを実行します。 -
typing.d.ts
:typescript
的描述文件,个人理解就是用来将一些没有ts
全局获取不到的包, 定义个环境提供给typescript
。 (深入学习 ts 后来补充xxx.d.ts
文件所代表的意义) -
utils/
:公共方法目录logger.ts
: 提供一个在终端输出特殊样式的方法
-
libs/
:环境工具目录
-
实现流程
项目地址已经贴出来了, 所以不讲解每个文件的代码实现逻辑
因为每个文件都是各司其职, 这里只记录主文件的实现逻辑
主文件解读
建议不懂的包自行去官网看一下,一方面不论我怎么讲解都没有官网讲解的深刻全面,另一方面我可能有的地方也不是很了解其原理本质,如果有错误的地方,欢迎指出,共同进步
-
利用
commander
包全局注册一个init
的命令import program from './libs/program' // ./libs/program文件就是对commander设置了一下基本信息,然后重命名、引入 async function commandInit(appName: string) {} program.command('init <project-name>').action((appName: string) => { commandInit(appName) }) // commander 的用法,可以设置命令行的参数 // 当用户输入 之前 cs init xxx 的时候 // cs ==> package.json文件的设置的环境变量 我设置名称是 cs // init ==> 是 cs 后面带的命令, 这里设置的是 init // xxx ==> 这里是指文件名,是用户输入的参数,此处用法 commander 包有关, 建议仔细看一下用法 // commandInit ==> 如果用户输入命令是 init 时所执行的函数。 program.parse(process.argv) // 将node的环境变量给 program ,简单来说就是将终端参数交个 commander 来解析 if (!process.argv.slice(2).length) { program.outputHelp() } // 这里是对 cs 命令的 提示帮助, 如果用户在终端只输入 cs ,而不输入命令 那么展示 提示信息
-
实现定义的命令函数 commandInit
import { join } from 'path' import { existsSync, mkdirSync } from 'fs' import Logger from './utils/logger' // 在终端输出信息,可以捕捉错误 import { downTemplate, // 下载模板方法 getMetaJson, // 下载需要的初始json文件方法 writeTemplate // 渲染文件方法 } from './libs/tools' // ./libs/tools 是方法库,具体的代码实现可以参考源代码。 import prompt from './libs/inquirer' // inquirer封装,终端交互的工具 import { metaName } from '../cs-config.json' // 获取 inquirer 所需要初始化的json信息,也就是最开始提问的json async function commandInit(appName: string) { const targetDir = join(process.cwd(), appName) // 查看目标目录是否存在 existsSync(targetDir) ? Logger.fatal('The current directory already exists --> %s ', appName) : mkdirSync(targetDir) // 存在就对用户,输出错误提示:目录存在, 如果不存在,就创建用户所输入的名称的文件夹 const baseInfo: MetaInfoMust = await prompt(await getMetaJson()) // 获取 模板列表的json 提供给 prompt,来和用户进行交互 const { template } = baseInfo // 获取用户选择的模板信息 const templatePath = (await downTemplate(template)) as string Logger.success('template download success!') // 下载目标模板到本地, 并提示成功信息 const templateMetaPath = join(templatePath, metaName) const templateMetaInfo = existsSync(templateMetaPath) ? await prompt(require(templateMetaPath)) : {} // 如果模板中需要自定义设置, 读取配置,在和用户交互 const metaInfo = { ...baseInfo, ...templateMetaInfo } // 获取两次的交互所得的用户信息 await writeTemplate(templatePath, metaInfo, targetDir) Logger.success('success ok!') // 根据获取的用户自定义信息,向开始创建的目标目录写入、渲染模板并提示成功信息 process.exit(1) // 退出命令程序 }
模板的设计
模板类型是根据github纪录的模板类型
模板类型以
cs-templates-xxx
格式命名,可用模板列表可自行查看本项目master_meta
分支
模板开发规则
可自行添加模板
目录
.
├── README.md
├── meta.json
└── template
模板写入利用 handlebars
,
例如:
{
"name": "{{projectName}}",
"version": "{{version}}",
"description": "{{description}}" }
默认交互
模板名称--template
项目名称--projectName
简介描述--description
版本--version
自定义交互
可以自行配置
meta.json
,依据inquirer
语法配置, 自动解析。
例如:
[
{
"name": "testname",
"type": "input",
"message": "测试", "default": "test" } ]
结语
设计这个脚手架大部分是为了锻炼自己的编程思想,写这篇文章也是为了能在提升自己的语言组织能力的同时帮助到小伙伴们。 个人网站也是用这个 cli
中的 基于vue-ssr
模板搭建的, 有兴趣的可以看一下个人网站。