前端工程化那些事

26,539 阅读16分钟

什么是前端工程化?本质上就是将前端开发流程,标准化、规范化、工具化、自动化、简单化。通过规范和工具来提高前端应用质量及开发效率

1.脚手架

脚手架用于快速生成新项目的目录模板,并集成一系列体系化工具的安装,能够提升前端开发人员的效率,减少copy操作

1.1 常见的脚手架工具

  • vue官方脚手架:vue-cli

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统官方文档🚀

如何安装

npm install -g @vue/cli-service-globa

如何快速创建一个项目

vue create admin-template

创建模式有两种,一种是默认配置(没有带其他辅助功能的 npm包),另一种是手动配置(可按照生产需要进行配置)

  • Yeoman

官方介绍:Yeoman帮助您启动新项目,规定最佳实践和工具以帮助您保持生产效率,它是一个脚手架底层框架,你也可以通过yeoman定制自己的脚手架实现。

Yeoman主要包括: yo(脚手架,自动生成工具)、 Grunt、gulp(构建工具)、 Bower、npm --- (包管理工具)等

如何安装

npm install -g yo  

yeoman 社区有不同项目目录模板可以选择查看链接,也可以使用 yeoman-generator 封装自己的脚手架

1.2 开发脚手架工具

现有的脚手架自定义及定制化程度不高的情况,团队需要定制化适合自身开发的脚手架工具,下面列举开发脚手架工具涉及的常用工具库如下👇

关于脚手架在项目中实践可以阅读树酱的《从0到1开发简单脚手架》

1.3 模版管理

看完前两小节的童鞋可能会觉得,配置脚手架以及开发脚手架对于规模较小的团队工作量很大,那可以通过生成一个统一的模版,然后用仓库管理维护起来,下次需要的时候创建新项目时,直接通过仓库拉取模版即可

1.4 总结

脚手架能提高项目初始化搭建的效能,减少搭建项目所消耗的时间,团队规模大的有条件可以自行开发内部的脚手架工具,而对于规模小的团队,开发脚手架工具“产出比”不是很高,毕竟脚手架工具完成项目初始化之后,脚手架就再无用武之地了,所以如果对于开发力量不大的团队而言,投入时间去开发一个脚手架工具不是很“划算”,简单的方式就是建立内部的模版管理,用git或者svn管理起来即可

2.构建工具

什么是构建工具?构建工具可以让我们更好地自动化处理包括(es6转换,css、js压缩,less、sass的转换等),让我们不再需要手动地去重复做这些事情,解放开发人员的双手,更好地聚焦到业务上的开发,构建本质上就是将代码“串”起来,然后压缩并混淆,最终构建出目标代码文件,常见的构建工具有:webpack、rollup、Parcel、grunt、gulp

2.1 Webpack

webpack是前端打包工具,通过分析所在项目的目录结构,找到模块及各模块间的依赖关系,且将浏览器不能直接运行的语言如typescript、css预处理器语法(less、sass)等或者因为浏览器因为版本底不支持新的内置函数,需要将其转换及打包成浏览器支持格式,👇是主要的特征

  • css预处理器如less、sass等浏览器不支持
  • 部分低版本浏览器不支持es6语法,需要转换为es5语法,为浏览器使用
  • 项目依赖过多,文件过多,需要将复杂的代码结构转换为细化
  • 模块化打包,保留单个模块的可维护性,又减少了http请求数,优化加载速度

关于webpack在项目中实践可以阅读树酱的《【webpack】从vue-cli 2x 到 3x 迁移与实践》

更多webpack的配置和学习可以阅读以下文章👇

2.2 Rollup

rollup比较适合打包js的sdk或者封装的框架,具备 Tree-shaking ,对上一节介绍的webpack,则比较适合打包一些应用,例如SPA或者同构项目

关于Rollup在项目中实践可以阅读树酱的《前端JS-SDK那些事》

更多Rollup的配置和学习可以阅读以下文章👇

2.3 Parcel

官方介绍:Parcel 是 Web 应用打包工具,适用于经验不同的开发者。它利用多核处理提供了极快的速度,并且不需要任何配置 官方链接🚀

