之前写vue项目都是用尤大佬固定的cli格式,自己为啥不能模仿一个呢?今天就讲怎么模仿
1.先创建一个入口文件index.js
里面先写上 #!/usr/bin/env node
2.创建package.json
npm init -y
3.配置环境变量
"lsh"这个名字可以随便取,入口index.js不能变
然后npm link
4.安装commander
npm i commander
5.在index.js中
const program = require('commander')
//版本号
program.version(require('./package.json').version,'-v,--version')
program.parse(process.argv)
program.version是查看版本号,lsh --version 或者 -v,但是有的人喜欢用大V,-V,如果想用大V的话,这两个同时写
program.version(require('./package.json').version,'-v,--version')
program.version(require('./package.json').version)
6.创建一个help.js文件
这个文件就放我们命令help,比如:npm i cli -l,npm i cli -d,npm I cli -f等等
const program = require('commander');
const helpOptions = () => {
//增加自己的options
program.option('-l --lsh', 'a lsh cli')
//可选 -d,类似--save
program.option('-d --dest <dest>', 'a destination folder,例如:-d /src/components')
//拉取不一样的框架,例如vue,react
program.option('-f --framework <framework>', 'your framework')
program.on('--help', function () {
console.log('others')
})
}
module.exports = helpOptions
7.创建一个actions.js文件

