基于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文件作為低層節(jié)點(diǎn)模塊開始其生命周期域帐,該模塊輸出一個(gè)接受該plop對象作為其第一個(gè)參數(shù)的函數(shù)赘被。
module.exports = function (plop) {
// 自定義動作類型
plop.setActionType('getTemplate', function (answers, config, plop) {
// 具體實(shí)現(xiàn)-省略...
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.' // 問題描述
}],
// 執(zhí)行操作。
actions: function(){
// 項(xiàng)目路徑
var basePath = process.cwd() + '\\\\{{projectName}}\\\\'
return [{
// 自定義操作
type: 'getTemplate', // 執(zhí)行自定義getTemplate類型 動作
speed: 'slow' // 執(zhí)行操作為異步時(shí)肖揣,添加該字段值
}, {
// 新增文件操作
type: 'add', // 操作類型,(add:新增文件民假,addMany:新增多個(gè)文件,modify:修改文件龙优,append:追加)
path: "./src/test.js", // 目標(biāo)文件路徑
templateFile: "./temp/test.hbs", // 模版文件路徑
force: true, // 是否強(qiáng)制執(zhí)行該動作羊异,(當(dāng)目標(biāo)文件已存在時(shí),true則會覆蓋該文件彤断, false則不新增 跳過)
verbose: true // 打印每個(gè)操作成功的文件路徑
}]
}
});
};
plop對象公開包含setGenerator(name, config)函數(shù)的plop api對象野舶。這是用來(等待)為該plopfile創(chuàng)建生成器的函數(shù)。當(dāng)plop從該目錄(或任何子目錄)在終端上運(yùn)行時(shí)宰衙,將會顯示prompts這些交互列表平道,最終執(zhí)行actions操作列表。
主要方法和參數(shù)看plop的官方文檔吧
- 2供炼、下載模版代碼(plopfile.js)
模版文件代碼也可以放在工程里面一屋,但是建議還是git等平臺上,便于后期維護(hù)袋哼,不至于修改一下模版就發(fā)布一次腳手架冀墨。
所有這里用到的是download-git-repo工具來從git下載模版代碼。
/**
* 異步獲取模版
* @param {*} path
* @param {*} callback
*/
function getTemplate(path, callback) {
// clone git代碼模版先嬉,不加分支時(shí)轧苫,默認(rèn)master。
download('direct:https://github.com/JumplyCode/plop-vue-cli-template.git', path, { clone: true }, callback);
}
-
3疫蔓、如何編寫模版
如何通過交互獲取的值含懊,進(jìn)行編寫模版。編寫模版 plop采用的是handlebars.js模版引擎來操作衅胀,通過預(yù)編譯.hbs文件來構(gòu)建Web模板岔乔。
使用方法是加兩個(gè)花括號{{value}}, handlebars模板會根據(jù)當(dāng)前上下文自動匹配相應(yīng)的數(shù)值、對象甚至是函數(shù)滚躯。
const PUBLICPATH = 'web-{{projectName}}'; // 上下文
假如交互時(shí)雏门,projectName我輸入的值是test嘿歌,則編譯后的模版就變成:
const PUBLICPATH = 'web-test'; // 上下文
模版生成之后就會根據(jù)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代碼模版宙帝,不加分支時(shí),默認(rèn)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步脓、請輸入項(xiàng)目名稱(projectName 【String】)
* 2、是否需要vuex緩存數(shù)據(jù)(isStore 【Boolean】)
* 3浩螺、是否需要用戶信息(isUser 【Boolean】)
* 4靴患、是否需要代理信息
*/
/**
* 執(zhí)行動作
* 1、下載模版 并創(chuàng)建項(xiàng)目
* 2要出、根據(jù)填寫內(nèi)容鸳君,配置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: '輸入項(xiàng)目名',
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("項(xiàng)目名已存在")
}
done(null,true)
}else{
done("請輸入項(xiàng)目名")
}
}
},{
type: 'input', // 輸入值類型:String
name: 'projectName_ch', // 獲取輸入值的key
message: 'Please input your project name for Chinese.', // 問題描述
default: "項(xiàng)目名稱",
description: '輸入項(xiàng)目的中文名',
}, {
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: '輸入后端接口代理地址',
}],
// 執(zhí)行操作
actions: function(){
// 項(xiàng)目路徑
var basePath = process.cwd() + '\\\\{{projectName}}\\\\'
return [{
type: 'getTemplate', // 執(zhí)行自定義的類型動作
speed: 'slow'
}, {
type: 'add', // 操作類型:新增文件
path: basePath + cfg.files.packageJson, // 目標(biāo)文件
templateFile: basePath + cfg.templates.packageJson, // 源文件(模版文件)
force: true, // 是否強(qiáng)制執(zhí)行該動作饭宾,(當(dāng)目標(biāo)文件已存在時(shí)批糟,true則會覆蓋該文件格了, false則不新增 跳過)
verbose: true // 打印每個(gè)成功添加的文件路徑
}, {
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'
}]
}
});
};
這時(shí)候基本完成通過命令行交互生成自己的工程了,只要在plopfile.js配置文件的目錄下徽鼎,執(zhí)行plop命令盛末,就可以開始生成之路了。
but否淤,但是我想像vue-cli一樣悄但,全局安裝vue-cli之后,不管在哪執(zhí)行“vue create hello-world”命令都可以生成vue工程石抡。
三檐嚣、自定義腳手架成神之路
- 1、配置package.json
配置package.json啰扛,為發(fā)布npm做準(zhǔn)備嚎京。
{
"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:定義命令行命令,執(zhí)行該命令行時(shí)會執(zhí)行到對應(yīng)的腳本文件隐解。命令執(zhí)行:create-plop-vue鞍帝,則會執(zhí)行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"), // 當(dāng)前依賴包文件路徑下的plopfile.js文件
require: argv.require,
completion: argv.completion
}, run);
npm發(fā)布
1摄凡、登錄npm
npm login
2、發(fā)布代碼(更新)
npm publish