脚手架。这个名词对于作为前端的我们来说可能并不陌生,比如vue-cli、react-native-cli等,全局安装后,只需要在命令行中输入简单的命令,就可以帮助我们快速生成一个initialproject,如vueinitwebpackprojectName,生成一个初始的vue项目。本文主要介绍一个简单脚手架的开发,了解开发的基本流程,最后通过npmlink链接到全局包。脚手架的作用1.减少时间,不必从头开始搭建初始项目,提高开发效率。2、方便多人协作。3、项目更新同步方便。您只需要更新代码库中的项目模板即可下载最新的项目。Node相关基础知识在开始项目之前,先简单介绍一下Node相关的一些基本知识。当一个node项目通过npminit初始化时,会生成一个package.json配置文件,包含项目名称、版本、作者、依赖等信息,主要说说bin字段。许多包都有一个或多个可执行文件,这些文件应该放在PATH中(事实上,这一特性使npm可执行)。当要使用该功能时,需要在package.json中的bin字段中添加命令名,并指向要执行的文件(即后面的入口文件)。在初始化的时候,npm会把他链接到prefix/bin(全局初始化)或者./node_modules/.bin/(局部初始化)。例如,npm有:{"bin":{"npm":"./npm-cli.js"}}所以,当你初始化npm时,它会在/usr中创建一个指向npm-cli.js脚本的符号链接/本地/bin/npm。如果你只有一个可执行文件,并且名称与包名相同。然后你可以只使用像这样的字符串:{"name":"my-program","version":"1.2.5","bin":"./path/to/program"}结果是一样的this:{"name":"my-program","version":"1.2.5","bin":{"my-program":"./path/to/program"}}想了解包。json更详细的配置可以参考这篇文章。开发脚手架首先要理清思路。脚手架是如何工作的?我们可以借鉴vue-cli的基本思想。vue-cli将项目模板放到git上,然后运行时根据用户交互下载不同的模板,通过模板引擎渲染生成项目。这样模板和脚手架就分开了,可以分开维护。即使模板发生变化,也只需要上传最新的模板,即可生成最新的工程,无需用户更新脚手架。那么就可以按照这个思路来开发了。初始化项目新建一个文件夹,打开命令行工具,通过npminit初始化项目,在项目根目录下会生成一个package.json文件。npminit安装依赖npminstallcommanderdownload-git-repoinquirerhandlebarsorachalklog-symbolsshelljs-S另外使用了nodejs内置的几个模块:fs、path、child_processcommander.js:可以自动解析命令和参数用于处理用户输入的命令。download-git-repo:下载并解压git仓库,用于下载项目模板。Inquirer.js:一组用于与用户交互的通用命令行用户界面。handlebars.js:一个模板引擎,可以用用户提交的信息动态填充文件。ora:如果下载过程耗时较长,可用于显示下载过程中的动画效果。chalk:您可以为终端的字体添加颜色。log-symbols:终端可以显示√或×等图标。fs:node内置的文件处理模块。path:Node内置的路径处理解析模块。child_process:在node.js中创建一个子进程模块。配置入口文件1.在package.json文件中添加bin字段,暂且命名为okcli。“bin”:{“okcli”:“./index.js”}2。在项目根目录新建index.js文件,在index.js文件顶部添加如下代码:#!/usr/bin/envnodefordevelopment。这里简单介绍下这行代码的含义。!/usr/bin/node告诉操作系统在执行这个脚本时调用/usr/bin下的节点解释器;!/usr/bin/envnode用于防止运行系统用户没有在默认的/usr/bin路径下安装node。系统看到这一行,会先在env设置中搜索node的安装路径,然后调用相应路径下的解释器程序完成运行。!/usr/bin/node相当于把节点路径写死;!/usr/bin/envnode会去环境设置里找node目录。推荐这种写法来处理命令行constprogram=require('commander');constinquirer=require('inquirer');constsymbols=require('log-symbols');constdownload=require('download-git-repo');consthandlebars=require('handlebars');=要求(“粉笔”);constora=require('ora');constshell=require('shelljs');constchild_process=require('child_process');constfs=require('fs');constpath=require('路径');program.version('1.0.0','-v,--version').command('init').action((name)=>{console.log(name);});程序.parse(process.argv);调用program.version('1.0.0','-v,--version')会在命令行添加-v和--version,调用可以通过添加这个参数获取脚手架的版本号(command-v/--version),并调用comand('init')来定义初始化命令。name参数必须作为项目的文件夹名称传递,比如vueinitwebpackparajectNameaction是command命令执行时的回调。参数为命令行输入的名称,即init中的名称,工程生成过程发生在回调函数中。现在可以调用nodeindex.jsinittest,可以看到控制台打印了输入的项目名test。其中:program.parse(process.argv)解析命令行中的参数,解析出名字,传入action回调。通过download-git-repo下载模板或者直接使用shelljs或者child_process直接运行命令下载模块(个人选择第三种)。download-git-repo支持从Github、Gitlab和Bitbucket下载存储库。具体使用请参考官方文档。download('https://github.com/jefferyE/webpack-configuration-for-vue',name,{clone:true},(err)=>{if(err){//spinner.fail();console.log(symbols.error,chalk.red(err));}else{//spinner.fail();}})或者if(shell.exec('gitclonehttps://github.com/jefferyE/webpack-configuration-for-vue').code==0){//spinner.succeed();}else{//spinner.fail();console.log(symbols.error,chalk.red('模板下载失败'))}或child_process.exec('gitclonehttps://github.com/jefferyE/webpack-configuration-for-vue',function(err,stdout,stderr){if(err){//spinner.fail();console.log(symbols.error,chalk.red('模板下载失败'))}else{//spinner.succeed();}})其中:download()的第一个参数是仓库地址,但是有点区别。实际仓库地址为https://github.com/jefferyE/w...,可以看到参数中端口号后面的'/'应该写成':',#master代表分支名称,不同的模板可以放在不同的分支,改变分支就可以下载不同的模板文件。第二个参数是路径。上面我们直接在当前路径下创建一个名为name的文件夹来存放模板,或者使用二级目录如test/${name}来与命令行进行交互。用户执行init命令后,即可执行命令行交互功能,向用户提问,接收用户输入并进行相应的处理。这个是使用inquirer.js实现的,也可以自己使用node内置的readline模块。具体可以参考我的文章inquirer.prompt([{type:'input',name:'author',message:'请输入作者姓名'}]).then((answers)=>{console.log(answers.author);})从这个例子可以看出,问题是放在prompt()中的,问题的类型是input,也就是输入类型,name是answer对象中的key,message是问题,以及用户输入的答案就在答案中,使用起来就是这么简单。更多参数设置请参考官方文档。渲染包模板这里使用handlebars的语法对HTML5/H5Template仓库模板中的package.json文件做一些修改。并在模板下载完成后将用户输入的答案渲染到package.json中。{"name":"{{name}}","version":"1.0.0","description":"{{description}}","scripts":{"test":"echo\"错误:notestspecified\"&&exit1"},"author":"{{author}}","license":"ISC"}注意:由于我的项目没有更改包模板,下载模板后,parse是动态修改。此外,还通过ora和chalk模块进行了一些视觉美化。详情请参考完整代码。完整代码如下:#!/usr/bin/envnodeconstprogram=require('commander');constchalk=require('粉笔');constora=require('ora');constfs=require('fs');constinquirer=require('inquirer');constshell=require('shelljs');constsymbols=require('log-symbols');constdownload=require('download-git-repo');constchild_process=require('child_process');consthandlebars=require('handlebars');constpath=require('路径');program.version('1.0.0','-v,--version').command('init').action(name=>{console.log(name);if(!fs.existsSync(name)){console.log('Creatingproject...');inquirer.prompt([{name:'description',message:'Pleaseenteraprojectdescription'},{name:'author',message:'请输入作者姓名'}]).then(answers=>{console.log(answers)constspinner=ora('正在下载模板...\n');spinner.start();child_process.exec('git氯一个https://github.com/jefferyE/webpack-configuration-for-vue',function(err,stdout,stderr){if(err){spinner.fail();console.log(symbols.error,chalk.red('模板下载失败'))}else{spinner.succeed();shell.mv(__dirname+'/webpack-configuration-for-vue',__dirname+'/'+name)constfilename=`${name}/package.json`;constmeta={name,description:answers.description,author:answers.author}if(fs.existsSync(filename)){constcontent=fs.readFileSync(filename).toString();让dt=JSON.parse(内容);dt.name='{{name}}';dt.description='{{description}}'constresult=handlebars.compile(JSON.stringify(dt,null,2))(meta);fs.writeFileSync(文件名,结果);console.log(symbols.success,chalk.green('项目初始化完毕'));}else{console.log(symbols.error,chalk.red('包不存在'))}}})})}else{console.log(symbols.error,chalk.red('项目已经存在'));}})program.parse(process.argv);其中:1、用户输入答案后,开始下载模板。这时候用ora提醒用户下载正在进行中2.然后用chalk打印信息添加样式,比如成功信息用绿色,失败信息用红色,方便用户区分,也让终端的展示更具吸引力。3、印刷信息除了可以加色外,还可以用对数符号在信息前加上√、×等图标。完成后可以将脚手架发布到npm,通过-g全局安装,在自己的机器上执行okcliinit[name]初始化项目,这样就完成了一个简单的脚手架工具。linkglobal命令在根目录中运行npmlink命令,将包链接到全局环境中。npmlink命令可以将任意位置的npm包链接到全局执行环境,从而可以在任意位置使用命令行直接运行npm包。详情请参考本文感谢:参考文章第1条第2条