这是我参与「第四届青训营 」笔记创作活动的第3天
这一篇来介绍以下脚手架的开发, 此脚手架参考了 vue-cli2 和 vue-cli3 版本, 最后以简单快速上手为依据选择只开发模板选择的功能。
自研脚手架的起因是 之前在用 vue
开发的时候, 遇到 node-sass
这个东西, 以及一些其他的包, 就是因为版本的问题导致一直报错报错, 排查了很久, 最后还是找能正常运行的项目复制粘贴解决的。 从那时起就打算做自定义脚手架了。
本来几个月前就写好了, 但当时的功能不是很完善, 直到最近 系统的学习了 webpack 之后, 就决定更新下 脚手架, 并写个博客记录下。
我的脚手架仓库
此博客以收录到我的个人博客中
大致功能
- 用户输入
wjy create <projectName>
, 准备创建项目 - 解析用户命令, 弹出交互语句, 询问以什么方式创建
- 用户选择模板后, 弹出选择什么模板
- 根据用户的选择 创建
package.json
, 主要是项目名 - 根据选择渲染模板
- 提示完成
项目目录树
|-- bin
| |-- wjy
|-- lib
|-- ConfigTransform.js
|-- Creator.js
|-- Generator.js
|-- PromptModuleAPI.js
|-- create.js
|-- promptCretor.js
|-- tplCreator.js
|-- generator
| |-- authTpl
| | |-- index.js
| | |-- template
| |-- baseTpl
| | |-- index.js
| | |-- template
| |-- reactTpl
| | |-- index.js
| | |-- template
| |-- vueTpl
| |-- index.js
| |-- template
|-- promptModules
| |-- authTpl.js
| |-- baseTpl.js
| |-- reactTpl.js
| |-- vueTpl.js
|-- utils
处理用户命令
首先我们要处理 用户输入的 wjy create <projectname>
bin/wjy 文件
#! /usr/bin/env node
const program = require("commander")
// 创建项目指令
program
.command("create <project-name>") // 增加创建指令
.description("create a new project powered by vue-cli-service") // 增加描述信息
.action((name) => {
// 没有插件选项,直接进行create name
require("../lib/create")(name);
})
program.parse(process.argv)
它注册了一个 create
命令, 并在 package.json
中添加
"bin":{
"wjy":"./bin/wjy"
}
再 npm link
, 就可以将 wjy 注册成全局指令, 之后就可以用 wjy create...了
与用户交互-询问选择什么创建项目
在 bin/create.js
中写入如下初始代码
async function create(name) {
const type = await inquirer.prompt({
name: "mode",
message: "选择功能创建项目:",
type: "list",
choices: () => [
{
name: "从模板创建",
value: "tpl",
short: "tpl",
},
],
});
console.log(type.mode)
}
这主要是用来选择通过什么方式来创建项目,我这里为了简单就只写了一个从模板创建, 接下来的就是重头戏了。
从模板中创建项目
生成选项信息
接下来我们要实现以下功能
首先看 Creator.js
和 tplCreator.js
这里是最后生成 choices 中的数组的文件. 这里定义了一个 featurePrompt
.
class Creator {
constructor() {
this.featurePrompt = [];
}
getFinalPrompts() {
const prompts = [this.featurePrompt];
return prompts;
}
}
module.exports = Creator;
tplCreator 是专门用来进行模板创建的, 它继承了Creator, 并重写了 featurePrompt
const Creator = require("./Creator");
class tplCreator extends Creator {
constructor() {
super();
this.featurePrompt = {
name: "features",
message: "选择一个模板创建项目:",
type: "checkbox",
choices: [],
};
}
}
module.exports = tplCreator;
然后, 还有一个往里面注入数据的API
module.exports = class PromptModuleAPI {
constructor(creator) {
this.creator = creator;
}
// 功能选项注入
injectFeature(feature) {
this.creator.featurePrompt.choices.push(feature);
}
};
那么,以上三个都准备好了后, 我们只要调用这个功能选项注入的API即可。 大家看 promotModules
文件夹下的文件.
这里就是实现注入每个具体模板的选项。
module.exports = (api) => {
api.injectFeature({
name: "权限认证登录模板",
value: "authTpl",
short: "authTpl",
description: "权限认证登录模板, 已经封装好动态路由添加、登录功能",
checked: false,
});
};
到这里, 我们把每个模板的信息都调用了 这个注入 API, 接下来就考虑怎么获取这里面的数据, 现在看下 create.js
if (type.mode === "tql") {
var creator = new tplCreator(); // 生成一个模板构造器的实例
// 获取获取提示语
const promptModules = getPromptModules(type.mode);
// 实现API, 注入 creator 实例
const promptAPI = new PromptModuleAPI(creator);
// 执行每个提示语, 让他们调用 injectFeature 这个功能, 使所有
// 的选项都注入到 creator 下的 `featurePrompt` 数组里
promptModules.forEach((m) => m(promptAPI));
}
// 获取提示语,通过在 promptModules 下用 require获取
function getPromptModules(mode) {
let res = null;
switch (mode) {
case "tpl":
res = ["authTpl", "baseTpl", "reactTpl", "vueTpl"].map((file) =>
require(`./promptModules/${file}`)
);
break;
default:
process.exit(1);
break;
}
return res;
}
最后使用如下代码进行选择
// 弹出提示语进行交互,获取最终prompt
const answers = await inquirer.prompt(creator.getFinalPrompts());
console.log(answers) // {features:reactTpl}
根据选择的模板生成文件
这个主要是 Generator
这个函数起作用, 这个函数这里就不直接写了, 主要是将 generator
文件下的先解析成二进制文件, 再写入给定的目录下即可。
总结
现在已经有了 vue,react,basic,auth
这个模板库的选择, 接下来的工作
- 用
vue, react
分别搭建一个后台管理系统 - 尝试自定义组件, 并在脚手架中加上选择特定组件进行创建的功能