第六章 工程化 - 项目工程化实施中涉及的流程及知识体系

项目工程化实施中涉及的流程及知识体系分类

项目工程化实施中涉及的 7 个 大致流程及知识体系
1、技术选型
2、统一规范
3、测试
4、部署
5、监控
6、性能优化
7、重构

每一个 知识体系 说明

技术选型
三大框架中选一个 【 React Vue Angular 】
可以依据以下两个特点来选
1、选你或团队最熟的,保证在遇到棘手的问题时有人能填坑
2、选市场占有率高的
统一规范
1、代码规范
a、好处
1、规范的代码可以促进团队合作
2、规范的代码可以降低维护成本
3、规范的代码有助于 code review(代码审查)
4、养成代码规范的习惯,有助于程序员自身的成长
b、如何制订代码规范
找一份好的代码规范,在此基础上结合团队的需求作个性化修改。
一些 star 较多的 js 代码规范如下
1、airbnb (101k star 英文版),airbnb-中文版 【 javascript
2、standard (24.5k star) 中文版 【 javascript
3、百度前端编码规范 3.9k 【 javascript
4、styleguide 2.3k 【 css 】
5、spec 3.9k 【 css 】
c、如何检查代码规范 【 Eslint 】
使用 eslint 可以检查代码符不符合团队制订的规范
2、git 规范
1、分支管理规范
2、git commit 规范
3、项目规范
主要是项目文件的组织方式和命名方式
Vue 项目举例
├─public 【 公共资源,不会被 webpack 处理 】
├─src 【 源码 】
├─api (接口)
├─assets (静态资源)
├─components (公共组件)
├─styles (公共样式)
├─router (路由)
├─store (vuex 全局数据)
├─utils (工具函数)
└─views (页面)
├─test 【 测试代码 】
文件名称如果过长则用 - 隔开
4、UI 规范
UI 规范需要前端、UI、产品沟通,互相商量,最后制定下来,建议使用统一的 UI 组件库。
1、统一页面 UI 标准,节省 UI 设计时间
2、提高前端开发效率
测试
测试是前端工程化建设必不可少的一部分,它的作用就是找出 bug,越早发现 bug,所需要付出的成本就越低。并且,它更重要的作用是在将来,而不是当下。
在前端用得最多的就是 单元测试
1、单元测试
定义
单元测试 就是对一个函数、一个组件、一个类做的测试,它针对的粒度比较小
用法
1、根据正确性写测试,即正确的输入应该有正常的结果。
2、根据异常写测试,即错误的输入应该是错误的结果。
分类
1、对一个函数做测试
2、对一个类做测试
3、对一个组件做测试
组件测试比较难,因为很多组件都涉及了 DOM 操作
2、TDD 测试驱动开发
TDD 就是根据需求提前把测试代码写好,然后根据测试代码实现功能
3、测试框架推荐
jest 测试框架
Jest 是由 Facebook 开源出来的一个测试框架,它集成了断言库、mock、快照测试、覆盖率报告等功能。
它非常适合用来测试 React 代码
所有的 js 代码都可以使用 Jest 进行测试
部署
1、手动部署
在没有自动部署前,部署项目通常是这样的
1、执行测试 npm run test。
2、构建项目 npm run build。
3、将打包好的文件放到静态服务器
2、自动化部署
自动部署 又叫持续部署 Continuous Deployment,英文缩写 CD ,一般有两种触发方式
1、轮询
轮询,就是构建软件每隔一段时间自动执行打包、部署操作。
这种方式不太好,很有可能软件刚部署完我就改代码了。为了看到新的页面效果,不得不等到下一次构建开始。
另外还有一个副作用,假如我一天都没更改代码,构建软件还是会不停的执行打包、部署操作,白白的浪费资源。
所以现在的构建软件基本采用监听 webhook 事件的方式来进行部署。
2、监听 webhook 事件
webhook 钩子函数,就是在你的构建软件上进行设置,监听某一个事件(一般是监听 push 事件),当事件触发时,自动执行定义好的脚本
例如 Github Actions,就有这个功能。
3、工具
Gitea + Jenkins 可以实现自动构建前端项目并部署到服务器
1、Gitea 用于构建 Git 局域网服务器
2、Jenkins 是 CI/CD 工具,用于部署前端项目。
监控
监控,又分 性能监控 和 错误监控,它的作用是预警和追踪定位问题。
包含
1、性能监控
2、错误监控
3、数据上报
性能监控
1、性能监控概述
性能监控一般利用 window.performance 来进行数据采集
Performance 接口可以获取到当前页面中与性能相关的信息
它是 High Resolution Time API 的一部分,
同时也融合了 Performance Timeline APINavigation Timing APIUser Timing APIResource Timing API
这个 API 的属性 timing,包含了页面加载各个阶段的起始及结束时间
几个重要的知识点
a、白屏时间
它指从输入网址,到页面开始显示内容的时间。
将以下脚本放在 </head> 前面就能获取白屏时间。
<script>
whiteScreen = new Date() - performance.timing.navigationStart
</script>
通过这几个时间,就可以得知页面首屏加载性能如何了
b、获取相关资源 【 s、css、img... 】 的加载时间
window.performance.getEntriesByType('resource')
这个方法返回页面当前所加载的所有资源需要的时间
它一般包括以下几个类型
1、sciprt
2、link
3、img
4、css
5、fetch
6、other
7、xmlhttprequest
一般只需用到以下几个信息
// 资源的名称
name: item.name,
// 资源加载耗时
duration: item.duration.toFixed(2),
// 资源大小
size: item.transferSize,
// 资源所用协议
protocol: item.nextHopProtocol,
2、性能监控 timing 各个属性的意义
timing: {
// 同一个浏览器上一个页面卸载(unload)结束时的时间戳。如果没有上一个页面,这个值会和fetchStart相同。
navigationStart: 1543806782096,
// 上一个页面unload事件抛出时的时间戳。如果没有上一个页面,这个值会返回0。
unloadEventStart: 1543806782523,
// 和 unloadEventStart 相对应,unload事件处理完成时的时间戳。如果没有上一个页面,这个值会返回0。
unloadEventEnd: 1543806782523,
// 第一个HTTP重定向开始时的时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0。
redirectStart: 0,
// 最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的时间戳。
// 如果没有重定向,或者重定向中的一个不同源,这个值会返回0.
redirectEnd: 0,
// 浏览器准备好使用HTTP请求来获取(fetch)文档的时间戳。这个时间点会在检查任何应用缓存之前。
fetchStart: 1543806782096,
// DNS 域名查询开始的UNIX时间戳。
//如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和fetchStart一致。
domainLookupStart: 1543806782096,
// DNS 域名查询完成的时间.
//如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
domainLookupEnd: 1543806782096,
// HTTP(TCP) 域名查询结束的时间戳。
//如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 fetchStart一致。
connectStart: 1543806782099,
// HTTP(TCP) 返回浏览器与服务器之间的连接建立时的时间戳。
// 如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。
connectEnd: 1543806782227,
// HTTPS 返回浏览器与服务器开始安全链接的握手时的时间戳。如果当前网页不要求安全连接,则返回0。
secureConnectionStart: 1543806782162,
// 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳。
requestStart: 1543806782241,
// 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳。
//如果传输层在开始请求之后失败并且连接被重开,该属性将会被数制成新的请求的相对应的发起时间。
responseStart: 1543806782516,
// 返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时
//(如果在此之前HTTP连接已经关闭,则返回关闭时)的时间戳。
responseEnd: 1543806782537,
// 当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的 readystatechange事件触发时)的时间戳。
domLoading: 1543806782573,
// 当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的时间戳。
domInteractive: 1543806783203,
// 当解析器发送DOMContentLoaded 事件,即所有需要被执行的脚本已经被解析时的时间戳。
domContentLoadedEventStart: 1543806783203,
// 当所有需要立即执行的脚本已经被执行(不论执行顺序)时的时间戳。
domContentLoadedEventEnd: 1543806783216,
// 当前文档解析完成,即Document.readyState 变为 'complete'且相对应的readystatechange 被触发时的时间戳
domComplete: 1543806783796,
// load事件被发送时的时间戳。如果这个事件还未被发送,它的值将会是0。
loadEventStart: 1543806783796,
// 当load事件结束,即加载事件完成时的时间戳。如果这个事件还未被发送,或者尚未完成,它的值将会是0.
loadEventEnd: 1543806783802
}
3、通过以上数据,我们可以得到几个有用的时间
// 重定向耗时
redirect: timing.redirectEnd - timing.redirectStart,
// DOM 渲染耗时
dom: timing.domComplete - timing.domLoading,
// 页面加载耗时
load: timing.loadEventEnd - timing.navigationStart,
// 页面卸载耗时
unload: timing.unloadEventEnd - timing.unloadEventStart,
// 请求耗时
request: timing.responseEnd - timing.requestStart,
// 获取性能信息时当前时间
time: new Date().getTime(),
4、代码实现收集 性能信息 和 资源信息
// 收集性能信息
const getPerformance = () => {
if (!window.performance) return
const timing = window.performance.timing
const performance = {
// 重定向耗时
redirect: timing.redirectEnd - timing.redirectStart,
// 白屏时间
whiteScreen: whiteScreen,
// DOM 渲染耗时
dom: timing.domComplete - timing.domLoading,
// 页面加载耗时
load: timing.loadEventEnd - timing.navigationStart,
// 页面卸载耗时
unload: timing.unloadEventEnd - timing.unloadEventStart,
// 请求耗时
request: timing.responseEnd - timing.requestStart,
// 获取性能信息时当前时间
time: new Date().getTime(),
}
return performance
}
// 获取资源信息
const getResources = () => {
if (!window.performance) return
const data = window.performance.getEntriesByType('resource')
const resource = {
xmlhttprequest: [],
css: [],
other: [],
script: [],
img: [],
link: [],
fetch: [],
// 获取资源信息时当前时间
time: new Date().getTime(),
}
data.forEach(item => {
const arry = resource[item.initiatorType]
arry && arry.push({
// 资源的名称
name: item.name,
// 资源加载耗时
duration: item.duration.toFixed(2),
// 资源大小
size: item.transferSize,
// 资源所用协议
protocol: item.nextHopProtocol,
})
})
return resource
}
5、性能监控 小结
通过对 性能 及 资源信息 的解读,我们可以判断出页面 加载慢 有以下几个原因
1、资源过多
2、网速过慢
3、DOM元素过多
除了用户网速过慢,我们没办法之外,其他两个原因都是有办法解决的
错误监控
1、错误监控 概述
现在能捕捉的错误有 三 种
1、资源加载错误,通过 addEventListener('error', callback, true) 在捕获阶段捕捉资源加载失败错误。
2、js 执行错误,通过 window.onerror 捕捉 js 错误。
3、promise 错误,通过 addEventListener('unhandledrejection', callback)捕捉 promise 错误,但是没有发生错误的行数,列数等信息,只能手动抛出相关错误信息
我们可以建一个错误数组变量 errors 在错误发生时,将错误的相关信息添加到数组,然后在某个阶段统一上报
// 捕获资源加载失败错误 js css img...
addEventListener('error', e => {
const target = e.target
if (target != window) {
monitor.errors.push({
type: target.localName,
url: target.src || target.href,
msg: (target.src || target.href) + ' is load error',
// 错误发生的时间
time: new Date().getTime(),
})
}
}, true)
// 监听 js 错误
window.onerror = function(msg, url, row, col, error) {
monitor.errors.push({
type: 'javascript',
row: row,
col: col,
msg: error && error.stack? error.stack : msg,
url: url,
// 错误发生的时间
time: new Date().getTime(),
})
}
// 监听 promise 错误 缺点是获取不到行数数据
addEventListener('unhandledrejection', e => {
monitor.errors.push({
type: 'promise',
msg: (e.reason && e.reason.msg) || e.reason || '',
// 错误发生的时间
time: new Date().getTime(),
})
})
2、错误监控 小结
通过错误收集,可以了解到网站错误发生的类型及数量,从而可以做相应的调整,以减少错误发生
数据上报
1、性能数据上报
性能数据可以在页面加载完之后上报,尽量不要对页面性能造成影响
window.onload = () => {
// 在浏览器空闲时间获取性能及资源信息
// https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
if (window.requestIdleCallback) {
window.requestIdleCallback(() => {
monitor.performance = getPerformance()
monitor.resources = getResources()
})
} else {
setTimeout(() => {
monitor.performance = getPerformance()
monitor.resources = getResources()
}, 0)
}
}
也可以设一个定时器,循环上报。不过每次上报最好做一下对比去重再上报,避免同样的数据重复上报
2、错误数据上报
// 监听 js 错误
window.onerror = function(msg, url, row, col, error) {
const data = {
type: 'javascript',
row: row,
col: col,
msg: error && error.stack? error.stack : msg,
url: url,
// 错误发生的时间
time: new Date().getTime(),
}
// 即时上报
axios.post({ url: 'xxx', data, })
}
SPA
window.performance API 是有缺点的,在 SPA 切换路由时,window.performance.timing 的数据不会更新
我们需要另想办法来统计切换路由到加载完成的时间
Vue 举例,一个可行的办法就是切换路由时,在路由的全局前置守卫 beforeEach 里获取开始时间,在组件的 mounted 钩子里执行 vm.$nextTick 函数来获取组件的渲染完毕时间。
router.beforeEach((to, from, next) => {
store.commit('setPageLoadedStartTime', new Date())
})
mounted() {
this.$nextTick(() => {
this.$store.commit('setPageLoadedTime', new Date() - this.$store.state.pageLoadedStartTime)
})
}
用户信息收集
1、navigator
使用 window.navigator 可以收集到用户的设备信息,操作系统,浏览器信息...
2UVUnique visitor )
指通过互联网访问、浏览这个网页的自然人
访问您网站的一台电脑客户端为一个访客。00:00-24:00内相同的客户端只被计算一次。一天内同个访客多次访问仅计算一个UV
在用户访问网站时,可以生成一个随机字符串+时间日期,保存在本地。
在网页发生请求时(如果超过当天24小时,则重新生成),把这些参数传到后端,后端利用这些信息生成 UV 统计报告。
3PVPage View
即页面 浏览量 或 点击量,用户每 1 次对网站中的每个网页访问均被记录 1PV
用户对同一页面的多次访问,访问量累计,用以衡量网站用户访问的网页数量
4、页面停留时间
传统网站用户在进入 A 页面时,通过后台请求把用户进入页面的时间捎上。过了 10 分钟,用户进入 B 页面,这时后台可以通过接口捎带的参数可以判断出用户在 A 页面停留了 10 分钟。
SPA 可以利用 router 来获取用户停留时间
Vue 举例,通过 router.beforeEach destroyed 这两个钩子函数来获取用户停留该路由组件的时间。
5、浏览深度
通过 document.documentElement.scrollTop 属性以及屏幕高度,可以判断用户是否浏览完网站内容
6、页面跳转来源
通过 document.referrer 属性,可以知道用户是从哪个网站跳转而来
7、小结
通过分析用户数据,我们可以了解到用户的浏览习惯、爱好等等信息,想想真是恐怖,毫无隐私可言
前端监控部署
前面说的都是监控原理,但要实现还是得自己动手写代码
可以用现有的工具 sentry 去做这件事
sentry 是一个用 python 写的性能和错误监控工具,你可以使用 sentry 提供的服务(免费功能少),也可以自己部署服务
性能优化
性能优化概述
性能优化主要分为两类
1、加载时优化
例如 压缩文件、使用 CDN 就属于 加载时优化
2、运行时优化
减少 DOM 操作,使用事件委托属于运行时优化
在解决问题之前,必须先找出问题,否则无从下手
所以在做性能优化之前,最好先调查一下网站的 加载性能 和 运行性能。
手动检查性能
1、检查 加载性能
一个网站 加载性能 如何主要看 白屏时间 和 首屏时间。
白屏时间:指从输入网址,到页面开始显示内容的时间。
首屏时间:指从输入网址,到页面完全渲染的时间。
a、获取 白屏时间
将以下脚本放在 </head> 前面就能获取 白屏时间。
<script>
new Date() - performance.timing.navigationStart
</script>
b、获取 首屏时间
在 window.onload 事件里
执行 new Date() - performance.timing.navigationStart 即可获取首屏时间
2、检查 运行性能
配合 chrome 的开发者工具,我们可以查看网站在运行时的性能
打开网站,按 F12 选择 performance,点击左上角的灰色圆点,变成红色就代表开始记录了。
这时可以模仿用户使用网站,在使用完毕后,点击 stop,然后你就能看到网站运行期间的性能报告。
如果有红色的块,代表有掉帧的情况;如果是绿色,则代表 FPS 很好。
另外,在 performance 标签下,按 ESC 会弹出来一个小框。点击小框左边的三个点,把 rendering 勾出来。
1、Paint flashing 是高亮重绘区域
2、Frame Rendering Stats 是显示帧渲染信息
把这两个选项勾上,然后浏览网页,可以实时的看到你网页渲染变化。
利用工具检查
1、监控工具
可以部署一个前端监控系统来监控网站性能,如 sentry 就属于这一类。
2、chrome 工具 Lighthouse 和 Performance 面板
安装 Chrome 52+ 版本,请按 F12 打开开发者工具 选择 Lighthouse 面板
它不仅会对你网站的性能打分,还会对 SEO 打分
重构
重构概述
所谓重构( refactoring )是这样一个过程:
在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。
重构是一种经千锤百炼形成的有条不紊的程序整理方法,可以最大限度地减小整理过程中引入错误的概率。
本质上说,重构就是在代码写好之后改进它的设计
重构和性能优化有相同点,也有不同点。
1、相同的地方是它们都在不改变程序功能的情况下修改代码
2、不同的地方是重构为了让代码变得更加易读、理解,性能优化则是为了让程序运行得更快
3、重构可以一边写代码一边重构,也可以在程序写完后,拿出一段时间专门去做重构。没有说哪个方式更好,视个人情况而定
4、如果你专门拿一段时间来做重构,建议你在重构一段代码后,立即进行测试。这样可以避免修改代码太多,在出错时找不到错误点。
重构原则
1、事不过三,三则重构。即不能重复写同样的代码,在这种情况下要去重构
2、如果一段代码让人很难看懂,那就该考虑重构了
3、如果已经理解了代码,但是非常繁琐或者不够好,也可以重构
4、过长的函数,需要重构
5、一个函数最好对应一个功能,如果一个函数被塞入多个功能,那就要对它进行重构了
重构手法
1、提取重复代码,封装成函数
2、拆分太长 或 功能太多 的函数
posted @   caix-1987  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示