下一篇传送门:从零开始搭建一个节点脚手架工具(二)前言在实际开发中,我们总会遇到各种各样的脚手架工具。从vue-cli,create-react-app,从头开始搭建项目结构,到保存代码片段的smallsnippets,都为我们的开发带来了很多便利。这些脚手架工具各有优缺点。比如vue-cli只支持创建Vue项目,定制化程度低,而snippets过于轻量,不支持多人协作开发。因此,在学习了node之后,我打算做一个符合自己需求的node脚手架工具。贴上脚手架工具的github地址供参考:YOSO:Youonlysetoncetypescript我选择的开发语言是typescript。众所周知,javascript是一种动态类型的语言,这使得我们在开发时不太关注对象的类型。这确实带来了一些方便,有时可以使代码简洁,但有时也会带来麻烦。比如很久以前写的一个函数,如果没有好的注释,你可能记不住这个函数的输入输出是什么。或者在重构代码的时候,给函数加了一个参数,一不小心很容易错过某个调用。特别是对于大型项目,这增加了程序员的负担。Typescript是javascript的超集,支持javascript的所有语法,可以编译成纯javascript运行。它的主要特性之一是静态类型。与动态类型相比,除了需要更多类型代码外,它还有更多优势。检测错误typescript的第一个优点是可以在编译时检测到类型错误,而不是等到上线后才发现。编程规范typescript的另一个优点是它加强了编程规范。它提供了一种定义接口的简单方法。系统模块可以抽象为由typescript定义的接口。一种更抽象的设计形式是将大型系统构建为具有清晰接口的模块。代码可读性类型注解对于提高代码可读性也有很大的帮助。同时,利用typedoc等工具,还可以轻松生成文档。决定使用typescript之后,开发的时候还有几点需要注意。首先,既然决定使用typescript,就一定要充分利用它的优势。写类型的时候,不要一直用any,定义多少接口就用多少,否则会是负担。考虑到复用性,可以在减速文件中定义常用的类型,方便参考。在typescript中导入npm包时,有时会出现Couldnotfindadeclarationfileformodule的错误。这是因为大多数JavaScript库没有打字稿类型定义。为了解决这个问题,DefinitelyTyped应运而生。这是一个高质量的typescript类型定义存储库,您可以通过npminstall@types/jquery--save-dev将类型定义添加到库中。如果在DefinitelyTyped中没有找到你想要的库,不要使用import方法,改用require引用,也可以避免报错。在正式开发设计之前,必须先做好设计。整个项目的结构我参考了nest-cli的结构,主要包括:bin文件夹下的入口文件commands文件夹,存放模块化的命令文件,用于接收和解析输入的命令,以及命令在nest-cli的文件夹如下。命令├──abstract.command.ts├──add.command.ts├──command.input.ts├──command.loader.ts├──generate.command.ts├──index.ts├──info.command.ts├──new.command.ts└──update.command.tsactions文件夹,存放模块化动作文件,用于处理和执行命令。nest-cli中的actions文件夹如下。actions├──abstract.action.ts├──add.action.ts├──generate.action.ts├──index.ts├──info.action.ts├──new.action.ts└──update.action.ts.gitignore、tsconfig.json、npm相关文件等,这些文件应该遵循行业规范。可以参考我的项目脚手架工具的工作流程如下。命令行处理会用到commander、inquirer等第三方库。另外,我选择使用react+ink来开发ui,让交互界面更好用。加载模板时,我选择从github仓库加载,这需要了解github的相关API,记录用户的github仓库地址。模板引擎我选择了Mozilla的nunjucks。之所以没有选择比较出名的handlebars、pug、ejs等模板引擎,是因为这些模板引擎主要是针对html语言的。为了防止xss攻击,会有很多转义处理。如果要生成js等文件作为脚手架工具,那就比较麻烦了。而且nunjucks默认是不做转义的,各方面都差不多的时候更适合我们的脚手架工具。最后,对于文件操作,node自带的fs工具可以完成。开始开发项目初始化完成,设计完成后,就可以开始正式的开发了。第一步是完成一些琐碎的事情,给项目起个名字。在命名之前,可以使用npminfoname查看是否有重名。新建一个git仓库存放项目代码,并在本地创建相应的目录连接远程仓库。使用npminit命令初始化并生成package.json文件。因为我们要使用typescript进行开发,所以需要安装typescript。然后创建一个tsconfig.json文件,在tsconfig.json中设置typescript相关的配置项。这时候可以运行tsc看看js文件是否可以正常编译。然后根据我们的设计,创建这些我们需要的文件夹,并在bin文件夹中新建一个入口文件,一般和输入的命令同名,我这里叫yoso.ts。然后在package.json中添加配置项。"scripts":{"build":"tec"}"bin":{"yoso":"bin/yoso.js"}需要注意的是,虽然我们使用typescript进行开发,但实际上最终还是会编译成js要运行,我们发送的npm包也必须是编译好的js代码。所以这里虽然创建了bin/yoso.ts,但是yoso.js还是写在了package.json里面。然后进入yoso.ts文件,写:#!/usr/bin/envnodeconsole.log("yoso!")#!/usr/bin/env开头的node不能少,指定的路径节点环境。保存,然后就可以测试了。调试和发送包你当然可以选择在构建之后运行测试,但这确实很愚蠢。要测试ts代码,您可以选择使用ts-node。安装npminstall-Dts-node后,将脚本"scripts"添加到package.json:{..."start":"ts-nodebin/yoso.ts"}然后运行??npmrunstart或npmstart,如果你看到输出yoso!,就成功了。那你可以发个包试试。去npm注册一个账号,然后返回npmlogin。发送包前,先将package.json中的version修改为0.0.1,然后每次发送都要修改版本号。0开头的代表测试版本。然后编译ts文件,使用tsc命令修改.npmignore文件,忽略ts文件,但包含d.ts文件。我是这样写的,仅供参考。.idea/.gitignoretsconfig.json#docdoc/#testtest/#source**/*.ts*.ts#definitions!**/*.d.ts!*.d.ts编译完成后,使用npmpublish命令发送包。为了防止发包前忘记编译,建议添加npmhook命令脚本:{..."prepublish":"npmrunbuild","postpublish":"npmrunbuild:clear","build:clear":"find./actions./bin./commands./utils./ui./component-typef-name'*.d.ts'-delete&find./actions./bin./commands./utils./ui./component-typef-not-name'*.ts*'-delete",...}这样每次publish前都会自动编译,编译后的js文件发布后自动清除,这点很省心。发送包成功后,可以全局安装npminstall-gyoso,然后运行命令yoso。如果正常,可以看到输出。但是全局调试不需要每次都发一个包。编译后可以使用npmlink命令创建全局软链接,然后全局使用yoso命令即可。模块化然后我们可以编写模块化命令。这里使用了commander框架,可以先去github主页看例子。我在这里发布最简单的命令。program.command('exec