Parcel相比前面介绍的webpack最大的区别就是:不需要维护配置文件,举个例子来说明:如果你想转换less的语法,在webpack你需要配置less-loader来完成,而Parcel不需要安装 less, 当检测到 less 文件时 Parcel 将会自动转换。换句话说:Parcel能做到无配置完成项目构建要求,简单!

优势在于:打包时间也更快!🚀

更多的配置和学习可以阅读以下文章👇

2.4 包管理工具构建 npm

可以使用npm脚本来执行构建操作,在packjson中编写对应的命令,通过执行npm run [任务]的方式,如下所示👇

"scripts": {
    "serve": "vue-cli-service serve ",
    "build": "vue-cli-service build",
    "build_development": "vue-cli-service build --mode development",
    "build_test": "vue-cli-service build --mode test",
    "build_preproduction": "vue-cli-service build --mode preproduction",
    "build_production": "vue-cli-service build --mode production",
    "unit": "jest --config src/test/unit/jest.conf.js --coverage",
  },

根据不同任务,定义不同的执行命令

2.5 总结

  • Webpack:适⽤于⼤型项目构建:webpack目前生态最完善,应用场景更多,社区人气高,有强⼤的loader和插件⽣态
  • Rollup:适⽤于工具库的打包: 可以将各个模块打包进⼀个⽂件中,具备 Tree-shaking 来删除⽆⽤的代码,降低代码体积,但是不具备webpack强大的插件生态,定位更适用于聚焦于库的打包
  • Parcel:适⽤于试验: 虽然无配置的优势,可以快速打包应用,且打包效率,但是不具备Tree-shaking,导致输出文件偏大
  • grunt、gulp:适用于项目工具流构建,慢慢被替换替代,不推荐使用

3.Mock 服务

Mock 指是解决前端在完成页面搭建后,此时需要联调后端接口时,后端接口尚未开发完成,还无法联调时前端可以先按照事先与后端约束好的数据结构来模拟接口数据来走完开发( 一般是通过后端接口文档比如Swagger ),实现真正意义上的前后端分离

前端Mock主要包括以下几种方式:

  • 数据拦截型
  • json-server服务型
  • 可视化接口管理平台

3.1 数据拦截型

数据拦截指的是通过模拟Http请求对相应匹配的接口进行真实请求拦截,返回模拟的数据,目前主要的工具有以下👇

  • mockjs

官方介绍:Mock.js 是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试,通过模拟 Ajax 请求,生成并返回模拟数据 官方文档

如何安装

npm install mockjs;

如何使用

更多mock示例语法 👉点我

//mock.js
const Mock = require('mockjs');
Mock.mock(new RegExp('/user/info'), 'get', {
        'code': 0,
        'msg': 'success',
        'data': {
            "content|15": [{
              "startTime": "@date('yyyy-MM-dd')",
              "createUser": '@cname', //名字为随机中文名字
              "endTime": "@date('yyyy-MM-dd')", 
              "ago|18-28":25,    //年龄为18-28之间的随机数字
              "sex|1": ["female", "male"], //返回数组中随机的一个
              "ud": "@increment" //自增
            }],
        }
})

main.js中引入mock.js,需要判断项目所处环境,只在mock环境则引入

import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios';
if(process.env.NODE_ENV === 'mock'){
    require('./mock.js')
}
Vue.prototype.$axios = axios;

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

当前端发起请求接口中匹配到api:'/user/info',则不会向后端发起真正的接口请求,而是被该mock拦截了,返回了我们原先设定的接口数据,如下

 axios.get('/user/info', {}}).then(res=> {
    console.log(res);
 })

如下图👇所示mock成功,可以看到我们定义的mock数据成功返回,拦截方式也只能通过console来查看数据返回,因为在Chrome的Network中没法看到请求,这也是它的一个缺点

3.2 json-server服务型

json-server是一个 Node 模块,通过运行 Express 服务器,可以直接把一个json文件作为一个具备全RESTful风格的API,并支持跨域、jsonp、路由订制等功能的 web 服务器,也可结合上一节介绍的mock.js,来达到mock数据的效果

对比单独上一节提到mock.js数据拦截型这种方式,json-server优势在于能够看到真实的网络请求,而劣势则在于需要运行一个node服务,更多使用可以阅读官方文档🚀

  • 如何安装
npm install -g json-server
  • 如何使用
json-server --watch db.json
// db.json 为mock数据源

