1. 脚手架定义
脚手架是为了保证各施工过程顺利进行而搭设的工作平台。对我们前端程序员来说,可以帮我们更好,更高效地进行编码工作。
2. 脚手架的常用命令
- 首先我们先建一个工程:bob_cli,进行bob_cli文件夹执行npm init 进行工程初始化,再创建一个lib文件夹和index.js文件
- 安装commander包,用来解析控制台输入的指令,去npm 里面进行搜素,有详细说明
- 自定义执行入口文件,如下图,以后可以用bob来代替index.js。然后npm link 使bob能进行相关映射
4.在index.js里面编写如下代码
index.js
#!/usr/bin/env node
const { program } = require("commander");
const { helpOptions } = require("./lib/core/help");
//获取版本号
program.version(require("./package.json").version);
helpOptions();
//解析控制台的指令
program.parse(process.argv);
./lib/core/help.js
const { program } = require("commander");
//自定义选项
const helpOptions = () => {
program.option("-s, --small", "small pizza size");
program.option(
"-d --dest <dest>",
"a destination folder, like: -d /src/components"
);
//还可以自定义事件监听
program.on("--help", function () {
console.log("");
console.log("Other:");
console.log(" other options~");
});
};
- 在控制台输入 bob --help, bob --V看到下面输出信息,就成功了。有些选项还没做,后面有需求可以完善。
Options:
-V, --version output the version number
-s, --small small pizza size
-d --dest <dest> a destination folder, like: -d /src/components
-h, --help display help for command
Other:
other options~
commaner -V
1.0.0
3. 脚手架做的事情
比如我们常用的vue-cli。当我们敲下 vue-cli create project,它会帮我们做好哪些事情呢?
- 用户选择需要的配置项,像常用的 vue-router,vuex,css 预处理器等。
- 安装所需依赖到工程环境。
- 进入npm run serve 启动项目。
- 打开浏览器输入网址。
现在我们从这4个步骤一个个来配置
- 现在我们省去用户交互选择配置的过程,直接定制一个配置好的通用的模板,此时需要安装download-git-repo包。地址:gitlab.com/flippidippi…
- 解析控制台命令,例如bob create demo01,我们要创建一个demo01文件夹,并将下载好的模板文件放进去
bob_cli\lib\core\action.js
//create project
program
.command("create <project> [others...]")
.description("clone a repository into a newly created directory")
.action(createProjectAction);
bob_cli\lib\core\action.js
//callBack ==> promisify ===>promise ==> async/await
const createProjectAction = async (project) => {
//1.克隆项目
await download(vueRepo, project, { clone: true });
// 2.执行npm install
//兼容windows
const command = process.platform === "win32" ? "npm.cmd" : "npm";
await commandOptions(command, ["install"], { cwd: `${project}` });
//3.启动serve
await commandOptions(command, ["run", "serve"], { cwd: `${project}` });
//4.打开浏览器
open("http://localhost:8080");
};
bob_cli\lib\config\repo-config.js
//注意这里分为三段:direct+git http的地址+#分支名称
//这里拿coderwhy老师的vue模板来演示下
let vueRepo = 'direct:https://github.com/coderwhy/hy-vue-temp.git#master';
module.exports = {
vueRepo,
};
bob_cli\lib\utils\terminal.js
/**
* 执行终端命令相关的代码
*/
//开启子进程
const { spawn } = require("child_process");
const commandOptions = (...args) => {
return new Promise((resolve, reject) => {
console.log("ready to create project ");
const childProcess = spawn(...args);
//将子进程的输出信息输出到当前控制台
childProcess.stdout.pipe(process.stdout);
childProcess.stderr.pipe(process.stderr);
//监听子进程执行完了
childProcess.on("close", (code) => {
console.log(`child process exited with code ${code}`);
resolve()
});
});
};
- 打开浏览器所需的包执行 npm install open就可以了。
- 需要注意 启动serve那段代码,需要根据package.json里的script 运行命令一致
- 最后可以看到拉取下来的demo01工程目录,浏览器也自动打开
4. 自动生成组件和路由文件
4.1 生成组件
- 此时我们要用到ejs包,来解析ejs语法。npm i ejs
- 准备好组件模板vue-component.ejs
bob_cli\lib\templates\vue-component.ejs
<template>
<div class="<%= data.lowerName %>">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: '<%= data.name %>',
props: {
msg: String
},
components: {
},
mixins: [],
data: function() {
return {
message: "<%= data.name %>"
}
},
created: function() {
},
mounted: function() {
},
computed: {
},
methods: {
}
}
</script>
<style scoped>
.<%= data.lowerName %> {
}
</style>
bob_cli\lib\core\create.js
program
.command("addcpn <name>")
.description(
"add vue component, like:addcpn HelloWorld [-d src/components]"
)
.action((name) => {
const options = program.opts();
addCpnAction(name, options.dest || "src/components");
});
bob_cli\lib\core\action.js
const addCpnAction = async (name, dest) => {
//1.编译ejs模板 result
const result = await compile("vue-component.ejs", {
name,
lowerName: name.toLowerCase(),
});
console.log(result);
//2.写入文件夹
//没有就创建。
if (createDirSync(dest)) {
const targetPath = path.resolve(dest, `${name}.vue`);
writeToFile(targetPath, result);
}
};
bob_cli\lib\utils\utils.js
//解析组件模板 成字符串,然后写入目标文件夹中
const compile = (templateName, data) => {
const fileOption = `../templates/${templateName}`;
const filePath = path.resolve(__dirname, fileOption);
return new Promise((resolve, reject) => {
ejs.renderFile(filePath, { data }, {}, (err, str) => {
if (err) {
reject(err);
return;
}
resolve(str);
});
});
};
const writeToFile = (path, content) => {
return fs.promises.writeFile(path, content);
};
/**
* 递归创建不存在的文件夹
* @param {路径名 包含后缀的文件} pathName
* @returns
*/
const createDirSync = (pathName) => {
if (fs.existsSync(pathName)) {
return true;
} else {
if (createDirSync(path.dirname(pathName))) {
fs.mkdirSync(pathName);
return true;
}
}
}
- 进入demo01文件夹,运行bob addcpn goods -d pages/goods,可以看到demo01下生成pages,并且里面的ejs模板全部替换为了组件名字
4.2 生成模块文件夹及模块路由文件
- 思路跟上面生成组件差不多。先准备router的ejs模板
bob_cli\lib\templates\vue-router.ejs
// 普通加载路由
// import <%= data.name %> from './<%= data.name %>.vue'
// 懒加载路由
const <%= data.name %> = () => import('./<%= data.name %>.vue')
export default {
path: '/<%= data.lowerName %>',
name: '<%= data.name %>',
component: <%= data.name %>,
children: [
]
}
bob_cli\lib\core\create.js
program
.command("addpage <page>")
.description(
"add vue page and router config, like: why addpage Home [-d src/pages]"
)
.action((page) => {
const options = program.opts();
addPageRouteAction(page, options.dest || "src/pages");
});
bob_cli\lib\core\action.js
//b.创建文件加及路由
const addPageRouteAction = async (name, dest) => {
//1.编译ejs模板 result
const pageResult = await compile("vue-component.ejs", {
name,
lowerName: name.toLowerCase(),
});
const routerResult = await compile("vue-router.ejs", {
name,
lowerName: name.toLowerCase(),
});
//将目标文件夹和组件文件夹做一个拼接。
const targetPath = path.resolve(dest, name.toLowerCase());
//先判断是否有文件夹,没有就创建、、
if (createDirSync(targetPath)) {
//2.写入文件夹
//program.dest可以获取到终端的<dest>
const targetPagePath = path.resolve(targetPath, `${name}.vue`);
const targetRouterPath = path.resolve(targetPath, "router.js");
writeToFile(targetPagePath, pageResult);
writeToFile(targetRouterPath, routerResult);
}
};
bob_cli\lib\utils\utils.js
//解析组件模板 成字符串,然后写入目标文件夹中
const compile = (templateName, data) => {
const fileOption = `../templates/${templateName}`;
const filePath = path.resolve(__dirname, fileOption);
return new Promise((resolve, reject) => {
ejs.renderFile(filePath, { data }, {}, (err, str) => {
if (err) {
reject(err);
return;
}
resolve(str);
});
});
};
/**
* 递归创建不存在的文件夹
* @param {路径名 包含后缀的文件} pathName
* @returns
*/
const createDirSync = (pathName) => {
if (fs.existsSync(pathName)) {
return true;
} else {
if (createDirSync(path.dirname(pathName))) {
fs.mkdirSync(pathName);
return true;
}
}
}
const writeToFile = (path, content) => {
return fs.promises.writeFile(path, content);
};
- 控制台输入命令bob addpage register -d src/views/pages 看输出结果,这样不用再一个个模块再手动注册路由和组件
4.3 生成vuex模块
过程如4.2一致。就不重复粘贴代码。
5. 打包发布到NPM
- 先到官网注册 npm账号
- 在vscode中对发布的包进行配置
//发布的包名
"name": "bobvue_cli",
"version": "1.0.0",
"description": "a ",
"main": "index.js",
"bin": {
//脚手架命令
"bobvue_cli": "index.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "bob",
//算所算法关键字
"keywords": ["vue-cli","vue","vue-template","vue3"],
//github所在仓库
"homepage": "https://github.com/xiaoboRao/bobvue_cli",
"repository": {
"type": "git",
"url": "https://github.com/xiaoboRao/bobvue_cli"
},
- 在vscode发布包,执行npm login,输入注册的账号,密码,邮箱,第一次登陆时会提示OTP,npm会发送一个验证码到注册邮箱,输入即可登陆了
- 接下来去npm下载这个包,验证下,最终结果在预想之中。
6. 附上GitHub地址和npm地址
GitHub:[https://github.com/xiaoboRao/bobvue_cli](bobvue_cli)
npm:[https://www.npmjs.com/package/bobvue_cli](bobvue_cli)