上一篇文章写了一下joao-cli的基本思路,部分同窗反应看不懂,此次直接带你们手写一个本身的cli工具,能够实现前端
步骤会给出对应gif图,图不动的话建议右键新链接打开.
vue
1.初始化npm并安装对应依赖.node
// 新建一个文件夹用以存储cli工具, 当前目录打开命令行
npm init
package name 输入你的cli name
能够一路回车跳过剩下内容...
复制代码
2.注册node.jsgit
在当前目录新建command.js 写上
#! /usr/bin/env node
console.log('执行了command脚本')
// 登记以上内容, 使command.js能够被node执行
// 而后在packge.json里添加 "bin": { "joao": "./command.js" }
{
"name": yourcli", "version": "0.0.1", "description": "快速搭建前端整站, 工程化自动开发", "main": "command.js", "dependencies": {}, "devDependencies": {}, "bin": { "joaocli": "./command.js" } } // 当前路径打开命令行工具 键入npm link, 声明环境变量 npm link // 成功后, 键入joaocli 会提示脚本 joaocli ... 执行了command脚本 复制代码
3.安装要用到的依赖github
安装依赖 | 安装目的 |
---|---|
commander | 命令行工具 |
fs | 用来处理文件 |
git-clone | 用来从git托管地址下载你的文件 |
inquirer | 命令行中可使用对话或者选项了 |
path | 用来处理路径 |
shelljs | 用来执行shell |
tracer | 用来花式打log |
安装方法: pageage.json所在目录, npm install ${对应的依赖名称}
web
npm install commander
npm install fs
...
复制代码
作好准备工做后(安装完全部依赖!), 你已经拥有了可执行的脚本, 如今咱们要一一完善各项功能
shell
//修改command.js
#! /usr/bin/env node
console.log('执行了command脚本')
const commander = require('commander');
const inquirer = require('inquirer');
const questions = [
{
type: 'input',
name: 'projectName',
message: '请为项目命名',
filter: function(val) {
return val;
}
},
{
type: 'list',
name: 'type',
message: '请选择使用的模板',
choices: ['empty-vue-template', '模板2', '模板3'],
filter: function(val) {
return val.toLowerCase();
}
}
]
// 新建项目 拉取模板
commander
.command('init')
.description('用来初始化项目, 拉取模板')
.action(() => {
console.log('正在构建...')
inquirer.prompt(questions)
.then(answers => {
console.log('answers', answers)
})
})
// 此行内容落下会使命令行监听失效
commander.parse(process.argv)
复制代码
如今键入 joaocli init 会输出对话, 并获取用户输入的内容和选项npm
引入git clone, 用来进行git 引入shelljs, 用来删除项目的.git文件 引入tracer, 用来彩色consolejson
const clone = require('git-clone');
const shell = require('shelljs');
const log = require('tracer').colorConsole();
复制代码
添加必要常量bash
// 项目地址
const projectUrl = {
'empty-vue-template': 'https://github.com/murongqimiao/joao-template', // 空白库
}
复制代码
在拿到用户输入内容的回调后
const { projectName, type } = answers
console.log(projectName)
console.log(type)
clone(`${projectUrl[type]}`, `./${projectName}`,null, function() {
log.info('项目构建完成')
shell.rm('-rf', `./${projectName}/.git`);
log.info(`清除掉${projectName}的git, 记得进入项目npm install`)
})
复制代码
如今在你的目录下执行 joaocli init
吧! 你将拉下一个模板项目并清除.git
const path = require('path')
复制代码
在packgejson的同级目录下添加物料文件夹
mkdir material
cd material
复制代码
添加新的commander实现物料下载
// 更新物料
commander
.command('update')
.description('更新物料库')
.action(() => {
let pwd = shell.pwd()
shell.cd(__dirname)
shell.exec('rm -rf .git')
const updateFiles = () => {
shell.cd(path.join(__dirname, '/material'))
shell.rm('-rf', '*')
shell.cd(__dirname)
shell.exec('git pull origin master')
}
shell.exec('git init')
shell.exec('git remote add origin git@github.com:murongqimiao/joao-website.git') // 物料仓库
shell.exec('git config core.sparseCheckout true')
shell.exec("echo 'material' >> .git/info/sparse-checkout")
updateFiles()
})
// 很是重要
commander.parse(process.argv)
复制代码
执行joaocli update 便可更新物料到 /material 下
关于物料的管理有不少办法, 这里笔者采用较为简单的git仓库创建专有文件夹托管物料, 利用git的 core.sparseCheckout来下载部分文件夹并非最好的办法
,由于就git的工做机制而言, sparseCheckout依然是追踪全部的历史变动,再删去没必要要内容
,若是项目在github托管,还能够把github的仓储转为svn再下载,具体操做能够查阅svn如何下载github的部份内容
,由于咱们厂的代码放在gitlab上,因故采用了core.sparseCheckout来下载物料文件.
同时由于引用下载整个项目, 执行update的时候会特别慢,请耐心等待.
update成功后material文件为下会增长组件文件夹generate_components与module文件夹generate_modules
const fs = require('fs')
复制代码
command.js中继续添加内容
/**
* 引入一些能够抽离的内容: commander快捷键 | getComponentsFiles获取目录 |_getFileName 获取是文件仍是文件夹 | generateComponent 在指定目录放置目标文件
**/
commander.version('1.0.0')
.option('-c, --component', 'Add component')
.option('-p, --page', 'Add page')
const getComponentsFiles = () => {
return _getFileName('../material/generate_components')
}
const _getFileName = (url) => {
let _url = path.join(__dirname, url)
let _back = fs.readdirSync(_url)
return _back
}
const generateComponent = (componentType, fileName, pwd) => {
fs.readFile(path.join(__dirname, `./material/generate_components/${componentType}${fileName}`), 'utf-8', (error, data) => {
if (error) throw error
// if (componentName) {
// data = data.replace(/__className__/g, componentName)
// componentType = componentName
// }
fs.writeFile(path.join(`${pwd}/src/components/${componentType}${fileName}`), data, (err) => {
if(err) {
console.log('err:', err);
} else {
console.log(`${componentType}${fileName}写入成功!...`)
}
})
})
}
// 添加物料
commander
.command('add [args...]')
.description('增长物料 -c 组件 -p 页面')
.action((args) => {
// 缺乏参数
if (!commander.component && !commander.page) {
log.warn('缺乏参数-c或者-p, 以区分物料种类, 具体见--help')
}
// 增长组件
if (commander.component) {
let pwd = shell.pwd()
args.map(componentType => {
_componentType = getComponentsFiles().indexOf(componentType) > -1 ? componentType : getComponentsFiles().indexOf(componentType + '.vue') > -1 ? componentType + '.vue' : void 0
if (!_componentType) {
log.warn(`:${componentType} --> 组件不存在, 请检查拼写`)
} else {
let _filePath = path.join(__dirname, `./material/generate_components/${_componentType}`)
let _isFile = fs.statSync(_filePath).isFile()
if (_isFile) {
generateComponent(_componentType, '', pwd)
} else {
let _aimFiles = fs.readdirSync(_filePath)
// 建文件夹
fs.mkdir(`${pwd}/src/components/${_componentType}`, 0777, (err) => {
if (err) {
log.info(`${componentType}目录已经创建`)
}
})
_aimFiles.map(item => {
generateComponent(_componentType, `/${item}`, pwd)
})
}
}
})
}
// 增长页面
if (commander.page) {
/**
* 这里是添加modules的逻辑,接下来补充
**/
}
})
...上面的内容一样添加到这句话前面
// 很是重要
commander.parse(process.argv)
复制代码
如今在你init出来的空项目中, 根目录执行 joaocli add -c empty 或者 joaocli add -c Layout 来测试可否正常添加物料吧!
能添加components后, 添加modules就没有那么困难了, 和组件相比只是多了一个自定义路径
首先添加新的问题
const modulesFileContent = ['data.js', 'index.js', 'vx.js', '__className__.vue']
// 引入page构建问题
const pageQuestions = [
{
type: 'input',
name: 'modelType',
message: '请输入想要使用的页面种类',
filter: function(val) {
return val;
}
}
]
复制代码
添加增长moduls的逻辑
/**
* 在目标文件中增长对应的page(单个添加)
*/
const generateModule = (modelType, pageName, fileName, pwd) => {
let aimFileName = fileName
let _directory = ''
// 考虑一级目录
if (pageName.split('/').length > 2) {
console.log('目前最多支持2级目录,好比dashboard/example')
}
if (pageName.split('/').length === 2) {
_directory = pageName.split('/')[0] + '/'
pageName = pageName.split('/')[1]
}
if (new RegExp(/.vue/).test(fileName)) {
aimFileName = pageName + '.vue'
}
fs.readFile(path.join(__dirname, `./material/generate_modules/${modelType}/${fileName}`), 'utf-8', (error, data) => {
if (error) throw error
data = data.replace(/__className__/g, pageName)
fs.writeFile(path.join(`${pwd}/src/views/${_directory}${pageName}/${aimFileName}`), data, (err) => {
if(err) {
console.log('err:', err);
} else {
console.log(`${fileName}写入成功!...`)
}
})
})
}
// 增长页面
if (commander.page) {
/**
* 这里是添加modules的逻辑补充
**/
inquirer.prompt(pageQuestions)
.then(answers => {
const { modelType } = answers
let pwd = shell.pwd()
console.log(`commander.page`, args)
args.map(pageName => {
console.log('pageName', pageName)
// 建立对应目录的文件夹
if (pageName.split('/').length === 2) {
fs.mkdir(`${pwd}/src/views/${pageName.split('/')[0]}`, 0755, (err) => {
log.info(`${pageName.split('/')[0]}已存在`)
})
}
fs.mkdir(`${pwd}/src/views/${pageName}`, 0755, (err) => {
log.info(`${pageName}已存在`)
})
/* 读取./generate_modules下面的文件 */
modulesFileContent.map(fileName => {
generateModule(modelType, pageName, fileName, pwd)
})
})
})
}
复制代码
在模板项目的根目录执行
joaocli add -p yourlogin
复制代码
再输入对应module类型, 好比login
就完成了一键安装modules的过程.
npm install -g joao-cli
复制代码
进入joao-cli的目录,直接看代码便可, 彻底一致.
目前物料很少, 有时间会维护, 欢迎各路大佬塞物料来, 建议添加README.md , 放置物料使用方法和收款码, 有同窗用的爽能够打赏给物料开发者.