如何开发一个Vue脚手架
实现一个脚手架之前我们必须知道什么是脚手架?通俗来说脚手架就是帮我们自动完成一些重复做的内容,比如大名鼎鼎的Vue脚手架Vue-Cli,只需要执行一行代码就能帮我搭建好Vue环境的项目,它帮我们自动创建了一个Vue的开发环境项目,我们不需要每次都自己搭建环境了。
脚手架做了哪些事?
Vue-Cli脚手架帮我们做了哪些事呢?我认为它做了三件事:
- 接受用户输入的信息
- 创建项目
package.json并且安装依赖 - 创建空项目(可以理解为:复制预先配置好的项目文件)
使用Yeoman开发脚手架
Yeoman是一个社区热门的搭建工具链的一个库。具体内容就不介绍了,移步官方地址 Yeoman
为什么要使用Yeoman
Yeoman提供现成的命令行交互,模板文件复制,npm相关操作,为工具链为生的库,当然你也可以通过node来实现这些功能。
搭建脚手架项目环境
创建项目
新建项目generator-vue-cli,进入目录执行npm init,项目名必须generator开头,vue-cli为脚手架名字
安装yo:
npm install yeoman-generator --save-dev
npm install -g yo
目录结构
在generator-vue-cli目录下新建:
├───package.json
└───generators/
├───app/
│ └───index.js
└───templates/
必须按照上面目录结构创建文件
编写构建逻辑
app/index.js是构建脚手架的入口文件,编写以下代码:
var Generator = require('yeoman-generator');
module.exports = class extends Generator {
method1() {
this.log('step 1');
}
method2() {
this.log('step 2');
}
};
在项目目录下执行npm link后再非项目目录下执行yo vue-cli执行我们的脚手架.
我们发现方法是从上往下依次执行的,看到这个效果后我们接着之前的思路完成脚手架开发,首先定义三个方法:
var Generator = require('yeoman-generator');
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.answers = null;
}
// 1.获取用户输入信息
async getUserEnter() {
}
// 2.安装相关依赖创建package.json
async installPackage() {
}
// 3.复制模板文件
async copyTemplateFiles() {
}
};
接受用户输入的信息
`Yeoman`提供了`prompt`方法来在命令行交互:
// 1.获取用户输入信息
async getUserEnter() {
// 获取用户输入的项目名
const answers = await this.prompt([
{
type: "input",
name: "name",
message: "Your Vue project name",
}
]);
/// 保存用户输入的信息
this.answers = answers;
this.destinationRoot(this.answers.name);
}
运行效果:
this.destinationRoot配置目根目录.
创建项目package.json并且安装依赖
// 2.安装相关依赖创建package.json
async installPackage() {
const pgkJSON = {
name: this.answers.name,
version: "1.0.0",
main: "./src/index.js",
license: "ISC",
scripts: {
build:"webpack",
watch: "webpack --watch",
dev: "webpack-dev-server --open"
},
devDependencies: {
"webpack": "^4.35.2",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2"
},
dependencies: {
}
};
// 创建package.json
this.fs.extendJSON(this.destinationPath('package.json'), pgkJSON);
// 安装依赖 相当于执行了npm install 会安装package.json配置的包
this.npmInstall();
// 安装指定包 相当于执行了npm install vue
this.npmInstall(["vue"], { "save-dev": false });
// 安装指定包 相当于执行了npm install xxx --save-dev
this.npmInstall(
["@babel/core", "@babel/preset-env", "babel-loader", "css-loader", "html-webpack-plugin", "style-loader", "vue-loader", "vue-template-compiler"],
{ "save-dev": true }
);
}
复制模板文件
在templates准备好了我们的项目模板文件:
模板文件就是已经搭建好的基于webpack的Vue开发环境。
复制模板文件也很简单:
// 3.复制模板文件
async copyTemplateFiles() {
this.fs.copyTpl(
this.templatePath('public/index.html'),
this.destinationPath('public/index.html'),
{
title: this.answers.name
}
);
this.fs.copyTpl(
this.templatePath('src/main.js'),
this.destinationPath('src/main.js'),
);
this.fs.copyTpl(
this.templatePath('src/App.vue'),
this.destinationPath('src/App.vue'),
);
this.fs.copyTpl(
this.templatePath('src/components/HelloWorld.vue'),
this.destinationPath('src/components/HelloWorld.vue'),
);
this.fs.copyTpl(
this.templatePath('webpack.config.js'),
this.destinationPath('webpack.config.js'),
);
}
copyTpl接受两个参数,一个是模板文件路径和复制到项目的路径。
完整代码
var Generator = require('yeoman-generator');
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.answers = null;
}
// 1.获取用户输入信息
async getUserEnter() {
// 获取用户输入的项目名
const answers = await this.prompt([
{
type: "input",
name: "name",
message: "Your Vue project name",
}
]);
this.answers = answers;
this.destinationRoot(this.answers.name);
}
// 2.安装相关依赖创建package.json
async installPackage() {
const pgkJSON = {
name: this.answers.name,
version: "1.0.0",
main: "./src/index.js",
license: "ISC",
scripts: {
build:"webpack",
watch: "webpack --watch",
dev: "webpack-dev-server --open"
},
devDependencies: {
"webpack": "^4.35.2",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2"
},
dependencies: {
}
};
// 创建package.json
this.fs.extendJSON(this.destinationPath('package.json'), pgkJSON);
this.npmInstall();
this.npmInstall(["vue"], { "save-dev": false });
this.npmInstall(
["@babel/core", "@babel/preset-env", "babel-loader", "css-loader", "html-webpack-plugin", "style-loader", "vue-loader", "vue-template-compiler"],
{ "save-dev": true }
);
}
// 3.复制模板文件
async copyTemplateFiles() {
this.fs.copyTpl(
this.templatePath('public/index.html'),
this.destinationPath('public/index.html'),
{
title: this.answers.name
}
);
this.fs.copyTpl(
this.templatePath('src/main.js'),
this.destinationPath('src/main.js'),
);
this.fs.copyTpl(
this.templatePath('src/App.vue'),
this.destinationPath('src/App.vue'),
);
this.fs.copyTpl(
this.templatePath('src/components/HelloWorld.vue'),
this.destinationPath('src/components/HelloWorld.vue'),
);
this.fs.copyTpl(
this.templatePath('webpack.config.js'),
this.destinationPath('webpack.config.js'),
);
}
};
使用脚手架
在非当前脚手架目录下执行yo vue-cli,输入项目名vue-demo:
在vue-demo运行项目npm run dev:
发布脚手架
发布到npmnpm publish,发布之前需要先登录npm adduser,注意如果存在同名的库会发布失败
模板文件地址
本篇文章只是简单介绍如何开发一个脚手架思路,整个代码非常简单。如需要增加一些复杂功能,例如想要做到像vue-cli这么强大还有很多需要功能完善,例如复杂的命令行交互,下载进度条的支持等。