一步一步手写一个自己前端脚手架cli工具1)#!/usr/bin/envnode>我要用系统中的这个目录/use

~~~~~~来回忆、或者复习下,不知道的同学也可以看看,当然知道的可以跳过回忆贴直接到正式部分啊~~~~~~~~~~~~~~~~~~~~~~

因为代码执行在node环境,所以需要提前安装了node,因为我们是从github上拉取的代码,你还需要知道一些git的知识~~~

在命令行中输入下面:当然是基于安装了node环境的:

#1)全局安装,可以在任意目录下执行vue这条命令npminstall-gvue-cli#2)选择一个工作目录,并且用cmd进入该目录,创建你一个项目名称为first-vue-project的vue项目vuecreatefirst-vue-project#运行vue项目cdfirst-vue-projectnpmrunserve

在按照上边过程安装时我们可以看到,首先我们的脚手架需要可以在命令行能够执行,能够解析用户输入的参数,(比如如果没有安装vue的脚手架直接在命令行输入vue是不能执行的,还有就是能够解析create参数)且在回车时,出现了选择如下图:有default\Manuallyselectfeatures两个可以选择项,选择后回车会出现loading效果、小图标等,安装成功后可以看到图1-3的文件内容,

(图1-1)

(图1-2)

(图1-3)

来下边就开始手撸代码了,创建我们自己的脚手架辣~~按照步骤来:(有浅及深)零基础构建一个CLi工具,~~~全栈架构师必备技能^_^

创建一个自己的空文件夹(lee-cli)来存放我们的项目,首先需要:

在当前目录命令行中按步骤输入下边的命令:

npminit-y#初始化package.jsonnpminstalleslinthusky--save-dev#eslint是负责代码校验工作,husky提供了git钩子功能npxeslint--init#初始化eslint配置文件

├──bin│└──www//全局命令执行的根文件├──src│├──main.js//入口文件│└──utils//存放工具方法||___constants.js//存放用户所需要的常量||___common.js│├──create.js//create命令所有逻辑│├──config.js//config命令所有逻辑│──.huskyrc//githook│──.eslintrc.json//代码规范校├──package.json|__README.md

#!/usr/bin/envnode//此文件是一个可执行文件console.log("这是我创建的一个文件,目录:/bin/www");~~~~~~ps:代码讲解及可能错误总结:

1)#!/usr/bin/envnode->我要用系统中的这个目录/user/bin/env的node环境来执行此文件,且需要注意必须放在文件开头。

"bin":{"lee-cli":"./bin/www"}

没有写上边的代码我们在命令工具是无法执行我们自己定义的命令的:

(图2-3-1)

~~~~~~ps:代码讲解及可能错误总结:

1)package.json中bin:内部命令对应的可执行文件的路径。很多包都有一个或多个可执行的文件希望被放到PATH中。(实际上,就是这个功能让npm可执行的)。上边的代码表示使用在命令工具使用命令lee-cli会调用bin/www文件

npmlink

1)使用npmlink,link将一个任意位置的npm包链接到全局执行环境,从而在任意位置使用命令行都可以直接运行该npm包。npmlink命令通过链接目录和可执行文件,实现npm包命令的全局可执行

2)我们可以看到上边的图2-3-1,有报错,就是因为bin/www中的文件原因是:

所以一定注意#!/usr/bin/envnode在文件的开头不能有空格。

#!/usr/bin/envnodeconsole.log("这是我创建的一个文件,目录:/bin/www");3)在执行npmlink如下报错:

是因为我们在建bin/www文件时建的文件时有扩展名的比如www.js,但是我们在package.json中的代码还是:"bin":{"lee-cli":"./bin/www"}改为"bin":{"lee-cli":"./bin/www.js"}既可以。

bin/www.js文件中引入main.js,www文件中使用main作为入口文件require('../src/main.js');

#!/usr/bin/envnode//此文件是一个可执行文件require('../src/main.js');

使用commander使用commander会自动生成help,解析参数。例如,我们使用vue的脚手架那样,vue-cli--help

1)安装模块

npmicommander2)src/main.js初步内容:

(图2-4-1)

如上图2-4-1所示,执行lee-cli--help已经有提示输出了,而且lee-cli-V是我们在代码中设置的内容。

3)动态获取版本号

第二步的version是我们写死的当前的cli的版本号,我们需要动态获取,并且为了方便我们将常量全部放到util下的constants.js文件中

