基于plop自定义前端vue脚手架,plop是生成脚手架的框架。
案例npm地址
https://www.npmjs.com/package/plop-vue-cli
一、安装依赖
- 安装plop脚手架生成框架
npm i plop --save
- 安装download-git-repo,能从git等下载代码的工具,用于下载模版。
npm i download-git-repo --save
二、上代码
- 1、plop 配置(plopfile.js)
plopfile.js文件作为低层节点模块开始其生命周期,该模块输出一个接受该plop对象作为其第一个参数的函数。
module.exports = function (plop) {
// 自定义动作类型
plop.setActionType('getTemplate', function (answers, config, plop) {
// 具体实现-省略...
console.log("下载模版中...");
return true;
});
// 注册
plop.setGenerator('CreateVue', {
// 描述
description: 'Create my vue project.',
// 交互:提问-回答
prompts: [{
type: 'input', // 输入值类型:String
name: 'projectName', // 获取输入值的key
message: 'Please input your project name.' // 问题描述
}],
// 执行操作。
actions: function(){
// 项目路径
var basePath = process.cwd() + '\\\\{{projectName}}\\\\'
return [{
// 自定义操作
type: 'getTemplate', // 执行自定义getTemplate类型 动作
speed: 'slow' // 执行操作为异步时,添加该字段值
}, {
// 新增文件操作
type: 'add', // 操作类型,(add:新增文件,addMany:新增多个文件,modify:修改文件,append:追加)
path: "./src/test.js", // 目标文件路径
templateFile: "./temp/test.hbs", // 模版文件路径
force: true, // 是否强制执行该动作,(当目标文件已存在时,true则会覆盖该文件, false则不新增 跳过)
verbose: true // 打印每个操作成功的文件路径
}]
}
});
};
plop对象公开包含setGenerator(name, config)函数的plop api对象。这是用来(等待)为该plopfile创建生成器的函数。当plop从该目录(或任何子目录)在终端上运行时,将会显示prompts这些交互列表,最终执行actions操作列表。
主要方法和参数看plop的官方文档吧
- 2、下载模版代码(plopfile.js)
模版文件代码也可以放在工程里面,但是建议还是git等平台上,便于后期维护,不至于修改一下模版就发布一次脚手架。
所有这里用到的是download-git-repo工具来从git下载模版代码。
/**
* 异步获取模版
* @param {*} path
* @param {*} callback
*/
function getTemplate(path, callback) {
// clone git代码模版,不加分支时,默认master。
download('direct:https://github.com/JumplyCode/plop-vue-cli-template.git', path, { clone: true }, callback);
}
-
3、如何编写模版
如何通过交互获取的值,进行编写模版。编写模版 plop采用的是handlebars.js模版引擎来操作,通过预编译.hbs文件来构建Web模板。
使用方法是加两个花括号{{value}}, handlebars模板会根据当前上下文自动匹配相应的数值、对象甚至是函数。
const PUBLICPATH = 'web-{{projectName}}'; // 上下文
假如交互时,projectName我输入的值是test,则编译后的模版就变成:
const PUBLICPATH = 'web-test'; // 上下文
模版生成之后就会根据actions中的类型(type),或者新增或者修改文件等等。
- plop 配置(plopfile.js)【完整】
var download = require('download-git-repo');
var rm = require('rimraf').sync;
const nodeFs = require('fs');
const cfg = require("./config");
/**
* 异步获取模版
* @param {*} path
* @param {*} callback
*/
function getTemplate(path, callback) {
// clone git代码模版,不加分支时,默认master。
download('direct:https://github.com/JumplyCode/plop-vue-cli-template.git', path, { clone: true }, callback);
}
/**
* 删除文件
* @param {String} filePath 文件路径
*/
function deleteFile(filePath) {
try {
rm(filePath);
return true;
// callback(null, `删除 ${filePath} 成功`)
} catch (e) {
return false;
}
}
/**
* 交互:询问-输入
* 1、请输入项目名称(projectName 【String】)
* 2、是否需要vuex缓存数据(isStore 【Boolean】)
* 3、是否需要用户信息(isUser 【Boolean】)
* 4、是否需要代理信息
*/
/**
* 执行动作
* 1、下载模版 并创建项目
* 2、根据填写内容,配置package.json
* 3、配置vue.config.js
* 4、配置src/main.js
* 6、清除.hbs文件
*/
module.exports = function (plop) {
// 自定义动作类型-下载模版
plop.setActionType('getTemplate', function (answers, config, plop) {
// do something
// getTemplate();
console.log("下载模版中...");
var path = process.cwd() + "\\" + answers.projectName || "vueDemo";
return new Promise((resolve, reject) => {
getTemplate(path, function (error, data) {
if (error) {
reject('模版下载失败:' + error);
} else {
resolve('下载模版完成.');
}
});
});
});
// 自定义动作类型-删除hbs文件
plop.setActionType('deleteHbs', function (answers, config, plop) {
var basePath = process.cwd() + "\\" + answers.projectName || "vueDemo";
var isStore = answers.isStore;
// var isUser = answers.isUser;
return new Promise((resolve, reject) => {
try {
var templates = cfg.templates;
// 删除hbs文件
for (var key in templates) {
var filePath = basePath + "/" + templates[key];
deleteFile(filePath);
}
// 如果不需要vuex,则删除store文件
if (!isStore) {
var storePath = basePath + "/src/store"
deleteFile(storePath);
}
//删除 package-lock.json 缓存文件
deleteFile(basePath + "/package-lock.json");
resolve('完成.');
} catch (e) {
reject('hbs模版删除:' + error);
}
});
});
// controller generator
// 注册plop
plop.setGenerator('CreateSmyVue', {
// 描述
description: 'Create smy vue project.',
// 交互
prompts: [{
type: 'input', // 输入值类型:String
name: 'projectName', // 获取输入值的key
message: 'Please input your project name.', // 问题描述
description: '输入项目名',
validate: function (input) {
// Declare function as asynchronous, and save the done callback
var done = this.async();
if(input){
if(nodeFs.existsSync(process.cwd() + '/' +input)){
done("项目名已存在")
}
done(null,true)
}else{
done("请输入项目名")
}
}
},{
type: 'input', // 输入值类型:String
name: 'projectName_ch', // 获取输入值的key
message: 'Please input your project name for Chinese.', // 问题描述
default: "项目名称",
description: '输入项目的中文名',
}, {
type: 'confirm', // 输入值类型:Boolean
name: 'isStore', // 获取输入值的key
message: 'Do you need a vuex?',
default: true,
description: '是否需要vuex(缓存)',
},{
type: 'input', // 输入值类型:Boolean
name: 'proxy',
message: 'Please enter your api proxy address.',
default: "https://www.baidu.com",
description: '输入后端接口代理地址',
}],
// 执行操作
actions: function(){
// 项目路径
var basePath = process.cwd() + '\\\\{{projectName}}\\\\'
return [{
type: 'getTemplate', // 执行自定义的类型动作
speed: 'slow'
}, {
type: 'add', // 操作类型:新增文件
path: basePath + cfg.files.packageJson, // 目标文件
templateFile: basePath + cfg.templates.packageJson, // 源文件(模版文件)
force: true, // 是否强制执行该动作,(当目标文件已存在时,true则会覆盖该文件, false则不新增 跳过)
verbose: true // 打印每个成功添加的文件路径
}, {
type: 'add',
path: basePath + cfg.files.vuConfigJs,
templateFile: basePath + cfg.templates.vuConfigJs,
force: true,
verbose: true
}, {
type: 'add',
path: basePath + cfg.files.mainJs,
templateFile: basePath + cfg.templates.mainJs,
force: true,
verbose: true
}, {
type: 'deleteHbs',
speed: 'slow'
}]
}
});
};
这时候基本完成通过命令行交互生成自己的工程了,只要在plopfile.js配置文件的目录下,执行plop命令,就可以开始生成之路了。
but,但是我想像vue-cli一样,全局安装vue-cli之后,不管在哪执行“vue create hello-world”命令都可以生成vue工程。
三、自定义脚手架成神之路
- 1、配置package.json
配置package.json,为发布npm做准备。
{
"name": "plop-vue-cli",
"version": "0.0.1",
"main": "plopfile.js",
"license": "MIT",
"keywords": [
"plop-vue-cli",
"cli",
"vue",
"plop"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"plop": "plop",
},
"author": "作者",
"description": "npm描述",
"bin": {
"create-plop-vue": "bin/index.js"
},
"dependencies": {
"download-git-repo": "^3.0.2",
"plop": "^2.7.4"
}
}
主要字段
name:上传npm后的名称
bin:定义命令行命令,执行该命令行时会执行到对应的脚本文件。命令执行:create-plop-vue,则会执行bin/index.js文件。
- 2、配置bin/index.js,使其启动plop
#!/usr/bin/env node
const args = process.argv.slice(2);
const {Plop, run} = require('plop');
const argv = require('minimist')(args);
const path = require('path');
Plop.launch({
cwd: argv.cwd,
configPath: path.resolve(__dirname, "../plopfile.js"), // 当前依赖包文件路径下的plopfile.js文件
require: argv.require,
completion: argv.completion
}, run);
npm发布
1、登录npm
npm login
2、发布代码(更新)
npm publish