【前端开发】架构/知识梳理/笔记
关于架构设计原则:
1、【轻快】能快速落地,符合业务需求的最简化架构,避免过度设计;
2、【降本增效】根据团队特点选择技术栈,符合团队使用习惯,降低学习成本和提升开发效率;
3、【高可用易扩展】高可用性,以使用者为优先原则,保证使用简洁,封装常用功能,提高工作效率,且方便扩展,减少后期大规模重构;
4、【高性能】保证加载、渲染、运行时的响应速度与性能,同时保证兼容性、容错能力;
5、【可维护】代码规范统一,目录结构及代码逻辑要清晰,便于后续迭代和问题排查;
6、【文档说明】包含当前架构的运行条件、步骤、特点、规范、示例、运维说明等,方便后续新人快速了解;
------------------------------------------------------------------------------
关于WEB网页性能指标:
Web Vitals -- google Chrome.DevTools.Lighthouse
谷歌浏览器自带的开发人员工具有个 Lighthouse 模块,可以检测网页性能
FCP-首次内容绘制,衡量首屏加载速度
LCP-最大内容绘制-衡量网页加载速度 <= 2.5s
CLS-累积布局偏移-衡量视觉稳定性 <= 0.1
INP-交互到下一次绘制-衡量交互的响应速度 <= 200ms
------------------------------------------------------------------------------
关于git branch
创建分支(xxx)
git checkout -b xxx 等价于 git branch xxx + git checkout xxx
推送到远程
git push -u origin xxx
** -u 表示关联本地分支和远程分支,后续推送/拉取可简化命令
合并分支
合并到哪先切到哪
git checkout main
git merge xxx
删除分支
git branch -d xxx
删除远程功能分支
git push origin --delete xxx
------------------------------------------------------------------------------
关于事件循环
为了实现异步编程,JS 设计了事件循环机制。它本质是一个循环调度流程,维护多个优先级不同的任务队列,由渲染主线程按顺序执行任务,同一时间只能执行一个任务,不能并行。
-
一开始执行的同步代码,就是事件循环中的第一个宏任务。
-
每执行完一个宏任务,会立即清空当前所有微任务,微任务全部执行完才会进入下一个环节。
-
微任务清空后,浏览器会执行渲染更新(样式计算、布局、绘制)。
-
然后再取下一个宏任务执行(根据浏览器的优先级规则,宏任务指除微任务外的其他优先级不同的任务队列中的任务),循环往复。
像 setTimeout、fetch 这类异步操作,不会阻塞主线程,而是交给浏览器的独立线程(定时器线程、网络线程)等待。等到时机满足后,才会把回调包装成宏任务放入任务队列排队。而 Promise、queueMicrotask 属于微任务,由 JS 引擎直接调度,执行时机优先于下一个宏任务。
根据W3C最新标准,宏任务的说法已经取消,由各家浏览器自主决策设计,可被拆分成多个队列,以适应日益复杂的任务调度(下图蓝色部分)

------------------------------------------------------------------------------
关于浏览器渲染原理