const{name,version}=require('../../package.json');module.exports={name,version,};

main.js

constprogram=require('commander');const{version}=require('./utils/constants');program.version(version).parse(process.argv);//process.argv就是用户在命令行中传入的参数

process.argv属性返回一个数组,这个数组包含了启动Node.js进程时的命令行参数,其中:

4.1.2配置脚手架命令参数

在前言中我们有复习到在用vue-cli创建项目时,使用命令vuecreatefirst-vue-project

这个create参数是固定表示创建项目的,还可以使用其他的指令如vueconfigsetkv

那我们就来实现commander来实现吧!

在utils/common.js中

const{mapActions}=require('./utils/common');//Object.keys()Reflect.ownKeys(mapActions).forEach((action)=>{program.command(action)//配置命令的名字.alias(mapActions[action].alias)//命令的别名.description(mapActions[action].description)//命令对应的描述.action(()=>{//动作if(action==='*'){//访问不到对应的命令就打印找不到命令console.log(mapActions[action].description);}else{console.log(action);//分解命令到文件里有多少文件就有多少配置createconfig//lee-clicreateproject-name->[node,lee-cli,create,project-name]console.log(process.argv);}})});program.version(version).parse(process.argv);//process.argv就是用户在命令行中传入的参数

输出:lee-clicreatemy

我们在看看lee-cli--help

(图2-4-3)

发现已经有了我们配置的createconfig*指令。

2)子命令command,可以使用.command为你的最高层命令指定子命令。在之前的代码我们可以简化一个create代码来看,

program.command('create')//配置命令的名字.alias('c')//命令的别名.description('创建一个项目')//命令对应的描述.action(()=>{console.log('此处为create子命令');})

(图2-4-4)

4.1.3监听--help

监听--help命令,打印帮助信息,在之前配置命令的代码中我们可以看到examples,这个就是在告诉我们这个子指令的用法,我们可以通过--help查看案例。

(图2-4-5)

在main.js中增加代码:

//监听用户的help事件program.on('--help',()=>{console.log('\nExamples:');Reflect.ownKeys(mapActions).forEach((action)=>{mapActions[action].examples.forEach((example)=>{console.log(`${example}`);})})})

(图2-4-6)

4.1.4具体create命令所做的事情

图(2-4-7)

4.1.4.1如何实现create的主要作用呢?

为命令绑定一个操作处理程序(actionhandler),或者将命令单独写成一个可执行文件。

上图(2-4-7)中是main.js配置指令的代码,我们知道当我们输入lee-clicreatemy命令时可以输出信息,动作在action里边,因为我们可以配置很多子命令比如create\config\init...所以我们将具体的动作分发到不同的文件中,通过读取不同的文件名来调用相对于的内容。

在main.js中增加代码

.action(()=>{if(action==='*'){//访问不到对应的命令就打印找不到命令console.log(mapActions[action].description);}else{console.log(action);//分解命令到文件里有多少文件就有多少配置createconfig//lee-clicreateproject-name->[node,lee-cli,create,project-name]console.log(process.argv);require(path.join(__dirname,action))(...process.argv.slice(3));}}

在create.js中增加代码:

module.exports=(projectName)=>{console.log(`此处是文件${projectName}`);}

图(2-4-8)

1)require(path.join(__dirname,action))(...process.argv.slice(3));

在action中我们引入了create.js,并且将我们在命令行中输入的项目名传入到create.js中。process.argv.slice(3)在之前也讲过process.argv返回的是一个数组,从图(2-4-8)也可以看出了。执行lee-clicmy打印出来了此处是文件my

4.1.4.2拉取项目

此时我们就需要将我们git上的项目或者其他云上的项目拉取下来,获取仓库中的所有模板信息,这里就以git为例。

1)安装axio模块

npmiaxios

2)在create.js中增加代码

4.2.1使用inquirer一个用户与命令行交互的工具

1)安装inquirer模块

npmiinquirer

varinquirer=require('inquirer')inquirer.prompt([{type:'confirm',name:'test',message:'你确定使用这个吗',default:true}]).then((answers)=>{console.log('结果为:')console.log(answers)})

执行命令lee-clicmy结果为:

(图2-4-11)

上边的图2-4-11我们可以看到出现了这是一个测试项目(Y/n)我们可以选择Y出现先,这是因为我们的参数type:'confirm',