3.3 Mock接口管理平台

上一节介绍数据拦截型的使用,但是如果当你团队比较大,项目众多的情况下,每个项目都需要去维护这样的“数据”,是及其不便的,那么有没有更好的方式呢?

那就是通过mock接口管理平台,比如rap、easy-mock文档链接、YApi文档链接等,这里介绍下YApi

  • YApi

官方介绍:YApi是高效、易用、功能强大的 api 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API

相比上一节讲的数据拦截型而言,YApi支持基于 Swagger 创建项目,节省手动创建的时间,以便快速生成各模块接口结构,同时免去你繁琐的手动添加操作

选择数据管理,开启url导入,输入swagger接口文档链接

3.4 总结

如果团队项目规模较小,那么推荐使用数据拦截型(mockjs)就足够,变更方便,但如果项目规模大,多人协作,且需求接口变更快,建议使用mock接口管理平台

4.前端规范

随着前端工程化的日益成熟,代码规范化对于开发效率的提升起着很大的作用,包括后期的维护,统一的规范能节省交接的时间成本,而规范包括目录结构、代码质量(命名、注释、JS规范、CSS规范、缩进等)

4.1 目录结构

根据业务模型来规范项目的src目录

静态资源目录: assets
本地数据模拟目录: mocks
公共函数方法目录: utils 
单元测试目录: test
常量目录: consts
icon目录: icons
公共混合函数目录: mixin
路由目录: router
组件目录: components
页面目录: views
配置目录: config
服务api接口管理目录: api
vuex 状态管路目录: store
.env*: 项目中我们通常会使用环境变量来影响应用在不同运行环境下的行为. 从文件中读取环境变量

4.2 语法约束

  • 组件化命名规则
  1. 按照功能命名:比如头部就是 Header,就是头部导航栏
  2. 按照页面来分组件:比如文章列表 NewsItem,即可用于文章列表,也可以用在详情页的内容推荐
1.组件的文件名始终是单词大写开头 如:(PascalCase)
2.在声明 prop 的时候,其命名应该始终使用 驼峰命名法
3.组件名应该是完整单词而不是缩写
  • vue规范
1.总是用 key 配合 v-for
2.不要把 v-if 和 v-for 同时用在同一个元素上。
3.Object.freeze 方法来冻结一个不会有任何改变的对象,减少组件初始化的时间
4.每个组件 export default {} 内的方法顺序一致,方便查找对应的方法。
按照 data、props、钩子、watch、computed、components
5.props里加数据类型,是否必传,以及默认值,便于排查错误,让传值更严谨
6.使用定时器,要在beforeDestroy()生命周期内清除定时器
  • css命名

随着项目模块增多,防止因为不同页面或者组件中定义的css冲突,所以规范css语法也变得至关重要,推荐:BEM,分别代表着:Block(块)、Element(元素)、Modifier(修饰符)

.user-info {} # user-info 是一个块,我理解是一个模块
.user-info--feature {} # user-info--feature 是一个修饰符,用来表示这个块的不同状态
.user-info__title{} # user-info__title 是一个元素,属于userinfo模块下的,多个元素组成块

4.3 开发工具规范

  • eslint

一个插件化的 javascript 代码检测工具,它可以用于检查常见的 JavaScript 代码错误,也可以进行代码风格检查