这个文件放我们创建项目,创建路由等等代码
首先要安装一个插件download-git-repo,从git上获取克隆地址
npm i download-git-repo
8.创建一个terminal.js文件
这个文件就放我们执行终端命令相关的代码的代码
const { spawn } = require('child_process')
const commandSpawn = (...args) =>{
return new Promise((resolve,reject)=>{
const childProcess = spawn(...args)
childProcess.stdout.pipe(process.stdout)
childProcess.stderr.pipe(process.stderr)
//执行完了
childProcess.on('close',()=>{
resolve()
})
})
}
module.exports = {
commandSpawn
}
9.创建一个repo-config.js文件
我们可以先用尤大佬内置的vue-cli,创建一个项目,然后根据我们的习惯,把一些插件啊和要用的配置写好,然后上传github或者gitlab,码云都可以,把地址记住就行
地址前面要加direct
let vueRepo = 'direct:https://github.com/';
module.exports = {
vueRepo
}
10.在actions.js中
还需要安装一个open插件,为的是我们创建好项目之后,自动运行到浏览器
npm i open
代码
const download = promisify(require('download-git-repo'));
const { vueRepo } = require('../config/repo-config');
const { commandSpawn } = require('../utils/terminal')
const createProjectAction = async (project) => {
console.log('lsh loading create')
// 1.clone项目
await download(vueRepo, project, { clone: true });
// 2.执行npm install
//windows和其他mac,linux不同
const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'
await commandSpawn(command, ['install'], { cwd: `./${project}` })
// 3.运行npm run serve
commandSpawn(command, ['run', 'serve'], { cwd: `./${project}` })
// 4.打开浏览器
open("http://localhost:8080/")
}
module.exports = {
createProjectAction
}
11.创建一个create.js
这里面就放具体创建的命令,相当于把actions.js封装了一下
const program = require('commander');
const { createProjectAction }= require('./actions')
const createCommands = () => {
//创建
program
.command('create <project> [others...]')
//描述
.description('clone a repository into a folder')
//执行
.action(createProjectAction);
}
module.exports = createCommands
12.在index.js中
引入这些配置好的js
const helpOptions = require('./lib/core/help.js')
const createCommands = require('./lib/core/create.js')
//帮助和可选信息
helpOptions()
//创建其他指令
createCommands()
13.开始创建项目
lsh create demo
然后我们github上地址的项目就被创建出来了
14.命令创建组件
当我们lsh addcpn template 或者lsh addcpn template -d src/component时候,会给我们创建好一个我们写好的组件模版
前面是默认地址,后面是指定创建地址
15.创建一个vue-component.ejs组件模版
<template>
<div class="<%= data.lowerName %>">
<h1>{
{ msg }}</h1>
</div>
</template>
<script>
export default {
name: '<%= data.name %>',
props: {
msg: String
},
components: {
},
mixins: [],
data: function() {
return {
message: "<%= data.name %>"
}
},
created: function() {
},
mounted: function() {
},
computed: {
},
methods: {
}
}
</script>
<style scoped>
.<%= data.lowerName %> {
}
</style>
16.创建一个utils.js
这个就是相当于转译我们的ejs,需要安装
npm i ejs
代码
const fs = require('fs')
const path = require('path')
const ejs = require('ejs')
const compile = (templateName,data) =>{
const remplatePosition = `../templates/${templateName}`
const templatePath = path.resolve(__dirname,remplatePosition)
return new Promise((resolve,reject)=>{
ejs.renderFile(templatePath,{data},{}, (err,result)=>{
if(err){
console.log(err)
reject(err);
return;
}
resolve(result)
})
})
}
//addpage的时候,同时创建一个文件夹包裹.vue和router.js
// source/components/category/why
const createDirSync = (pathName) => {
if (fs.existsSync(pathName)) {
return true;
} else {
if (createDirSync(path.dirname(pathName))) {
fs.mkdirSync(pathName);
return true;
}
}
}
const writeToFile = (path,content) =>{
// 判断path是否存在, 如果不存在, 创建对应的文件夹
return fs.promises.writeFile(path,content)
}
module.exports = {
compile,
writeToFile,
createDirSync
}
17.actions.js中
const { compile,writeToFile,createDirSync } = require('../utils/utils')
//添加组件的action
const addCpnAction = async (name, dest) => {
// 1.编译ejs模块result
const data = {name, lowerName: name.toLowerCase()};
const result = await compile("vue-component.ejs", data)
// 2.将result写入到.vue文件中
const targetPath = path.resolve(dest,`${name}.vue`)
writeToFile(targetPath,result)
// 4.放到对应到文件夹中
}
module.exports = {
addCpnAction
}
18.create.js中
const { addCpnAction} = require('./actions')
const createCommands = () => {
//创建
program
.command('addcpn <name>')
//描述
.description('add vue component,例如:lsh addcpn helloword -d src/components')
//执行
.action((name) => {
addCpnAction(name, program.dest || 'src/components')
});
}
module.exports = createCommands
19.创建组件
lsh addcpn template
lsh addcpn template -d src/pages/src
第一个是没有指定创建地址,所以默认地址就是src/components
第二个指定创建地址,地址就是src/pages/src
20.创建路由和路由
其实跟前面一个原理,我们把方法全封装了起来,所以就很方便
先写好ejs模块,创建一个vue-router.ejs文件
// 普通加载路由
// import <%= data.name %> from './<%= data.name %>.vue'
// 懒加载路由
const <%= data.name %> = () => import('./<%= data.name %>.vue')
export default {
path: '/<%= data.lowerName %>',
name: '<%= data.name %>',
component: <%= data.name %>,
children: [
]
}
21.actions.js中
// 添加组件和路由
const addPageAndRouteAction = async (name, dest) => {
// 1.编译ejs模板
const data = {name, lowerName: name.toLowerCase()};
const pageResult = await compile('vue-component.ejs', data);
const routeResult = await compile('vue-router.ejs', data);
// 3.写入文件
const targetDest = path.resolve(dest, name.toLowerCase());
if (createDirSync(targetDest)) {
const targetPagePath = path.resolve(targetDest, `${name}.vue`);
const targetRoutePath = path.resolve(targetDest, 'router.js')
writeToFile(targetPagePath, pageResult);
writeToFile(targetRoutePath, routeResult);
}
}
module.exports = {
addPageAndRouteAction
}
21.create.js中
const program = require('commander');
const {
addPageAndRouteAction,}
= require('./actions')
const createCommands = () => {
program
.command('addpage <page>')
.description('add vue page and router config, 例如: why addpage Home [-d src/pages]')
.action((page) => {
addPageAndRouteAction(page, program.dest || 'src/pages')
})
}
module.exports = createCommands
22.创建
跟前面创建组件是一模一样的,所以就不写了,这就是封装的好处,方便
23.发布到npm
首先到npm上创建一个自己的账号,这个就不说了,创建好账号之后登录
npm login
然后到自己包的根目录打开终端
npm publish
记住上传的version版本号要比你这个大,记得修改一下
有2个问题如果出现咋解决?
1.执行npm publish 报错:403 Forbidden - PUT https://registry.npmjs.org/kunmomotest - you must verify your email before publishing a new package: https://www.npmjs.com/email-edit
你的邮箱没有验证,去你绑定的邮箱验证一下即可
2.npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/ui-com - You do not have permission to p
名字重复,改一下
结尾
我把我的包已经发到npm上去了,有兴趣的可以看一下下,写的不好请别见怪,我也是小白,使用命令跟我上面写的是一样的
npm i lsh_vuenew_cli
我这个包的源码也发到github上去了,可以看看