2

最近对团队开发的脚手架研究了下并参与进去做了一点工作,觉得非常的有意思,自此开辟了前端学习的另一条道路。

目的

相信大家在开发过程中都遇到这样的问题:为了新建项目,要不停地拷贝文件,配置什么的,或者干脆从零开始,这样是非常浪费时间的。
这个时候,一个善解人意的scaffold就很被大家需要了,它可以仅用简单的命令就帮助我们完成项目的创建,编译打包,发布等工作,让我们可以专注于我们的核心业务。
总体来说,一个贴心的scaffold可以帮我们解决以下问题:

  • 减少重复性的工作,不再需要复制其他项目再删除无关代码,或者从零创建一个项目和文件。
  • 根据交互动态生成项目结构和配置文件等。
  • 多人协作更为方便,不需要把文件传来传去。

功能实现

通过命令行询问用户并获取用户输入参数,根据用户的输入参数进行项目的创建,启动,编译,发布,删除,更新依赖包等工作。

开发scaffold常用依赖包:

交互界面相关:scaffold需要通过命令行或者可视化工具与用户互动来获取用户的意图,这里我们采用命令行的方式询问用户并获取用户输入。下面的几个包可以帮助我们完成这些事情:
yargs 通过解析参数并生成优雅的用户界面来构建交互式命令行工具 https://www.npmjs.com/package...
inquirer 常见的交互式命令行用户界面的集合 https://www.npmjs.com/package...
chalk 可以修改控制台中字符串的样式 https://www.npmjs.com/package...

yargs用法示例:

#!/usr/bin/env node
require('yargs') // eslint-disable-line
  .command('serve [port]', 'start the server', (yargs) => {
    yargs
      .positional('port', {
        describe: 'port to bind on',
        default: 5000
      })
  }, (argv) => {
    if (argv.verbose) console.info(`start server on :${argv.port}`)
    serve(argv.port)
  })
  .option('verbose', {
    alias: 'v',
    type: 'boolean',
    description: 'Run with verbose logging'
  })
  .argv

用--help参数运行此段脚本如下:
image.png

node进程和文件操作相关:由于我们的scaffold是在node环境下运行,所以要用到很多node的API,最多的就是子进程child_process和文件系统fs,不过我们并没有使用原生的node API,而是尝试了一些兼容性更好,使用更方便的第三方node依赖包。
cpx linux的cp命令,多了watching功能 https://www.npmjs.com/package...
cross-spawn node的spawn和spawnSync的跨平台(window,macos等)解决方案 https://www.npmjs.com/package...
asnyc 处理异步javascript https://www.npmjs.com/package...
fs-extra 补充了node的fs模块,支持方法的promise https://www.npmjs.com/package...
replace 用于在文件上执行搜索和替换的命令行实用程序 https://www.npmjs.com/package...
empty-dir 检查目录是否为空 https://www.npmjs.com/package...

用法示例:

const spawn = require('cross-spawn');
 
// Spawn NPM asynchronously
const child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
 
// Spawn NPM synchronously
const result = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
文件编译相关:scaffold的开发过程中经常需要处理配置文件的创建,替换内容等,这些都与AST(抽象语法解析树)紧密相关。esprima和escodegen就是两个经常用的处理AST的依赖包。
esprima 将javascript解析成AST的解析器 https://www.npmjs.com/package...
escodegen 将AST生成javascript https://www.npmjs.com/package...

escodegen用法示例:

escodegen.generate({
    type: 'BinaryExpression',
    operator: '+',
    left: { type: 'Literal', value: 40 },
    right: { type: 'Literal', value: 2 }
});

esprima用法示例:

var esprima = require('esprima');
var program = 'const answer = 42';
console.log(esprima.tokenize(program));

// 可以看到把const answer = 42解析如下:
[
  { type: 'Keyword', value: 'const' },
  { type: 'Identifier', value: 'answer' },
  { type: 'Punctuator', value: '=' },
  { type: 'Numeric', value: '42' }
]
众多typescript类型文件

当使用第三方库时,我们需要引用它的声明文件,这样才能获得对应的代码补全、接口提示等功能。推荐使用 @types 统一管理第三方库的声明文件,比如@types/async,@types/cross-spawn,@types/empty-dir等。

总体来说开发scaffold是一件很有意思的事情,后面还会继续探索。

参考文章


雨花石
410 声望19 粉丝

人生没有彩排,每天都是直播