推荐使用到两个扩展包(airbnb规范官方文档链接 🚀 & eslint-plugin-vue 官方文档链接🚀

  • Prettier

是格式化代码工具。用来保持团队的项目风格统一

  • stylelint

stylelint是的css代码审查工具供,用来约束css的书写规范,增强代码可读性,官方文档

具体使用请阅读树酱的《前端规范那些事》

4.4 Git commit 规范

commit 规范可以更好的形成清晰的提交记录(changelog),通过制定 相应的 Commit Message 规范来约束开发人员根据不同的提交添加备注,常用的类别如下

  • 约束定义
feature: 开发新的功能
fix: 修复bug
refactor: 代码重构
docs: 文档修改
style: 代码格式修改, 注意不是 css 修改
test: 测试用例修改
perf: 改善性能
build: 变更项目构建或外部依赖(例如scopes: webpack、gulp、npm等)
revert: 代码回退

比如:
git commit -m 'fix:修复某某bug'

除了上面简单的规范,还可以通过集成Commitlint配置,下一节教你如何上手,感兴趣的童鞋可以查看更多官方文档信息点我👈,

  • 自动化检测

那如何在vue-cli上配置呢?这个时候就需要用到 Git Hook vue-cli3x的官方配置支持看这里 点我👈 。他把yorkie(尤大改写)做了封装,yorkie本质上是通过fork husky的基础上做了一些定制化的改动,使得hook钩子能从package.json的 "gitHooks"属性中读取,我们可以通过gitHooks配置结合Commitlint来实现自动化检测commit的提交log,下面是流程图👇

安装commitlint

npm install -g @commitlint/cli @commitlint/config-conventional

创建commitlint配置文件

// 新建 commitlint.config.js 
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feature', // 开发新的功能
        'fix', // 修补bug
        'refactor', // 代码重构
        'docs', // 文档(documentation)
        'style', // 格式(不影响代码运行的变动)
        'test', // 增加测试
        'build', //  变更项目构建或外部依赖(例如: webpack、package等)
        'revert', // 回滚
        'perf', // 改善性能
      ],
    ],
    'type-empty': [2, 'never'], // 提交不符合规范时,也可以提交,但是会有警告
    'subject-empty': [2, 'never'], // 提交不符合规范时,也可以提交,但是会有警告
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
  },
};

配置gitHooks

// package.json
"gitHooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "commitlint -E GIT_PARAMS"
  },
  "lint-staged": {
    "*.js": [
      "vue-cli-service lint"
    ],
    "*.vue": [
      "vue-cli-service lint"
    ]
  },

4.5 文档约束

如果团队较小,可以参考一线互联网公司前端规范,统一代码风格、

5.单元测试

单元测试是工程化中用来确保项目质量及代码质量的一个环节,虽然测试并不能直接地减少bug,但是可以减少因为反复修改过程中新生成的bug,因为当你修改代码时,很容易忽略之前设定的一些逻辑,导致系统出现故障

5.1 准备工作

  • 需要先选定一个单元测试框架:jest、Mocha、Karma等
  • 制定测试规则
  • 约束团队单元测试覆盖率最小值:比如函数覆盖率达到80%,那么如果每次自动化测试达不到这个条件,项目就发布失败,直到完成目标条件

5.2 遵循规则

无论使用什么单元测试框架,万变不离其宗,基本的原则都是依靠以下几点👇

  • 假设:如:test('formatTime()默认格式,返回时间格式是否正常', () => {}) 指定完成测试所要达成的条件
  • 当:所要执行的操作,如:date.formatTime(1586934316925) 执行这个函数的测试
  • 那么:得到的结果,既获得断言 如: expect(date.formatTime(1586934316925,'yyyy.MM.dd')).toBe('2020.04.15');

更多使用请阅读树酱的《前端单元测试那些事》

6.项目部署

完成项目开发后,上线部署也是工程化一个重要的环节,而对于前端项目而言,部署并不是一件痛苦的事情

目前大部分SPA只是单纯的静态资源文件,直接打包,然后用nginx做代理就可以完成简单的部署,也可以结合docker和jenkins做自动化部署,持续部署、持续集成。

而对于服务端渲染的前端应用,部署相对而言环节多一些,还需要管理进程、监控服务是否正常等等,就涉及到其他工具的使用,下面是前端工程化项目部署涉及到的几个主流工具如下👇

  • jenkins: 一个可扩展的自动化服务器,可以用作简单的 CI 服务器,具有自动化构建、测试和部署等功能
  • docker: 虚拟环境容器,可以将环境、代码、配置文件等一并打包到这个容器中,最后发布应用
  • npm : Node.js 官方提供的包管理工具,主要用来管理项目依赖,发布
  • nginx: 可以作为 Web 服务器,也可以作为负载均衡服务器,具备高性能、高并发连接
  • pm2: node进程管理工具,可以利用它来简化很多node应用管中繁琐任务

更多使用请阅读树酱的《前端运维部署那些事》

参考文献: 《前端架构从入门到微前端》

请你喝杯🍵 记得三连哦~

1.阅读完记得给🌲 酱点个赞哦,有👍 有动力

2.关注公众号前端那些趣事,陪你聊聊前端的趣事

3.文章收录在Github frontendThings 感谢Star✨