脚手架
TIP
脚手架是一种用在建筑领域的辅助工具,或者说是为了保证各施工过程顺利进行而搭设的工作平台。
对应到软件工程领域,脚手架可以解释为帮助开发人员在开发过程中使用的开发工具、开发框架,使用脚手架你无须从头开始搭建或者编写底层软件。
脚手架它的本质作用就是帮助开发者创建项目基础结构、提供项目规范和约定,使开发者可以方便地将注意力集中到业务开发本身。当我们开发相同类型项目时都会有一些相同的约定,包括:
- 相同的文件组织结构
- 相同的开发范式
- 相同的模块依赖
- 相同的工具配置
- 相同的基础代码
那么这样就会导致我们在搭建新项目时有大量的重复性工作要去做,脚手架工具就是为了解决这样问题的。我们可以通过脚手架工具去搭建特定项目类型的骨架,然后基于骨架去完成后续的开发工作,例如IDE(Android Studio)创建项目的过程就是一个脚手架的工作流程。
由于前端技术选型多样,没有统一的标准,所以它的脚手架一般不会放在IDE中,都是以独立的工具存在,而且相对复杂一些。
脚手架的价值
复用原则(Reuse Principle):现在我们推崇的是极致化的编程体验,缩短的开发时间、大量的开发任务、支持需求的变更、高频率的应用服务交付。这些都给软件开发人员带来了前所未有的压力。其中,软件复用技术被公认为解决这些问题的行之有效的方法。从计算机软件编程的发展历史来看,从面向过程的编程语言到面向对象的高级编程语言的广泛使用,是软件复用技术进步的体现。从对象的复用到更大的组件复用,再到如今的框架的复用、服务的复用,都是在利用他人的优秀成果来放大你的工作价值。当一个新手使用脚手架时,对于一个具体问题,可以套用县城的解决方案加以扩展。使用脚手架的应用,仅需通过简单的朱姐和配置就可以具备健康状态检查、生产环境就绪、可观测等基本服务能力。对于一个业务逻辑问题,可以复用已有的逻辑,一步步迭代,敏捷开发。
DRY原则(Dont't Repeat Yourself):DRY原则直译过来就是不要重复你自己,这一原则和复用原则类似,强调尽量在项目中减少重复的代码行、重复的方法、重复的模块。其实,软件设计原则和模式最本质的思想都是消除重复。
我们经常提到的重用性和可维护性其实是基于减少重复这一简单而重要的思想的。DRY原则意味着系统内的每一个部件都应该是唯一的,并且是具有明确含义的(不模糊的)。我们可以通过应用职责单一、接口隔离等原则尽量拆分系统、模块、类和方法,使每一个部件都是职责明确且可重复使用的。
- 开闭原则(Open Close Principle):开闭原则中的开就是指对功能的扩展是开放的,闭是指对于原有代码的修改是封闭的。通俗一点讲,软件系统通常是由各种模块组成的,软甲你系统在增加一项新的功能时,应该在不修改现有代码的基础上操作。实现开闭原则的关键就是抽象,从微观的角度讲,开闭原则适用于一个业务模型的类的设计,把系统内的所有可能行为抽象为一个抽象底层,在这个抽象底层中规定需要提供的方法接口,具体实现类通过集成、代理、委托的方式,扩展实现新的行为或者新的功能。从宏观的角度讲,我们说开闭原则就是将公共模块、开发约定、最佳技术实践经过共享、提炼沉淀到封闭的底层技术基座。而将变化频繁的业务模块、独特的功能逻辑通过集成、组合和集成的方式实现对扩展的开放。
脚手架需求评审
脚手架为了更便于支持开发, 提供了一些实用命令,诸如创建项目、创建模块、测试、打包、发布,初次之外,可以根据自己的的项目需要继续拓展脚手架功能。
创建项目
创建项目主要流程包含:
- 初始化创建环境
- 项目配置引导
- 获取项目模板
- 安装项目依赖
- 完成项目创建
初始化创建环境用于对一些创建相关依赖的检测,比如:Node版本。
项目配置引导包含开发者输入项目相关信息,包含:项目名称、项目描述、项目所需模板选择等
通过前面配置,决策出拉取什么项目模板,并拉取
通过前面配置,决策出拉取什么项目模板,并拉取
拉取完模板后,执行依赖安装
项目创建完成,进程结束
打包项目
打包项目主要流程包含:
- 检测打包环境(版本等信息)
- 配置打包环境,例如使用rollup等库
- 打包
- 打包完成
监听模式启动项目
监听模式启动项目可以实现热更新,实时代码lint等功能,原理类似于webpack热更新
'--entry, -i ','Entry module'
'watch --entry src/foo.tsx'
'--target','Specify your target environment', 'browser'
'watch --target node'
'--name','Specify name exposed in UMD builds'
'watch --name foo'
'--format','Specify module format(s)','cjs,esm'
'watch --format cjs,esm'
项目代码检测
借助eslint可实现项目代码检测,我们通常需要再项目打包构建时,一并执行代码的检测和格式化以及代码压缩
关于eslint及使用,详见https://eslint.org/docs/developer-guide/nodejs-api
创建模块
从模板中获取模块模板,并替换模块中的占位数据,根据键入的配置信息生成新模块,流程如下:
- 拉取模块
- 替换模块占位信息
- 生成新模块
检测当前项目信息
该命令可实现对项目的环境检测,例如当前项目版本、依赖版本及其他相关信息
常用的脚手架工具
市面上有很多的脚手架工具,但是大都是为了特定项目类型服务的。例如:
- React项目使用create-react-app
- Vue项目使用vue-cli
- Angular项目使用angular-cli
这些工具都大同小异,根据开发者提供的信息自动的生成项目的特定文件、相关的配置等项目基础结构。
还有一类像Yeoman为代码的通用型脚手架工具,它可以根据一套模板生成对应的项目结构,这种类型的脚手架工具很灵活也很容易去扩展。
还有一类脚手架工具Plop,它们在项目开发的过程中创建特定类型的文件,例如创建一个组件或模块所需要的文件,这类模块一般是由特定的文件组成的,而且都有基本的代码结构,相比手动创建,脚手架有更为便捷的创建方式。
Yeoman
Yeoman的slogan是“THE WEB'S SCAFFOLDING TOOL FOR MODERN WEBAPPS”——面向webapp的脚手架工具。Yeoman不能直接创建项目文件,它提供了一套完整的脚手架开发者API,使用这些API可以定制符合自己业务需求的任意脚手架方案。换句话说,Yeoman不封装任何方案,它是完全开放、高度可扩展的。
脚手架的工作原理
大部分脚手架工具都很简单,在启动脚手架之后,会自动询问一些预设的问题,然后根据开发者回答的结果结合模板文件生成项目的结构。脚手架工具就是一个Node cli应用,那我们可以创建一个cli应用。
mkdir test-cli && cd test-cli
npm init
创建完项目后可以新建一个cli.js,在文件中先声明一个文件头。
//cli.js
#! /usr/bin/env node
//Node cli应用入口必须要有这样的文件头
脚手架的工作过程分为两点:1. 通过命令行交互询问用户问题,2. 根据用户回答的结果生成文件
命令行交互询问使用inquirer库来实现。
npm install inquirer --save
生成文件可以使用ejs模板引擎来实现
命令行工具原理和实现
现代脚手架离不开命令行工具,命令行工具即 Command-line interfaces(CLIs) ,是编程领域的重要概念,也是我们开发中经常接触到的工具之一。
比如 Webpack、Babel、npm、Yarn 等都是典型的命令行。此外,流畅的命令行能够迅速启动一个脚手架,实现自动化和智能化流程。这一部分,我们就使用 Node.js 来开发一个命令行。
我们先来看几个开发命令行工具的关键依赖。
- inquirer、enquirer、prompts:可以处理复杂的用户输入,完成命令行输入交互。
- chalk、kleur:使终端可以输出彩色信息文案。
- ora:可以让命令行出现好看的 Spinners。
- boxen:可以在命令行中画出 Boxes 区块。
- listr:可以在命令行中画出进度列表。
- meow、arg:可以进行基础的命令行参数解析。
- commander、yargs:可以进行更加复杂的命令行参数解析。
脚手架方案设计
技术选型
- commander处理命令
- enquirer命令行交互
- chalk为命令上色
- semver环境检测,依赖约束
- fs-extra文件操作
初始化脚手架项目
- 创建node项目
- 安装commander,编写一个hello命令,实现控制台输出"你好"
- 发布到本地包
- 使用这个脚手架
定义一个项目模版
准备模板
通常,模板的获取有两个途径:
- 本地定义,更方便,但是更新相对比较麻烦
- 单独托管到github,创建时拉取,方便更新和维护,但是因为受网络影响,可能会影响用户使用体验
选择模板
如果我们项目需要配置很多模板,则可以定义多模板,然后根据项目模板选择,拷贝指定模板生成新项目
打包与检测
打包我们可以选择rollup提供的node api进行,代码检测可以使用eslint提供的node api进行。
脚手架调试
当我们本地开发脚手架的时候总不能将脚手架发布到npm仓库中再安装使用太繁琐,这时候我们就需要脚手架本地调试的能力。在这里介绍一个命令
npm link
使用 link 命令将脚手架 link 到 node 的全局目录,同时指向 node _modules中,效果和我们全局安装是一样的。
如果我们要从全局移除该脚手架的话就需要使用以下命令
npm unlink
npm unlink是将当前项目从 node 全局 node _modules中移除