(图2-4-12)

我们在代码中输出inquirer.prompt()结果是一个promise,上边是用的default,如果我们想选择不同的仓库可以用choice,type:'list',

3)在我们项目中改为:create.js代码增加

const{repo}=awaitinquirer.prompt([{type:'list',name:'repo',message:'请选择一个你要创建的项目',choices:repos}]);console.log(`我现在选择了那个仓库?${repo}`);

(图2-4-13)

上图中我们可以看到有多出现了请选一个你要创建的项目,下边为我们的仓库列表通过上下键选择一个回车选中

(图2-4-14)

1)inquirer.prompt(参数):

{//表示提问的类型,下文会单独解释type:String,//在最后获取到的answers回答对象中,作为当前这个问题的键name:String,//打印出来的问题标题,如果为函数的话message:String|Function,//用户不输入回答时,问题的默认值。或者使用函数来return一个默认值。//假如为函数时,函数第一个参数为当前问题的输入答案。default:String|Number|Array|Function,//给出一个选择的列表,假如是一个函数的话,第一个参数为当前问题的输入答案。//为数组时,数组的每个元素可以为基本类型中的值。choices:Array|Function,//接受用户输入,并且当值合法时,函数返回true。当函数返回false时,//一个默认的错误信息会被提供给用户。validate:Function,//接受用户输入并且将值转化后返回填充入最后的answers对象内。filter:Function,//接受当前用户输入的answers对象,并且通过返回true或者false来决定是否当前的问题应该去问。//也可以是简单类型的值。when:Function|Boolean,//改变渲染list,rawlist,expand或者checkbox时的行数的长度。pageSize:Number,}4.2.2使用ora

npmiora

constspinner=ora('Loading测试中哈哈哈。。。').start();setTimeout(()=>{spinner.color='red';spinner.text='Loadingora哈哈哈';//成功spinner.succeed('拉取成功');},1000);

constora=require('ora');//封装loading效果constfnLoadingByOra=async(fn,message)=>{constspinner=ora(message);spinner.start();letresult=awaitfn();spinner.succeed();//结束loadingreturnresult;}module.exports={mapActions,fnLoadingByOra};

const{fnLoadingByOra}=require('./utils/common');module.exports=async(projectName)=>{letrepos=awaitfnLoadingByOra(fetchReopLists,'正在链接你的仓库...');repos=repos.map((item)=>item.name);//使用inquirer在命令行中可以交互const{repo}=awaitinquirer.prompt([{type:'list',name:'repo',message:'请选择一个你要创建的项目',choices:repos}]);console.log(`我现在选择了那个仓库?${repo}`);}

(图2-4-17)

1)在utils/common.js中增加更改信息

2)在create.js

constinquirer=require('inquirer');const{fnLoadingByOra,fetchReopLists,getTagLists}=require('./utils/common');module.exports=async(projectName)=>{letrepos=awaitfnLoadingByOra(fetchReopLists,'正在链接你的仓库...')();repos=repos.map((item)=>item.name);//使用inquirer在命令行中可以交互const{repo}=awaitinquirer.prompt([{type:'list',name:'repo',message:'请选择一个你要创建的项目',choices:repos}]);lettags=awaitfnLoadingByOra(getTagLists,`正在链接你的选择的仓库${repo}的版本号...`)(repo);tags=tags.map((item)=>item.name);console.log(`我现在选择了那个仓库?${repo}`);console.log(`仓库${repo}的版本信息列表:${tags}`);}

(图2-4-18)

3)增加选择版本信息

在create.js

lettags=awaitfnLoadingByOra(getTagLists,`正在链接你的选择的仓库${repo}的版本号...`)(repo);tags=tags.map((item)=>item.name);const{tag}=awaitinquirer.prompt([{type:'list',name:'tag',message:'请选择一个该项目的版本下载',choices:tags}]);console.log(`我现在选择了那个仓库?${repo}`);console.log(`仓库${repo}的版本信息列表:${tag}`);

(图2-4-19)

(图2-4-20)

npmidownload-git-repo

2)我们需要下载到本地的地址

下载前先找个临时目录来存放下载的文件,来存放,以备后期使用,这样的好处是,如果我们之前下载这个版本的项目可以直接从这个存放的地址拿来(相当于缓存),如果项目中更新我们将临时目录中的文件覆盖也可以。

2.1)在utils/constants.js增加常量

