https://github.com/WTlumos/learn_cli
1. 创建项目
创建index.js
创建package.json
创建命令
入口文件index.js中,添加如下指令(shebang也成为hashbang)
1 2 #! /usr/bin/env node console .log ("learn_cli" );
修改package.json
1 2 3 "bin" : { "learn" : "index.js" }
执行命令
1 2 3 4 5 $ npm link added 1 package in 2s $ learn learn_cli
2. Commander的使用 编写代码来描述你的命令行界面
Commander 负责将参数解析为选项和命令参数,为问题显示使用错误,并实现一个有帮助的系统
https://github.com/tj/commander.js/blob/master/Readme_zh-CN.md
2.1. 安装
2.2. 目录结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |- learn_cli |- lib |- config |- repo-config.js |- core |- help.js |- create.js |- templates |- vue-component.ejs |- vue-router.ejs |- vue-store.ejs |- vue-types.ejs |- utils |- node_modules |- index.js |- package-lock.js |- package.js
2.3. 编写命令信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const { program } = require ("commander" );const helpOptions = ( )=>{ program.option ('-i --info' ,'a learn cli' ); program.option ('-s --src <src>' ,'a source folder' ); program.option ('-d --dest <dest>' ,'a destination folder, 如: -d src/pages' ); program.option ('-f --framework <framework>' ,'your framework name' ); program.on ('--help' ,function ( ){ console .log ("" ); console .log ("Others:" ); }); } module .exports = helpOptions;#! /usr/ bin/env node const { program } = require ("commander" );const helpOptions = require ("./lib/core/help" );const package = require ("./package.json" );program.version (package.version ); helpOptions ();program.parse (process.argv );
运行命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ learn --help Usage: learn [options] Options: -V, --version output the version number -i --info a learn cli -s --src <src> a source folder -d --dest <dest> a destination folder, 如: -d src/pages -f --framework <framework> your framework name -h, --help display help for command Others: $ $ $ learn --version $ 1.0.0
3. 创建项目指令 3.1. 思路
创建解析create指令
通过download-git-repo从代码仓库中下载模板
https://www.npmjs.com/package/download-git-repo
1 $ npm install download-git-repo
进入目录,并且执行 npm install
命令
执行 npm run serve
命令
打开浏览器
3.2. 创建解析create指令 创建 /lib/core/create.js
单独引入 createProjectAction
promise函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const { program } = require ("commander" );const { createProjectAction } = require ("./actions" );const createCommands = ( )=>{ program .command ('create <project> [otherArgs...]' ) .description ('clone a repository into a newly created directory' ) .action (createProjectAction); } module .exports = createCommands;
3.3. 定义项目地址 创建 /lib/config/repo-config.js
1 2 3 4 5 6 const vueGitRepo = "direct:https://github.com/coderwhy/hy-vue-temp.git" ;module .exports = { vueGitRepo }
3.4. createProjectAction函数实现 创建 /lib/core/action.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const {promisify} =require ("util" );const { vueGitRepo } = require ("../config/repo-config" );const download = promisify (require ("download-git-repo" ));const createProjectAction = async (project,others )=>{ await download (vueGitRepo, project, { clone : true }); } module .exports = { createProjectAction };
3.5. 执行命令 1 2 3 4 const createCommands = require ("./lib/core/create" );createCommands ();
终端
自动创建的文件夹
3.6. 执行 npm install命令 创建 /utils/termianls.js
https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processspawncommand-args-options
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const {spawn} = require ("child_process" );const spawnCommand = (...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 = spawnCommand;
在 /lib/core/action.js 中添加 npm install
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const spawnCommand = require ("../utils/terminal" );const createProjectAction = async (project,others )=>{ console .log ("Learn_cli helps you create your project, please wait a moment" ); await download (vueGitRepo, project, { clone : true }); const npm = process.platform === 'win32' ? 'npm.cmd' :'npm' ; await spawnCommand (npm,['install' ],{cwd : `./${project} ` }); }
终端
自动创建的文件夹,并完成 npm install
3.7. 执行 npm run serve命令 在 /lib/core/action.js 中添加 npm run serve
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 const createProjectAction = async (project,others )=>{ console .log ("Learn_cli helps you create your project, please wait a moment" ); await download (vueGitRepo, project, { clone : true }); const npm = process.platform === 'win32' ? 'npm.cmd' :'npm' ; await spawnCommand (npm,['install' ],{cwd : `./${project} ` }); spawnCommand (npm,['run' ,'serve' ],{cwd : `./${project} ` }); open ("http://localhost:8080/ " ); }
4. 创建添加组件-页面-vuex命令 4.1. 思路
创建addcpn、addpage、addstore的命令
准备好对应的ejs模块(component.vue.ejs
, vue-router.js.ejs
, vue-store.js.ejs
, vue-types.js.ejs
)
封装编译ejs模块的函数
封装将编译后的内容,写入文件的函数
将上面封装的所有代码放到一起的函数
4.2. 编写ejs模块 https://ejs.bootcss.com/ 高效的嵌入式 JavaScript 模板引擎
/lib/templates/vue-component.ejs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <template> <div class="<%= data.name %>"> <h1>{{ msg }}</h1> </div> </template> <script> export default { name: '<%= data.name %>', props: { msg: String }, components: { }, mixins: [], data: function(){ return { message: "<%= data.lowerName %>" } }, created: function(){ }, mounted: function(){ } } </script> <style scoped> .<%= data.name %>{ } </style>
/lib/templates/vue-router.ejs
1 2 3 4 5 6 7 8 9 10 11 12 // 普通加载路由 // import Home from './Home.vue' // 懒加载路由 const <%= data.name %> = ()=> import('./<%= data.name%>.vue') export default{ path: '/<%= data.lowerName %>', name: '<%= data.name %>', component: '<%= data.name %>', children: [ ] }
/lib/templates/vue-store.ejs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import * as types from './types.js' export default{ namespaced: true, state: { }, mutations: { }, actions: { }, getters: { } }
/lib/templates/vue-types.ejs
4.3. 创建addcpn指令代码 lib/core/create.js
添加指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const { createProjectAction,addComponentAction } = require ("./actions" );const createCommands = ( )=>{ program .command ('create <project> [otherArgs...]' ) .description ('clone a repository into a newly created directory' ) .action (createProjectAction); program .command ('addcpn <name>' ) .description ('add vue component, 例如: learn addcpn NarBar [-d src/components]' ) .action (name => addComponentAction (name, program.opts ().dest || 'src/components' )); }
lib/core/action.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const {compile, writeToFile} = require ("../utils/utils" );const { mkdirSync } = require ("fs" );const addComponentAction = async (name )=>{ const result = await compile ("vue-component.ejs" ,{name, lowerName : name.toLowerCase ()}); mkdirSync (dest,{recursive :true }); const targetPath = path.resolve (dest,`${name} .vue` ); writeToFile (targetPath,result); } module .exports = { createProjectAction, addComponentAction };
lib/utils/util.js
先下载 ejs 模板
编写代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 const ejs = require ("ejs" );const path = require ("path" );const compile = (templateName, data )=>{ const templatePath = path.resolve (__dirname,`../templates/${templateName} ` ); return new Promise ((resolve,reject )=> { ejs.renderFile (templatePath,{data},{},(err,str )=> { if (err){ console .log (err); reject (err); return ; } resolve (str); }) }) } const writeToFile = (path,content )=>{ if (fs.existsSync (path)){ console .error ("the file already exist!" ); return ; } return fs.promises .writeFile (path,content); } module .exports = { compile, writeToFile }
执行命令
在 src/components
中得到模板代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <template> <div class="Narbar" > <h1>{{ msg }}</h1> </div> </template> <script> export default { name: 'Narbar' , props: { msg: String }, components: { }, mixins: [], data: function (){ return { message: "narbar" } }, created: function (){ }, mounted: function (){ } } </script> <style scoped> .Narbar{ } </style>
4.4. 创建addpage指令代码 /lib/core/create.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { createProjectAction,addComponentAction, addPageAction} = require ("./actions" );const createCommands = ( )=>{ program .command ('addpage <page>' ) .description ('add vue page, 例如: learn addpage Home [-d src/pages]' ) .action (page => addPageAction (page, program.opts ().dest || `src/pages/${page.toLowerCase()} ` )); }
lib/core/action.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const addComponentAction = async (name,dest )=>{ handleEjsToFile (name,dest,'vue-component.ejs' ,`${name} .vue` ); } const addPageAction = async (page,dest )=>{ handleEjsToFile (page,dest,'vue-component.ejs' ,`${page} .vue` ); handleEjsToFile (page,dest,'vue-router.ejs' ,'router.js' ); } const handleEjsToFile = async (name,dest,template,filename )=>{ const result = await compile (template,{name, lowerName : name.toLowerCase ()}); mkdirSync (dest,{recursive :true }); const targetPath = path.resolve (dest,filename); writeToFile (targetPath,result); } module .exports = { createProjectAction, addComponentAction, addPageAction };
执行命令
创建文件
4.5. 创建 addstore 指令代码 /lib/core/create.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { createProjectAction,addComponentAction, addPageAction, addStoreAction } = require ("./actions" );const createCommands = ( )=>{ program .command ('addstore <store>' ) .description ('add vue store, 例如: learn addstore favor [-d dest]' ) .action (store => addStoreAction (store, program.opts ().dest || `src/store/modules/${store.toLowerCase()} ` )); }
/lib/core/action.js
1 2 3 4 5 6 7 8 9 10 11 12 const addStoreAction = async (store,dest )=>{ handleEjsToFile (store,dest,'vue-store.ejs' ,`${store} .js` ); handleEjsToFile (store,dest,'vue-types.ejs' ,`types.js` ); } module .exports = { createProjectAction, addComponentAction, addPageAction, addStoreAction };
执行命令
创建文件
5. 发布项目
注册npm账号:
https://www.npmjs.com/
选择sign up
在命令行登录
修改package.json
1 2 3 4 5 6 7 8 "keywords" : [ "vue" , "CLI" , "component" ] , "author" : "wtlumos" , "license" : "MIT" , "homepage" : "https://github.com/WTlumos" , "repository" : { "type" : "git" , "url" : "https://github.com/WTlumos" }
发布到 npm registry上
更新仓库
修改版本号(最好符合semver规范)
重新发布
删除发布的包
让发布的包过期