在日常开发中,我们经常使用脚手架工具来帮助我们创建项目,如vue-cli,create-react-app等,本文主要概述下什么是工程化,工程化主要解决的问题是什么,探讨如何使用Yeoman和Plop工具来搭建脚手架,最后来探讨下脚手架的基本原理。
前端工程化
前端工程化是指遵循一定的标准和规范,通过工具去提高效率,降低成本的一种手段,近些年被广泛的关注和探讨,究其原因主要是因为前端应用功能要求不断提高,业务逻辑日益复杂,从传统的网站,到现在的H5、移动web、桌面应用、以及小程序,前端技术几乎是无所不能全面覆盖,在这些表象的背后,实际上是前段行业我对我们开发人员的要求越来越高。
以往这种写Demo,套模板,再去调页面的这种“刀耕火种”方式,已经完全不符合对当下开发效率的要求,前段工程化就是在这样背景下被提上台面的,成为前端工程师必备的手段之一,技术是为了解决问题而存在的,前端工程化也不例外。
1. 工程化之前我们面临的一些问题:
想要使用ES6 +新特性,提高编码效率但是兼容有问题
想要使用 Less / Sass / PostCSS 提高 CSS 的编程性,但是这种工具在运行环境不能直接支持
想要使用模块化或者组件化的方式提高项目的可维护性,但实际运行环境不能直接支持
开发中经常会手动做的一些重复的工作,如部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器
多人协作开发,无法硬性统一大家的代码风格,从仓库中 pull 回来的代码质量无法保证
部分功能开发时,需要等待后端服务接口提前完成,才可以做具体的编码
2. 工程化主要解决的问题
传统语言或语法的弊端
无法使用模块化/组件化
重复的机械式工作
代码风格统一、质量保证
依赖后端服务接口支持
整体依赖后端项目
3. 工程化的表现
以项目开发过程为例,来看下工程化的表现:
创建项目阶段:使用脚手架自动完成项目基础结构的搭建;
编码阶段:借助工程化的工具,自动化的帮我们做一些代码的格式化和风格校验,确保在项目中每个开发人员写出的代码风格相似,借助一些编译工具,提高代码编码效率
预览/测试阶段:传统的预览需要借助Apache服务器提供基础的web服务,让应用可以在上面运行起来,但是没有热更新体验,除此之外在开发阶段会用到编译,编译就涉及到实际编写的代码和最终运行的代码有个转换,如果运行中存在问题需要借助source Map工具去定位到源代码所在的位置,使用mock方式可以解决,后端服务未完成的情况下提前开发业务功能,即写假接口方式,跟后端接口是以相同的规格存在的
提交阶段:使用Git Hooks 方式自动化的在代码提交之前对项目做整体的检查,包括项目质量检查和项目风格检查
部署阶段:使用命令代替传统的FTP上传,还可以实现代码提交后自动化的通过持续集成或者持续部署的方式自动将我们代码部署到服务器,避免了手动操作产生的不稳定的因素
一切重复的工作都应该被自动化。实现前端工程化可以从 模块化、组件化、规范化、自动化等方面出发。
4. 工程化不等于工具
工程化是对项目整体的一种规划或者架构,工具只是实现规划或者结构的手段
如上图 一个工程化应该有的过程是规划项目整体的工作流架构,包括文件的组织结构,源代码的开发范式,以什么样的方式做前后端分离(基于ajax还是中间层),明确规划后再根据这些规划来搭配工具做具体的配置选项,从而实现工程化整体的规划等
一些成熟的工程化集成:create-react-app、vue-cli、angular-cli、gatsby-cli工具,需要注意的是这里工具不是脚手架,不同于之前的工具,这里的工具属于特定类型的项目官方给出的集成式工程化方案,以vue-cli为例,它不仅仅帮我们创建了项目,更多的是约定了vue项目应该是什么样的结构,提供了热更新开发服务的工具,自动编译单文件组件以及其他的模块文件,代码风格校验等,这些都是集成在vue-cli内部的server中。
5. 工程化与Node.js
工程化的一切都应该归功于Node。
如果说Ajax给前端带来了新的生命力,那么Node对于前端而言,它除了让JavaScript有了一个新的舞台,更多的是让我们整个前端行业进行了一次工业革命,可以毫无夸张的说,没有Node.js,就没有今天的前端。
前端工程化是由Node.js强烈驱动的。
脚手架工具
概要
简单来说,脚手架就是用来自动的去帮我们创建项目基础文件的一个工具。脚手架工具,可以认为是前端工程化的发起者。
脚手架工具的作用
创建项目基础结构、提供项目规范和约定。
一般来说,一个项目中包含一些相同的约定,即:
相同的组织结构
相同的开发范式
相同的模块依赖
相同的工具配置
相同的基础代码
我们可以通过脚手架工具去快速搭建特定类型项目的骨架,然后去基于这个骨架进行后续开发工作。因为前端技术选项比较多样,也没有一个统一的标准,所以前端方向的脚手架不会集成在某一个IDE当中,都是以一个独立的工具存在,相对会复杂些。
脚手架目标都是一样的,都是为了解决我们在创建项目过程当中那些复杂的工作。
常用的脚手架工具
适用于特例项目类型服务的脚手架工具
目前一些成熟的脚手架工具(但大都是为了一些特例项目类型服务的):
React项目 => create-react-app
Vue.js项目 => vue-cli
Angular项目 => angular-cli
这些工具的实现方式都大同小异,无非都是根据信息创建对应的项目基础结构。
- 通用性脚手架工具: Yeoman
Yeoman
概述
Yeoman是基于Nodejs开发的模块,是一款用于创造现代化web应用的脚手架工具,不同于cli工具,Yeoman更像是一个脚手架运行平台,我们可以通过它,搭配不同的Generator,去创建任何类型的项目。
基于Yeoman搭建一个项目类型的脚手架
- 全局范围安装Yeoman
1 | $ yarn global add yo #or npm install yo --global |
安装项目模板:Generator
Yeoman 需要搭配特定的 Generator 使用,在这里使用的node_module,因此还需要全局安装 generator-node
1 | $ yarn global add generator-node # or npm install generator-node --global |
通过yo运行对应的Generator
使用 Yeoman 提供的yo命令,去运行generator-node生成器。运行特定的生成器,就是将generator-前缀去掉,直接使用yo运行后面的部分即可。
1 | $ yo node |
运行结果如下:
项目结构,如下图所示:
Sub Generator
有时候我们不需要创建完整的项目结构,可能是在已有的项目基础上创建一些特定类型的文件,比如在原有项目中添加一些配置,如eslit,babel文件,都会有一些基础的文件,可以通过生成器自动生成,可以使用Yeoman提供的Sub Generator特性进行实现,具体实现是在项目中运行特定的Sub Generator命令,生成对应的文件
- 使用 generator-node中的子集的生成器,即cli生成器,它可以生成cli应用所需要的一些文件。
1 | $ yo node:cli # or yo + generator的名字 + : + Sub Generator的名字 |
- 通过以下命令,将这个模块连接到全局范围,使其可以作为全局的命令行模块进行使用。
1 | $ npm link # or yarn link |
可以看到,此时会将新的模块生成的依赖包,存放到 npm 应用程序的本地数据文件夹中。
- 安装项目依赖。
1 | $ yarn |
- 全局访问生成的模块
1 | $ my-module --help |
注意:并不是每一个 generator 都存在子集的生成器,需要以官方文档为准。
基于Yeoman自定义一个脚手架工具
基于Yeoman自定义一个脚手架工具,这个脚手架工具通常用来搭建项目类型的脚手架。实现上其实也就是自定义Yeoman的Generator,在这个过程中我们需要准备自己的脚手架模板项目并编写自己的generator模块。与Plop一样,相对于完全自定义实现脚手架脚本 / 工具而言,使用Yeoman虽然不能实现完全的自定义,但在它的规范下编写脚本可以调用它封装好的Api,可以简化脚本的编写。这让我们能够更加关注任务本身,而无需关注过多任务的实现细节,进而提高开发效率。
命名规范
如果命名不规范,那么后期 Yeoman 就无法找到所定义的生成器模块。
1 | generator-name |
以自定义Vue Generator为例:
- 创建generator-eline-vue文件夹,并创建及初始化package.json包管理文件,以及安装yeoman-generator模块
1 | $ mkdir generator-eline-vue |
将 vue中生成的目录结构,拷贝到Generator中,使其作为模板文件存在,如下图所示:
根据自定义 Generator 步骤,在 index.js 入口文件中,解析项目模板创建项目。
1 | // 此文件作为Generator的核心入口 |
- 通过以下命令,将这个模块连接到全局范围,使其可以作为全局的命令行模块进行使用。
1 | $ npm link # or yarn link |
可以看到,此时会将新的模块生成的依赖包,存放到npm应用程序的本地数据文件夹中。
*执行 yeoman 操作,创建一个跟模板相同的新项目
1 | $ yo eline-vue |
- 将generator模块发布到GitHub和npm中
在发布之前,首先将项目的源代码托管到公开的代码仓库里面,这里我们使用GitHub。
这里就不在介绍,具体可参考GIT关联本地仓库与远端仓库
在命令行界面输入发布命令,需要确保在npm中有注册账号。
1 | $ yarn publish # or npm publish |
发布成功后可以去npm官网,查看刚刚发布的模块,如下图所示:
需要注意:若使用淘宝的镜像资源,则会报错下面的错误,这是由于淘宝镜像是只读的,不能将模块进行发布
- 可以改变镜像资源
1 | $ npm config set registry https://registry.yarnpkg.org # yarn 镜像源 |
- 在命令后面,直接跟上相关的镜像资源
1 | $ yarn publish --registry-https://registry.yarnpkg.com # yarn 镜像源 |
发布报错时候可以参考yarn publish 报错和npm发布包
基于Plop搭建单 / 多文件类型的脚手架
基本介绍
plop是一个在日常开发当中非常值得且频繁使用的小工具,在我们碰到需要搭建一个单/多文件类型的脚手架需求,比如搭建一个react组件脚手架(需要创建一个.js模板文件、一个.css模板文件以及一个.test.js模板文件),Plop就会是一个不错的助手。相对于完全自定义实现脚手架脚本/工具而言,使用Plop虽然不能实现完全的自定义,但在它的规范下编写脚本可以调用它封装好的Api,实现配置化的脚手架工具。这让我们能够更加关注任务本身,而无需关注过多任务的实现细节,进而提高开发效率。
接下来主要关注下Plop自动化搭建脚手架的工作流程,具体的使用细节查看官方文档Plop
基本使用
这里以react为例,集成Plop。
- 创建react项目
1 | $ npx create-react-app my-react-app |
- 将 plop 模块作为项目开发依赖安装
1 | $ yarn add plop --dev # or npm install plop -D |
- 在项目根目录下,新建一个 plopfile.js 文件,定义 Plop 脚手架任务
1 | // Plop 入口文件,需要导出一个函数 |
- 创建对应的模板文件,模板文件采用Handlebars模板引擎进行书写,一般放置在根目录下的plop-templates下
components.hbs
1 | import React from 'React' |
components.css.hbs
1 | .{{name}} { |
components.test.hbs
1 | import { render, screen } from '@testing-library/react'; |
- 在安装 plop 时,Plop 提供了一个 CLI 的应用程序,由于yarn会自动找到node_modules下的bin目录下的命令行工具,所以可以通过 yarn 去启动这个程序
1 | $ yarn plop component # yarn plop 生成器的名称 |
执行结果,如下图所示:
执行成功后,我们可以去对应的文件夹下,找到生成的文件,如下图所示:
脚手架工作原理
通过前面对脚手架工具的介绍,我们不难发现,大部分脚手架的工作原理都很简单,无外乎就是启动之后,它会自动的询问一些预设的问题,然后将回答的结果结合一些模板文件生成一个项目的结构,我们都知道脚手架工具就是一个 node cli 的应用,去创建脚手架工具,就是创建cli的应用,接下来通过nodejs开发一个小型的脚手架工具,在深入体会下脚手架工作的过程
通过 在package.json 中添加属性bin,设置入口文件,用于指定CLI应用的入口文件
编写 cli.js 文件,与以往的入口文件不同的,Node CLI 应用入口文件必须要有特定的文件头
#!/usr/bin/env node
,如果是Linux或者macOS系统下还需要修改此文件的读写权限为755
1 | // 使用inquirer模块实现用户交互 |
1 |
|
创建模板,这里主要是关注脚手架的工作过程,不需要太过关系模板里面有什么,创建一个简单的html和css文件
执行脚本,生成项目结构
- 在新文件中
1 | $ sample-scaffolding |
- 在当前项目中,生成的文件会在newProject文件中
1 | $ npm run init |