前端基础建设和架构30讲
前端基础建设与架构 30 讲
一、前端架构30讲
1. 开篇
前端学习路线 https://roadmap.sh/frontend
如何打造一个顺滑的工程化流程,为研发效率助理,如何建设可靠的基础设施,为业务保驾
vue.js完整版和运行版的区别?问的是编译器原理。
制定工程化方法,实现构建和发布流程,设计应用中公共方法和底层架构。
2. 导读
2-1. 演进方向
2-1-1. ajax-2005年实现前后端分离。
2-1-2. MVVM模式:双向绑定或自动渲染更新;
MVC:主要是通过view或者用户直接控制controller;简化数据和视图的依赖,解决数据频繁更新的问题,虚拟Dom理念。
![MVC模式](./images/1654230630085.png)
2-1-3. mvvm与mvc最大的区别:
MVVM实现了view与model的自动同步,也就是model属性改变的时候, 我们不需要再自己手动操作dom元素去改变view的显示,而是改变属性后该属性对应的view层会自动改变。
最终发展处三个前端框架:vue,angle,reactor
2-1-4. nodejs崛起实现BFF层
**同构方案实现SSR架构;**此时前端工程师就要关系服务器的运维,部署,发布,监控
2-1-5. 为了解放运维工作 Servless理念及平台出现
2-1-6. 现代化架构方案特点
2-2. 渲染方案的演进(CSR->ssr->NSR->ESR)
2-2-1. CSR
- 实现前后端分离
- TTFB时间最小,但是FCP/FMP时间不理想
2-2-2. SSR
SSR和CSR结合基于hydration(注水)的方案
hydration:同构应用中数据的获取和消费需要保留状态;在服务端返回html字符串的时候讲数据JSON.stringify一并返回叫dehydrate(脱水),客户端就不需要再请求数据可以直接使用,这个过程叫注水。
2-2-2-1. 流失SSR和渐进式SSR
2-2-3. NSR:通过Native渲染生成HTML并缓存在客户端
优点:将服务器的渲染工作放在了一个个独立的移动设备中,并借助离线存储技术实现了页面的预加载,同时又不会增加额外的服务器压力。
2-2-4. ESR:边缘渲染
边缘计算:在靠近物或者源头的一侧,采用网络,计算,存储,应用核心为一体的开放平台,就近提供最近端服务。应用服务在边缘测发起,产生更快的网络服务响应,应用在更快的实时,应用智能,隐私保护等需求。而云端扔可以访问边缘的数据。
在CDN上缓存页面的静态部分,在用户访问页面时可以快速返回用户静态内容,在CDN节点上发起动态内容请求,在动态内容获取之后利用流的方式,继续返回给用户。
3. npm机制和私服原理(JS报管理工具原理分析)
3-1. 包管理问题
3-1-1. 安装机制
3-1-2. npm缓存机制
3-1-3. npm link 本地调试和包可用性验证
3-1-4. npx的作用
npx commandname 会自动地在项目的 node_modules 文件夹中找到命令的正确引用,而无需知道确切的路径,也不需要在全局和用户路径中安装软件包。
3-2. npm多远镜像和私服部署原理
3-2-1. npm配置优先级
4. Yarn理念破解依赖管理困境(nodejs是packge-lock.json,yarn是yarn.lock;synp工具可以后者转前者)
依赖的“嵌套地狱“:项目依赖树的层级非常深,不利于调试和排查问题,依赖树的不同分支里,可能存在同样版本的相同依赖。
这些包就是js代码包。
5. CI环境上的npm优化和工程化问题
6. 横向对比主流构建工具,了解构建工具设计考量
7. 横向对比构建工具
8. vite实现:从源码分析触发,构建bundlele工程
vite在开发环境下并没有打包和构建过程,是vue坐着尤雨溪产出。
9. core-j及垫片理念,设计一个polyfill(垫片/补丁)
polyfill:用社区上提供的一段代码,在不兼容某些新特性的浏览器上,使用该新特性。
方案1.手动打补丁
目前流行方案:babel-polyfill结合@babel/preset-env+userBuiltins(entry)+preset-env targets方案。
如果环境需要但是某个业务不需要polyfills可以使用@babel/preset-env+userBuiltins(usage)+preset-env targets
方案2.在线打补丁。
10. 梳理混乱的Babel(工具链),不再被编译报错困扰
11. 探索前端工具链生态,制定统一标准的babel-preet
12. 才能够0到1构建一个标准的公共库
UMD规范
13. 代码拆分和按需加载:缩减bundle ize
14. Tree Shaking摇树):溢出JS上下文未引用的代码
15. 如何理解AST实现和编译原理(AST Explore,acorn解析)
16. 工程化思维实现应用主题切换
17. 解析Webpack源码,实现自己的构建工具
18. 从编译到运行,跨端解析小程序多端方案
多端方案就是使用一种DSL 实现“write once,run everywhere”
19. 原生跨平台技术:移动端跨平台到Flutter的技术变革
20. 学习axio:封装一个结构清晰的Fetch库(请求库)
20-1. 请求库功能点:
- 自定义headers添加
- 统一断网/弱网处理
- 接口缓存处理
- 接口统一错误提示
- 接口统一数据处理
- 统一数据层结合
- 统一请求埋点
20-2. axios设计之美
- 在浏览器端,使用XMLHttpRequest发送请求
- 支持Node.js端发送请求
- 支持PromiseAPI,s使用Promise风格语法
- 支持请求和响应拦截
- 支持自定义修改请求和返回内容
- 支持请求取消
- 默认支持XSRF防御
拦截器思想:分层开发时借助拦截行为,注入自定义能力功能
适配器思想:可以支持浏览器和node.js不同请求方式。
安全思想:在请求中携带cookie值。
20-3. 知识脑图
思考:axios如何取消一个请求?
ajax取消请求的方式有两种:一种是通过设置时间,超时自动断开,另一种我们可以调用XMLHttpRequest对象上的abort方法;而axios是通过cancelToken方法
21. 对比Koa和Redux:分析前端中的中间件理念
代码设计:聚焦中间件和插件化理念。
使用compose组合各个中间件逻辑(更像拦截器的各个拦截逻辑)。
koa是洋葱模型,express插件不是是基于回调的线性机制,不仅容易实现拦截处理逻辑。
Redux实现了一个compose方法完成了中间件的注册和串联。
22. 如何理解软件开发灵活性和高定制性
ES.next的proxy代理模式
装饰者模式:在不改变原2对象的基础上,对其对象进行包装和扩展,使原对象能够应对更加复杂的需求
AOP切面编程
面向对象,函数式思想相互对立互相补充;
纯函数:不能修改外部变量,不能调用Math.radom()方法以及发送异步请求等。
高阶函数:接受函数做参,返回另外一个函数;
curry化函数;反curry化。
23. 如何理解前端中面向对象的思想
javascript的new其实是为了模仿java,掩盖了javascript的原型继承思想。
23-1. new 关键字
- 创建一个空对象,这个对象将会作为执行new 构造函数之后,返回的对象实例。
- 讲上面创建的空对象的原型(proto),指向构造函数的prototype属性。
- 将这个空对象赋值给构造函数内部的this,并执行构造函数逻辑。
- 根据构造函数执行逻辑,返回第一步创建的的对象或者构造函数的显示返回值。
23-2. 类继承和原型继承的区别
- 传统的面向对象语言的类继承,引发问题:
- 紧耦合问题
- 脆弱基类问题
- 层级僵化问题
- 必然重复性问题
- 大猩猩-香蕉问题
23-3. 前端的面向对象脑图
24. 如何利用javascript实现经典数据结构
24-1. 8类数据结构
- 数组
- 堆栈
- 队列
- 链表Linked Lists
- 树
- 图Graphs
- 字典树Trie
- 散列表(hash表)
基于数组连续存储特性:可以实现堆栈,队列
基于链表指向性:可以实现树,图
字典树和散列表使用查询比较广泛。
24-2. 图的bfs(广度优先)和dfs(深度优先算法)
- bfs在于队列
- dfs在于递归
25. 剖析前端中数据结构应用场景
25-1. 栈的应用场景
历史记录,undo/redo;线程调用栈;进制转换,括号匹配,栈混洗表达式求职等。
react context特性;
25-2. 队列的应用场景
宏任务/微任务;消息队列;
http1.1队头阻塞,因为同一个域名所有请求都是一个http连接,队头无响应阻塞。http2采用而金拇指分帧和多路复用,实现并行请求和响应解决。
25-3. 链表应用
刚开始使用stack reconciler调度算法。
局限性:每次递归都会在栈中添加一个同步帧,因此无法将遍历过程拆为粒度更小的工作单元,也就无法暂停组件的更新,并在未来某段时间恢复更新。
react核心算法Fiber实现就是链表,Fiber就是一个对象通过parent,children,sibling维护一个树形关系。Fiber模型就规避了stact的递归无法更新组件的局限。
25-4. 字典树
典型例子AutoComplete(自动填充)搜索,分类,ip地址检索,电话号码检索;一种搜索树(前缀树)插入和查询就是o(k),可就是字符串长度,消耗内存,空间换时间。
26. npm scripts:打造一体化的构建和部署流程
原理其实就是npm run调用系统 shell;脚本可以串行或并行执行。
26-1. lucas-scripts
npm scripts插件集合,通过Monorepo风格的项目,借助npm抽象“自己常用的”npm scripts脚本,以在多个项目中达到复用的目的。(tools without config 思想)
27. 自动化代码检查:剖析Lint工具和工程化接入&优化方案
27-1. prettier和Lint
- pretty:代码美化风格
- ESLint: code Linting 基于静态分析代码原理,找出代码反模式的过程,多数编程语言都有Linter,他们往往被继承在编译阶段,完成coding Linting的任务;javascript不具备先天编译流程往往会在运行时暴露错误,ESLint允许开发者在执行前发现代码错误或不合理的写法。
27-1-1. ESLint(.eslintrc文件配置)
- 所有规则都插件化
- 所有规则都可插拔(随时开关)
- 所有设计都透明化
- 使用Espree进行javascript解析
- 使用AST分析语法
27-2. husky和lint-staged
husky就是git的一个钩子,在git进行到某一时段时,可以交给开发者完成某些特定的操作。
在整个项目上运行Lint会很慢,一般会对更改的文件进行检查,此时用到lint-statged
代码是非串行的,ESLint通过5个事件控制检测范围和粒度,是多条规则串联执行,核心原理就是事件驱动。
- onCodePathStart
- onCodePathEnd
- onCodePathSementStart
- onCodePathSementEnd
- onCodePathSementLoop
27-3. 代码检查工具知识脑图
28. 如何设计一个前端+移动端离线包方案(NSR)
28-1. 离线包方案体系
29. 如何设计一个“万能”项目脚手架
脚手架:为了保证各施工过程顺利进行而搭设的工作平台,为了完成新项目的启动和搭建,能够帮助开发提示效率和开发体验。
- vue/react 框架类脚手架
- webpack等构建配置类脚手架
- 混合脚手架
29-1. 命令行工具(原理和实现)
29-1-1. 命令行到万能脚手架
30. 同构渲染架构:实现一个SSR应用
同构应用时调用一个renderToString(React中)类似的API。
assets/bundle.js CSR架构下浏览器端脚本
assets/Client.js SSR架构下浏览器端脚本,衔接SSR部分
src/ 包含所有源码,Babel将会编译该文件内代码到views/目录;低版本node.js不支持esm规范所以执行:“babel”:"babel src -d views"
30-1. 实现一个建议SSR应用项目目录说明
- src/components 中放react组件
- src/redux/中放redux相关代码
- assets/和media/中存放样式文件及图片
- src/server.js和src/template.js是node.js环境相关文件。
同构实现了客户端和服务端代码统一,只需要编写一种组件,就能生成适用于服务端和客户端的组件案例。
30-1-1. 大部分情况下:服务端代码和客户端代码需要单独处理:
- 服务端根据请求路径,匹配页面组件;客户端通过浏览器地址匹配页面(如客户端通过window.location,而服务端没有window组件)
- 打包差别(服务端不需要打包依赖的node模块和第三方模块,因为这些依赖已经安装在环境中了,可以直接引用)需要在webpack配置target:node并借助webpack-node-externals插件解决第三方依赖打包的问题。
- 请求认证问题:某个请求依赖cookie表明用户信息,比如我的学习计划列表,这种情况服务端请求不同于客户端,不会有浏览器添加cookie以及其他header信息;解决服务端保留客户端页面请求信息,并在api请求时携带并透传这个信息。
- 样式问题:style-loader:不能使用,因为webpack loader会在编译时讲样式模块载入到HTML header中,服务端编译时不存在style-loader就会报错,通过使用iso-morphic-style-loader来实现,原理把css文件转换为对象,获取所有样式利用context api,在渲染页面组件时获取所有react组件的样式信息最终插入HTML字符串中。
31. 设计性能守卫系统:完善CICD流程
31-1. 如果页面渲染前有一个loading动画(监控指标):
LCP(larget contentful paint) 衡量页面加载体验,标示视口内可见的最大内容元素的渲染时间。
FCP:以loading动画出现的时间为准。
FID(First input delay):衡量可交互性,表示用户和页面进行首次交互操作所花费的时间,比TTI更加提前。
CLS(Cumulative Layout Shift):衡量视觉稳定性,表示页面的整个生命周期中,发生的每个意外的样式移动的所有单独布局更改得分的总和。
31-2. 监控守卫
31-2-1. 真实用户监控(RealUserMonitoring RUM)
基于真实用户访问应用情况,在应用生命周期内计算产出性能指标,并进行上报。一般搭配稳定的SDK,会给用户带来额外流量消耗,影响用户访问性能。
31-2-2. 合成监控(Synthetic Mointoring,SYN)
一种实验室数据,指在某个模拟场景中,通过工具搭配规则和性能审计条目,得到一个合成的监控报告,缺点,数据量小,模拟条件配置复杂,无法完全反应真实场景。
CD/CD pipeline就是合成守卫方案
31-2-2-1. Lighthouse原理介绍
- Chrome DevTools
- Chrome 插件
- Node Cli
- Node module
- lighthouse会与浏览器建立连接并通过CDP与浏览器进行交互;
- 通过lighthouse,我们可以自定义审计项并得到审计结果。
31-2-2-2. 性能守卫系统Pert-patronus
主要有以下指标:
FCP,Total Blocking Time;First CPU idle;TTI;Speed Index;LCP;
31-2-2-2-1. 真实反映用户情况考虑不确定因素和波动因素
- 页面不确定性
- 用户侧网络情况不确定
- 终端设备不确定
- 页面服务器不稳定性(小概率)
- 性能体检服务的稳定性:在同一台机器上,如果不确定有其他应用服务,会影响性能体检服务的稳定性和一致性,不过预计影响不大,可以通过模拟网络环境和cpu能力,来保证性能体检服务的稳定和一致性。
31-2-2-2-2. 如何解决有“用户态”页面鉴权问题
对于有登录状态的页面,提供以下几种方案进行登录状态的性能服务:
- 通过Puppeteer page.cookie,测试时通过script实现登录
- 通过请求服务时,传递参数解决登录态问题
32. 实践打造网管:改造企业BFF(网关)方案
企业级BFF网管,微服务,Serverles概念,并实现代码;
BFF服务于前端的后端 逻辑分层:作为适配器能够更好地为前端服务,而传统业务后端只需要关注自己的微服务。
BFF痛点:
- 需要解决谁来开发的分工问题
- 链路复杂
- 资源浪费
BFF数据处理:
- 数据聚合和裁剪
- 序列化格式转换
- 协议转换
- Node.js调用RPC
BFF 流量处理:
- 请求分发能力,代理能力
- 可用性保障
可以有良好的限速,隔离,熔断降级,负载均衡和缓存能力。
BFF网关层的原则:
- BFF层不需要完成全部的校验逻辑,部分业务校验应该留在微服务中完成
- BFF需要完成必要的减产,比如请求头检查和必要的数据消毒
- 合理使用Content-Security-Policy
- 使用Https/HSTS
- 设置监控报警以及调用链追踪能力
- 关注依赖包安全问题
32-1. 实现一个lucas-gateway(BFF)
如何设计一个扩展性良好的BFF层?以灵活支持上述需要考量的问题
- 插件化:如logger等也可以接受第三方插件
- 中间件化:sso,限流熔断等策略。
fork了jkybernees的fast-gateway:设计
- fast-proxy(基本反代理)
- @polka/send-type(中间件)
- http-cache-middleware(缓存)
- restana(Hooks)
负载均衡:proxyHandler支持req,res,req.url,proxy,proxyOpts等参数。
Serverless:无服务器架构,它的弹性伸缩,按需使用,无运维是未来的方向。
Serverless+BFF=SFF
33. 实现高可用:使用Puppeteer生成性能最优的海报系统
以Puppeteer代表的Headless浏览器:Puppeteer是一个node库,他提供了一整套高级API,通过devtools协议控制谷歌内核浏览器,正如其翻译“操纵木偶的人”一样可以通过该库直接控制浏览器,模拟大部分用户操作进行UI测试或者作为爬虫访问页面来搜集数据。
1.7.0版本分Puppeteer和Puppeteer-core两个模块;后者默认不会下载chrome,同时会忽略所有puppeteer_* 环境变量
符合27讲的同构渲染架构,最大好处是不需要对项目代码进行任何调整,却能获取到SSR应用的数据
- 和JEST结合通过断言能力实现一个端到端测试系统
- 和Lighthouse结合实现简单性能守卫。
33-1. Puppeteer实现海报Node.js服务
34. 结束语2 项目基建和架构,个人ji价值和方向
34-1. 基建和架构
34-2. 价值和方向
34-2-1. 遇见的问你提
-
看不见的“黑天鹅”
新技术的爆发,技术的更新换代:对于菜鸟来说弯道超车,对于有经验的是颠覆和变革,核心价值是逻辑,分析,数据,算法等抽象能力。 -
被我们视而不见的“灰犀牛”:职业进阶
探索生命的种种可能!!