前言
vue-cli, webpack-cli 等腳手架是不是用起來愛不釋手?自己寫了個模版每次來回復制粘貼代碼是不是很難維護?如果你是對前端、Node操作有一定的了解,同時也存在以上疑問,那就請盡情閱讀嘗試吧!
本篇文章按照al-block-cli
舉例, al-block-cli
是一個基於vue
和elementUI
而集成的一個開發模版,可安裝進行使用
依賴
- Commander.js 命令行工具
- download-git-repo git倉庫代碼下載
- chalk 命令行輸出樣式美化
- Inquirer.js 命令行交互
- ora命令行加載中效果
根據上方的依賴插件即可以看出,其實腳手架就是一個利用終端命令將倉庫中的代碼拉取到本地的工具。所以還沒有模版代碼的同學趕緊去創建個
項目准備
初始化
$ npm init
根據提示完成初始化搭建,如果不清楚如何配置可以直接回車
安裝依賴
$ npm install commander download-git-repo chalk inquirer ora --save
構建結構
創建bin
和commands
文件夾以及配置文件templates.json。bin文件夾為可執行命令入口目錄,commands則負責編寫一些命令交互
最終目錄結構
- al-block-cli
| - bin
| - commands
| - node_modules
| - package.json
| - templates.json
編寫代碼
配置文件
輸入默認需要的配置,如這里需要github
的倉庫地址和命令行的名稱
{
"init": {
"name": "init",
"path": "Alisdon/al-block-template"
}
}
入口文件
新建al-block-cli
文件,並在其第一行加入
#! /usr/bin/env node
此行為了防止操作系統用戶沒有將node裝在默認的/usr/bin路徑里。當系統看到這一行的時候,首先會到env設置里查找node的安裝路徑,再調用對應路徑下的解釋器程序完成操作。
#!/usr/bin/env node
process.env.NODE_PATH = __dirname + '/../node_modules/';
const program = require('commander');
program
.version(require('../package').version);
program
.usage('<command>');
program.command('init')
.description('create a new project')
.alias('i')
.action(() => {
require('../commands/init')
});
program.parse(process.argv);
if(!program.args.length){
program.help()
}
命令交互
新建init.js
文件表示命令init
const { prompt } = require('inquirer');
const program = require('commander');
const chalk = require('chalk');
const download = require('download-git-repo');
const ora = require('ora');
const fs = require('fs');
const option = program.parse(process.argv).args[0];
const question = [
{
type: 'input',
name: 'name',
message: 'Project name',
default: typeof option === 'string' ? option : 'al-block-template',
filter (val) {
return val.trim()
},
validate (val) {
const validate = (val.trim().split(" ")).length === 1;
return validate || 'Project name is not allowed to have spaces ';
},
transformer (val) {
return val;
}
},
{
type: 'input',
name: 'description',
message: 'Project description',
default: 'Vue project',
validate () {
return true;
},
transformer(val) {
return val;
}
},
{
type: 'input',
name: 'author',
message: 'Author',
default: '',
validate () {
return true;
},
transformer(val) {
return val;
}
}
];
module.exports = prompt(question).then(({name, description, author}) => {
const gitPlace = require('../templates').init.path;
const projectName = name;
const spinner = ora('Downloading please wait...');
spinner.start();
download(`${gitPlace}`, `./${projectName}`, (err) => {
if (err) {
console.log(chalk.red(err));
process.exit()
}
fs.readFile(`./${projectName}/package.json`, 'utf8', function (err, data) {
if(err) {
spinner.stop();
console.error(err);
return;
}
const packageJson = JSON.parse(data);
packageJson.name = name;
packageJson.description = description;
packageJson.author = author;
fs.writeFile(`./${projectName}/package.json`, JSON.stringify(packageJson, null, 2), 'utf8', function (err) {
if(err) {
spinner.stop();
console.error(err);
} else {
spinner.stop();
console.log(chalk.green('project init successfully!'))
console.log(`
${chalk.yellow(`cd ${name}`)}
${chalk.yellow('npm install')}
${chalk.yellow('npm run dev')}
`);
}
});
});
})
});
測試發布
測試
至此,一個簡單的腳手架(殼)就已經完成了,為了查看在編寫過程中是否出錯,我們現在本地進行測試
$ node bin/al-block-cli
如果沒有報錯,出現了熟悉的命令行,那就說明成功了
發布
發布之前我們需要做個小調整,觀察其他腳手架工具他們都是以自己獨特的key
值進行搭建,對此我們可以在package.json
里面配置bin
對象
"bin": {
"al-block-cli": "bin/al-block-cli"
}
這里需要注意
bin/
后面的al-block-cli
,這個路徑是由入口文件的路徑確定,如果你是建的al-block-cli.js
則此處應該配置bin/al-block-cli.js
,本篇是創建的沒有后綴名的文件
修改后生成的最終package.json
{
"name": "al-block-cli",
"version": "1.0.0",
"description": "al-block-cli",
"keywords": [
"vue",
"al-block",
"al-block-cli"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"al-block-cli": "bin/al-block-cli"
},
"preferGlobal": true,
"author": "Alisdon [920124512@qq.com]",
"license": "MIT",
"dependencies": {
"chalk": "^2.4.1",
"commander": "^2.19.0",
"download-git-repo": "^1.1.0",
"inquirer": "^6.2.1",
"ora": "^3.0.0"
}
}
對比文件內容,如果沒有問題我們就開始發布了
$ npm login
$ npm publish