下载临时文件存放地址因为不同的电脑平台临时存放地址不同

constdownloadDirectory=`${process.env[process.platform==='darwin''HOME':'USERPROFILE']}/.myTemplate`;console.log(downloadDirectory);module.exports={name,version,downloadDirectory};

1)process.platform

比如小编使用的电脑:

(图2-4-21)

2.2)获取用户目录

在utils\common.js中增加代码

const{promisify}=require('util');constdownloadGit=require('download-git-repo');downloadGit=promisify(downloadGit);//将项目下载到当前用户的临时文件夹下constdownDir=async(repo,tag)=>{console.log(tag,'downDir方法');letproject=`lxy-cli/${repo}`;//下载的项目if(tag){project+=`#${tag}`;}//c:/users/lee/.myTemplateletdest=`${downloadDirectory}/${repo}`;//把项目下载当对应的目录中console.log(dest,'dest的内容。。。。。。。。。。');console.log(project,'dest的内容。。。。。。。。。。');try{awaitdownloadGit(project,dest);}catch(error){console.log('错误了吗???\n');console.log(error);}returndest;}

在create.js中增加代码并引入

//下载项目到临时文件夹C:\Users\lee\.myTemplateconsttarget=awaitfnLoadingByOra(downDir,'下载项目中...')(repo,tag);

(图2-4-22)

根据图2-4-22我们可以看出来当我们执行lee-clicmy创建项目时,选择了vue-tempalte,选择下载版本v1.0我还我们下载到临时文件夹目录是:下载项目到临时文件夹C:\Users\lee\.myTemplate所以我们可以找到地址:C:\Users\lee\.myTempalte\vue-tempalte打开可以看到下图(图2-4-23):对应我们github地址上的内容是一样的,如图(图2-4-24)

(图2-4-23)

(图2-4-24)

1)promisify(downloadGit);

这句代码我们知道是将downloadGit改为promise,因为download-git-repo不是promise,而我们在项目中都用asyncawait需要我们自己包装为promise。

npmincp

2)在utils\common.js增加方法

在create.js文件中增加代码

awaitcopyTempToLoclhost(target,projectName);

(图2-4-25)

我们跟上边一样的选择命令发现图2-4-25和图2-4-24、图2-4-23内容相同。

因为此情况有很多种形式,我们在此模拟了一个需要用户在命令行选择用户输入内容的特定的复杂模板。在其中一个仓库中存放一个ask.js中放入可以用inquirer模块执行的命令行参数,来询问生成相应的package.json文件,因为里边用到ejs