1解析html > 2构建cssom树、Dom树 > 3生成布局树 > 4分层 > 5绘制 > 6分块 > 7光栅化 > 8画
重要节点解释:
1、解析html --- 将字符串转为 Dom 树,方便后续通过对象的方式操作
浏览器以流式接收html文本(streaming,类似AI聊天打字机效果),接收到一行解析一行,不是等整个html下载完才解析,解析html由渲染主线程完成
遇到内部js,执行js,遇到外部js也会阻塞解析html,直接暂停等js下载好并执行完,才恢复html的解析 (因为js可能改变dom,因此要同步执行,与css逻辑不一样)
遇到内部css,外部css,不会阻塞html解析,但会阻塞js执行和页面渲染(浏览器并行下载css,边下载边解析,直到需要执行js时暂停,因为JS可能要读样式,这里要等待,在cssom树构建完成之前,页面不会渲染,会等待外部css,所有外部css加载完并解析成cssom树的一部分,cssom树才构建完成)
如果外部js有 async、defer 标识
<script src="..." async> 异步下载,下载完立即执行,下载阶段不阻塞html解析,执行阶段,如果还在解析html,先暂停html解析,执行完js再继续解析
<script src="..." defer> 异步下载,强制html解析完成后再执行
3、dom树和布局树的区别
Dom树包含html上所有节点,如<html><head><meta><link>
布局树仅包含参与布局的节点,少了<head><script>、{ display: none; } 等非页面可视元素节点(visibility: hidden 的有占位不可见元素也包含),增加了布局的匿名行盒块盒等(行元素不能直接放在块容器里,需要用匿名行盒包裹)
4、分层 layer
--- 为了后续更新更快更流畅,将页面元素按一定规则分层,每层独立绘制,然后合成显示,某一层的重绘不会影响其他层的重绘,提高渲染性能,主要图层如下:
4.1、根层,默认层,默认整个页面都在这一层
4.2、独立层,如遇到 transform(带animation或transition)、opacity(带animation)、will-change: transform|opacity 任一情况(不一定准确)会新建独立层
4.3、有独立合成需求的元素会新建独立层,如:<video><canvas>,{ position: fixed|sticky; },scroll出现滚动内容的容器
4.4、存在堆叠情况的,如:页面不同z-index内容重叠的,overflow:hidden,clip 需要裁剪的会新建独立图层
总之当元素需要GPU加速、独立滚动、固定定位、视频画布、堆叠隔离时,会被提升为独立图层,后由合成线程统一叠层显示
6、分块 Tiling
分块这一步骤主要是将网页按位置分成不同的块,为渲染提供优先级,靠近视口位置的块优先渲染,在视口外的块延迟渲染
7、光栅化 Raster
将分好的块进行像素化,转成一个一个的像素点排列,计算每个像素点的颜色
------------------------------------------------------------------------------
关于github Actions 或 gitLab CI/CD
都是自动部署的方案,在项目根目录创建相应的配置文件如github为:`.github/workflows/deploy.yml`,配置好相关信息,在我们提交、合并等操作时,github/gitLab 后台自动检测及触发所配流程,如:main 分支提交了带 'feat'的commit,触发流程,
整个流程由github、gitLab完成,我们只需要通过配置文件将关键信息告诉他们
部署时需要一个秘钥对(锁和钥匙),公钥(锁)放云服务器,私钥(钥匙)放github/gitlab 的后台设置里,在配置文件中通过特殊语法引用,实现免密上传,覆盖前的备份通过命令实现,都可以配在配置文件中,具体配置根据需求临时用AI生成即可
------------------------------------------------------------------------------
关于 git 提交规范
目前主流:Commitlint 规范(Angular 规范)
格式:类型(作用域/模块): 描述信息
强制约束可以安装插件:commitlint + husky
装好开启之后,不按规范写,直接不让提交
关于 husky
husky 就是一个给 Git 加 “看门狗” 的工具,专门在代码提交 / 推送之前自动拦一下,帮你做检查。
你只需在项目中安装 husky + lint-staged + commitlint,根目录配置 .husky 相关配置,当执行 git commit 等git命令时,git会检测配置里的内容,执行相关的行为,但是会让你的提交推送过程大幅变慢。
husky → 看门狗哈士奇(触发时机)
lint-staged → 只检查本次修改的文件(超级快)
commitlint → 检查提交信息规范
------------------------------------------------------------------------------
关于monorepo、微前端、qiankun/无界
monorepo 是一个代码组织策略,通过这样的方式来实现单仓库管理多个相关的项目,及跨子项目复用;
微前端是一个概念,把一个大型前端应用,拆成多个独立的小应用,独立开发、独立部署,最后再 “拼装” 成一个完整系统给用户使用。实现跨团队,跨技术栈的应用集成,用户无感切换。
目的:技术栈兼容、独立开发部署、系统解耦、老项目渐进式升级
qiankun/wujie 是实现了微前端的框架
主流实现方案
qiankun(阿里,最流行、接入成本低)
single-spa(鼻祖)
wujie(腾讯,基于 WebComponent + iframe)
MicroApp(京东)
关键区别:微前端 vs Monorepo
-
Monorepo:代码组织方式管的是:怎么写、怎么放、怎么构建。
-
微前端:运行时架构管的是:怎么在浏览器里加载、隔离、拼装多个应用。
总结
-
Monorepo = 单仓多项目(开发阶段)
-
微前端 = 单页多应用(运行阶段)
-
一个管代码结构,一个管页面运行。
------------------------------------------------------------------------------
关于SEO,两种部署方式,详情页动态路由的SEO如何配
SEO是指搜索引擎优化,在百度、谷歌上能搜到你的网站
vue使用Nuxt框架开发(react使用Next框架开发)
1、SSR,npm run build 打包的部署,需要服务器端部署一个node服务,将打包的 .output/ 部署上去并启动node服务接管服务端实时渲染,通过nginx代理到node服务,在浏览器访问页面时会先在node服务跑一遍该页面,再将结果返回给前端接着跑,有相关API能控制哪些代码只在服务端运行,哪些只在客户端运行
2、npm run generate 打包的部署,这种是提前将所有路由打包成html文件,部署在服务器上,用户直接访问,不需要在服务器上部署node服务,这种是死的,每次内容变更都需要重新打包部署
这种方式对于动态路由是无法打包到的,导致线上无法访问,需要特殊处理:
2.1、能静态列举的通过 nitro 配置上去
// nuxt.config.ts
export default defineNuxtConfig({
ssr: true,
// 关键配置
nitro: {
prerender: {
routes: [
'/goods/1',
'/goods/2',
'/goods/3',
'/goods/4',
// ... 所有商品ID
]
}
}
})
2.2、否则通过 defineNuxtConfig 配置预渲染 hooks,通过接口获取所有ID,拼接成动态路由数组 ['/goods/xxx', ...],再通过 nitro 相关API将动态路由添加到预渲染路由中。
export default defineNuxtConfig({
ssr: true,
hooks: {
async "nitro:prerender"(nitro) {
// 拉取商品列表
const res = await fetch("https://你的接口.com/goods/list");
const list = await res.json();
// 生成所有商品路由
const routes = list.map(item => `/goods/${item.id}`);
nitro.options.prerender.routes.push(...routes);
}
}
});
服务端渲染有个比较重要的概念,水合过程 (Hydration)
服务端渲染出 HTML 后,客户端在已有 DOM 上绑定事件、初始化状态、激活组件交互的过程。
HTML是死的,无法交互,必须交由前端绑定交互逻辑
爬虫只看 HTML,用户需要交互,水合让两者兼得
水合具体步骤:
1、服务端跑一遍代码,将服务端渲染部分替换为静态HTML1,返回给前端
2、爬虫、SEO 拿到了服务端渲染部分关键信息并记录
3、前端接收到HTML1,进行页面渲染
4、前端重新跑一遍代码,生成虚拟DOM
5、比较HTML1的 DOM 和 虚拟DOM,如果结构不一致则报错,如果结构一致则校验通过
6、已经渲染的HTML1不动(复用),把虚拟DOM上的事件绑定给HTML1的DOM
7、后续交互、状态更新按虚拟DOM逻辑进行,精准更新HTML1
重点问题:
a、服务端请求数据渲染后,前端重新跑一遍代码生成虚拟DOM时,为什么不重新请求数据,也能生成虚拟DOM?
因为服务端在返回时,将所需API数据保存在了<script>里,如:
<!-- 服务端返回给你的页面 -->
<html>
<body>
<ul>
<li>苹果</li>
<li>香蕉</li>
<li>橘子</li>
</ul>
<!-- 关键:服务端把数据“丢”到 window 上 -->
<script>
window.商品列表 = [
{ name: "苹果" },
{ name: "香蕉" },
{ name: "橘子" }
]
</script>
<script src="加载你的组件JS代码"></script>
</body>
</html>
客户端加载的JS代码也是经过打包处理过的,服务端渲染用的那份数据,本来你是通过fetch 调API,这时已经变成了从window里取,如:
function List() {
// 前端直接从 window 拿数据
const data = window.商品列表;
return (
<ul>
{data.map(item => (
<li key={item.name}>{item.name}</li>
))}
</ul>
)
}
避免了重复请求API
------------------------------------------------------------------------------
关于 vite、npm 插件开发
vite 插件,即给 Vite 打包 / 编译过程加功能,实现很简单
与普通项目不同,普通项目是运行在浏览器环境,vite 插件则是运行在node环境
vite 插件本质是一个返回对象的函数!里面有很多钩子用来做对应的事情
function myVitePlugin() {
return {
name: 'my-plugin', // 必须有,插件名
// 各种钩子(生命周期)
// 用来解析自定义路径
resolveId() {},
// 用来自己返回文件内容
load() {},
// 用来修改代码,code:源代码,path:文件路径
transform(code, path) {
if (path.endsWidth(.js)) {
return code.replace('$APP_NAME$', 'AI助手')
}
return code
},
// 构建开始时触发
buildStart() {},
// 其他钩子...
}
}
应用插件只需在 vite.config.js 里绑定
import myPlugin from './vite-plugin-my'
export default {
plugins: [myPlugin()]
}
npm 插件(包含组件、工具函数、样式库等)
和普通项目相比,必须遵守的额外规范:
1、必须有统一出口(src/index.js)将组件、工具函数统统在index.js中导出,样式库能通过子路径引用即可
对应使用时需满足这样用如:
import { Button, formatDate } from 'my-package'
import 'my-package/base.less'
2. package.json 必须配置正确(最重要)
{
"name": "你的包名(不能重复,全球唯一)",
"version": "1.0.0", // 每次发布必须增长
"type": "module",
"main": "dist/index.cjs.js", // 告诉别人怎么引入
"module": "dist/index.esm.js", // 告诉别人怎么引入
"exports": { // 告诉别人怎么引入
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts" // 类型文件,有代码提示的关键,可通过插件生成,如:vite-plugin-dts
},
"./style.css": "./dist/style.css",
"./style.less": "./src/styles/index.less" // 发布了源码可以从源码里导出,每一个能被用户单独 import 的样式,都必须在 exports 里单独声明!
},
"files": [
"dist",
"src/styles" // 可选,可将源码也发布出去
], // 只发布 dist 目录,安全干净
"peerDependencies": { // 声明依赖 Vue/React
"vue": "^3.0.0"
}
}
用户能引入哪些路径,全靠 exports 定义!
'.' 表示根目录,'./'表示根目录下,如:'./style.css' 对应 import '包/style.css'
每一个能被用户单独 import 的样式,都必须在 exports 里单独声明!
一般less建议导出 less + css 两种格式
3. 必须打包
npm 包必须打包成:
- esm(import 方式)
- cjs(require 方式)
pnpm build 生成的 dist/ 目录,就是要发布的内容,通过files指定要发布的内容。
4. 版本号规范(必须遵守)
主版本.次版本.补丁版
1.0.0
每次发布 npm 必须升级版本!
5. 必须有 README.md
写清楚:
- 安装
- 使用示例
- 组件 / 方法列表
发布到 npm 官方仓库
1. 注册 npm 账号
2. 登录
npm login
3. 发布
npm publish
发布成功!全世界都能下载:
npm install 你的包名
你以后使用方式
import { Button, MyComponent, formatTime } from 'your-package'
import 'your-package/base.less'
项目标准结构参考:
my-package/
src/
components/ → 你的组件
utils/ → 你的工具函数
styles/ → 你的公共样式
index.js → 统一出口
package.json → 核心配置
README.md → 说明
dist/ → 打包后(自动生成)
------------------------------------------------------------------------------
关于未来趋势
由于AI大量解放劳动力,未来对普通编码能力的要求会越来越低,而对架构设计、业务分析、方案落地、系统整合、复杂交互等综合能力要求会逐渐提高,前后端可能迎来再次合并,人人全栈的时代将会来临,以前很多不敢尝试的技术领域也可以勇敢尝试。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)