当前位置: 首页 > 后端技术 > Node.js

前端工程3:如何编写NodejsCli应用-自定义脚手架

时间:2023-04-03 23:08:39 Node.js

什么是NodejsCli应用?简单的说就是一个可以在命令行使用nodejs执行的应用程序,比如:vue-cli、creat-react-app、webpack-cli等;在前端开发过程中,我们会用到很多工具。这些工具安装好后可以直接使用命令行执行;请注意,全局安装与项目安装不同。//全局安装,直接执行命令>npminstallwebpackwebpack-cli-g>webpack//项目安装,需要使用npx执行>npminstallwebpackwebpack-cli--save-dev>npxwebpackNodejsCli申请流程!1.启动过程:命令行执行=>根据package.json中的bin查询入口=>执行入口js文件cli.js2.执行过程:命令行执行js文件函数启动=>命令行问用户问题=>结合问题答案+模板和其他文件=>生成结构文件NodejsCli应用入口文件:cli.js1,入口文件路径,先添加bin字段{"name":"ncl","main":"index.js","bin":{"ncl":"./cli.js"//入口文件,ncl和名字要一致},...}2、入口文件的具体文件头,在cli最前面输入。js#!/usr/bin/envnode3,入口文件权限//如果是linux或者macOS系统,需要修改这个文件的读写权限为755//具体通过chmod755cli.js修改4.简单的测试模块npmlink可以将模块链接到整个世界,或者链接到使用该模块的项目node_modules;这样,在开发模块的过程中,无需发布到npm,模块就可以用于测试。>npmlink//在自定义模块项目的目录下执行,将模块连接到全局>ncl//直接执行模块,使用模块名NodejsCli应用示例本示例的功能实现了一个自定义脚手架:askon命令行用户将一些简单的问题作为参数,然后自动生成一些工程文件。其中的文件可以通过模板生成,也可以将数据传递给模板。1.安装一些依赖模块>npminstallinquirer--save//在nodejs环境下,实现命令行的用户交互插件>npminstallejs--save//模板引擎2、在cli中定义命令行.js向用户提问inquire.prompt执行命令行用户查询操作。Inquirer.prompt返回一个promise对象。inquirer.prompt的参数是一个数组constinquirer=require('inquirer')inquirer.prompt([{type:'input',name:'name',message:'Pleaseenteraprojectname?'}])。then(anwsers=>{//anwsers:{name:"xxx"}//anwsers返回一个结果对象})3.获取模板目录和目标生成目录constpath=require('path')//模板目录//__dirname获取当前执行代码文件的绝对路径//tmplDir为模板的绝对路径consttmplDir=path.join(__dirname,'templates')//目标目录//process.cwd()返回当前工作目录Node.js进程。//流程参考api文档:http://nodejs.cn/api/process.htmlconstdestDir=process.cwd()4.模板引擎渲染模板constejs=require('ejs')constpath=require('path')//通过模板引擎渲染文件//参数1:fileDir为文件的绝对路径//参数2:渲染模板所需的变量,保存在anwsers对象中//参数3:回调函数,结果为新文件ejs.renderFile(fileDir,anwsers,(err,result)=>{if(err)throwerr//将结果写入目标文件路径fs.writeFileSync(fileDestDir,result)})//示例作为模板的package.json:{"name":"<%=name%>","version":"<%=version%>","description":"<%=description%>","author":"<%=author%>","bin":"cli.js","scripts":{"test":"echo\"Error:notestspecified\"&&exit1"},"license":“ISC”}5。读取目录下面的文件//将模板下的所有文件转换为目标目录//参数1:path//参数2:回调函数,参数files为文件相对路径数组fs.readdir(tmplDir,(err,files)=>{if(err)throwerrfiles.forEach(file=>{//通过模板引擎渲染文件//处理文件})})})6.将文件写入路径//写入result到目标文件路径//参数1:文件的绝对路径//参数2:文件内容fs.writeFileSync(fileDestDir,result)mode板文件相关这里就是把需要自动生成的文件根据自己的需要放在模板目录下。如果没有改动或统一文件,则不需要使用模板引擎1.模板路径:templates;2.平时整理项目结构整体复制到模板中,如:vue示例源文件、lint文件、package.json等;测试模块可用于本地开发,使用npmlink关联模块目录和依赖该模块的项目node_modules目录;也可以发布到npmsources上传后直接安装使用模块。1.关联模块:>cdnodejs-cli-sample//NodejsCli应用所在目录>npmlink//将模块连接到全局2.执行模块:>cdnodejs-cli-demo//执行模块intheprojectdirectory>ncl//直接执行模块,使用模块名(ncl为项目nodejs-cli-sample的名称)发布NodejsCli应用1.可以直接使用npmpublish发布到source>npmpublish--registry=https://registry.xxxx2,考虑npm源是否有写权限,可以发布到你公司的npm源或者yarn源//淘宝镜像源是只读的,不能bepublished//发布到yarn镜像源后,使用淘宝镜像源时,可以手动同步加速模块下载yarnpublish--registryhttps://registry.yarnpkg.com/完整示例代码1.NodeJsCli应用cli.js入口文件#!/usr/bin/envnode//NodeCLI应用入口文件必须有这样一个文件头//如果是linux或者macOS系统下,需要这个文件的读写权限修改为755//具体通过chmod755cli.js实现修改constfs=require('fs')//文件读写constpath=require('path')//获取路径constinquirer=require('inquirer')//命令行用户交互constejs=require('ejs')//模板引擎//脚手架工作过程:开始=>命令行向用户提问=>结合问题答案+模板=>生成结构fileinquirer.prompt([{type:'input',name:'name',message:'请输入项目名称(\'\')'},{type:'input',name:'version',message:'请输入项目版本Thisnumber(1.0.0)'},{type:'input',name:'description',message:'请输入项目备注(\'\')'},{type:'input',name:'author',message:'Pleaseentertheauthorname(\'\')'}]).then(anwsers=>{//anwsers:{name:"xxx"}//anwsers返回一个结果对象//绝对路径模板目录的consttmplDir=path.join(__dirname,'templates')//目标目录constdestDir=process.cwd()//读取目录中的所有文件letreadFiles=(dir)=>{returnnewPromise((resolve,reject)=>{//参数一:目录路径//参数二:回调函数(错误对象,files是相对文件路径的数组)fs.readdir(dir,(err,files)=>{if(err)reject(err)resolve(files)})})}//处理模板文件letejsRender=(file)=>{returnnewPromise((resolve,reject)=>{//模板文件的绝对路径letdir=path.join(tmplDir,file)//参数1:文件路径//参数2:数据对象//参数3:回调函数(错误对象,渲染后的新文件)ejs.renderFile(dir,anwsers,(err,result)=>{if(err)reject(err)resolve(result)})})}//1.先读取目录下的所有文件//2.使用ejs渲染allfilesTemplate//3.将新文件写入目标路径readFiles(tmplDir).then((files)=>{files.forEach(file=>{ejsRender(file).then((result)=>{//target文件的绝对路径,file其实是文件的相对路径letfileDestDir=path.join(destDir,file)//将结果写入目标文件路径//参数1:文件的绝对路径//参数2:渲染后的新文件fs.writeFileSync(fileDestDir,result)},throwError)})},throwError)})/***错误处理函数*@param{*errorobject}error*/functionthrowError(error){throwerror}2.package.json示例模板文件,使用ejs模板引擎{"name":"<%=name%>","version":"<%=version%>","description":"<%=description%>","author":"<%=author%>","bin":"cli.js","scripts":{"test":"echo\"错误:没有指定测试\"&&exit1"},"license":"ISC"}特别鸣谢:拉勾教育前端高薪训练营