THE END
1.github操作学习笔记这是一个学习github高级操作的笔记本 创建新仓库 1、先在github上建一个新仓库 2、打开vscode终端 git init 初始化仓库 git add README.md 保存新文件 git commit -m "first commit" 提交新文件 git branch -M main 更名为main分支 git remote add origin https://github.com/ZJR-FZD/experiment1.git 添加https://blog.csdn.net/2302_79795489/article/details/144332325
2.github下载的东西怎么运行?Worktile社区要运行从GitHub下载的东西,你需要遵循一些基本的步骤。下面是一个简单的指南,告诉你如何运行从GitHub下载的项目。 1. 首先,确认你的计算机上是否已安装了所需的运行环境。通常,从GitHub下载的项目会有一个说明文件,其中包含了必要的依赖项和环境要求。你需要确保你的计算机上已经安装了这些依赖项和环境。 https://worktile.com/kb/ask/515877.html
3.github上下载的python程序如何运行git上下载项目下载完成,点击.exe文件打开运行,然后点击Next 按需选择安装组件与配置,我这里使用的是默认选项。然后点击Next。 选择Git默认编辑器 注意:选择默认编辑器的时候,只能选择电脑里已经安装了的编辑器,没有安装的,需要先安装。 Git安装程序中有10种编辑器和1个其他项可以选择,比如:the Nano、Vim、Notepad++、Visual Studiohttps://blog.51cto.com/u_16213624/9144116
4.GitHub加速器GitHub加速工具下载下载电脑V1.60以管理员运行exe,也可打开exe文件属性->兼容性->以管理员运行 最后的话 如何有不对的地方或者更好的办法,欢迎讨论 如果还是访问不了网站,这是正常现象,因为只是加速,不能保证100%访问 GitHub加速工具下载 电脑V1.60 普通下载地址: 本地普通下载 本地电信下载 http://www.kkx.net/soft/85527.html
5.HelperWiki·publishhelper/publish打开本仓库Releases,下载最新的zip文件。 如果中国大陆GitHub下载缓慢,可访问Gitee仓库Releases,内容会同步更新。 2. 解压软件 解压下载后的zip压缩包,获取解压后的文件夹,并且储存到你想要存的地方。 3. 运行软件 打开解压后的Publish Helper文件夹,双击运行Publish Helper.exe应用程序,耐心等待软件启动。 至此,软件https://github.com/publish-helper/publish-helper/wiki/Publish-Helper-Wiki
6.Deskreen它可能与这个错误有关: https://github.com/pavlobu/deskreen/discussions/68#discussioncomment-330357 在我的操作系统上,Deskreen 应用程序无法运行/安装。防病毒软件会阻止它,并提示它可能有病毒。它有病毒吗?我该怎么办? Deskreen 安装文件中没有病毒,您可以使用防病毒软件进行检查。你看到这些警告的原因是这个应用https://deskreen.com/
7.Github如何下载文件或源代码这篇文章教大家如何下载GitHub上面的代码或者单个文件,以及已经编译好的可执行软件文件,网上很多地方都没有把这个事情讲明白,连一张图都没有配,简直让人无法接受,本站将简单明了的教你怎么下载GitHub上面的东西。 我们告诉你最简单的方法下载,方便你快速入门,GitHub也支持使用客户端clone,也支持命令复制代码,不过那对https://get.qiaobuqiao.com/post-7907
8.Mac如何安装FaceFusion视频AI换脸软件张洪Heo这篇文章介绍了如何在Mac上安装和使用AI视频换脸软件的步骤。首先,它提供了安装所需环境(Python、PIP、GIT、FFmpeg)的命令。接着,介绍了如何下载源文件和设置Python环境。文章详细说明了如何运行安装脚本,包括选择Torch变体和处理器类型。最后,它指导用户如何运行软件、下载模型,并使用浏览器访问软件的主界面,以及如何选https://blog.zhheo.com/p/a856617c.html
9.如何解决百度云下载大文件限速问题ps:百度云下载不保证是最新版,最新版请自行到github下载 3.下载好插件以后,打开谷歌浏览器->更多工具->扩展程序 ->将下载好的文件(chrome.crx)直接拖到扩展程序界面 这样扩展程序就安装好了。 打开百度云的分享界面,我们可以看到多了一个按钮。 测试链接:https://pan.baidu.com/s/1dECWsdN https://www.jianshu.com/p/cc25189db4a1
10.简易教程NLPIR汉语分词系统2.下载-解压后,得到2.3GB的文件夹,点击该文件夹。 3.点击【NLPIR-Parser】。 4.根据系统情况(32/64),选择相应文件夹。 5.点击【NLPIR-Parser】。 注意:如果弹出【授权文件无效】,需要重新下载授权文件。 GitHub上的授权文件页面:https://github.com/NLPIR-team/NLPIR/tree/master/License https://www.douban.com/note/715867867/
11.Git--distributed-is-the-new-centralized Git is afree and open sourcedistributed version control system designed to handle everything from small to very large projects with speed and efficiency. Git iseasy to learnand has atiny footprint with lightning fast performance. It outclasses SCM tools like https://git-scm.com/
12.智算平台模型训练相关问题智算平台常见问题在Jupyter文件浏览器双击打开ipynb文件,并在导航栏选择:File-Save and Export Notebook As-Executable Script 10. 如何在预置kernel的Notebook文件中运行py文件,且确保能引用到预置kernel的包? 在Notebook里执行pip,查看当前使用的kernel对应的环境,并在运行py文件时,使用绝对路径的python,例如,使用预置kernel时,可在Nohttps://ecloud.10086.cn/op-help-center/doc/article/51475
13.2019年5月,如何解决百度云限速问题?Morix(WIN / IOS / Lunix)下载:https://motrix.app/ ? Windows推荐使用IDM,Mac上推荐使用Morix 下面阿虚讲一下IDM的安装使用注意事项等。 IDM安装说明 解压后,右键解压出来的文件「点我绿化卸载.bat」,选择管理员模式运行,安装软件。 打开Chrome浏览器的更多工具——扩展程序——打开右上角的开发者模式——https://weibo.com/ttarticle/p/show?id=2309404367596328747071