CSP 管得住脚本从哪个域加载,管不住页面自己往 innerHTML 里塞了什么字符串。Trusted Types 把危险 DOM Sink 的写入变成浏览器强制审查,这篇讲它的机制、落地代码和撞见的真实麻烦。
团队要做一个多人协同编辑的功能,传统的后端合并冲突加乐观锁在多人同时改同一段内容时很难写干净;记录一下改用 CRDT、用 Yjs 落地协同文档的过程,以及这套方案要付出的代价。
Svelte 4 的响应式声明依赖编译期静态分析,没法在组件外的普通模块里复用;Runes 用 `$state`、`$derived`、`$effect`、`$props` 这套显式 API 解决了这个问题,这篇记录我们把内部发布看板一部分模块迁移到 Runes 后的具体判断。
几十万个点位的散点图在 Canvas 2D 下卡到没法交互,换 WebGL 也只是把卡顿从主线程挪到了每帧几千次 draw call 上——记录我排查这个瓶颈、最终用 WebGPU 的 Compute Shader 重写数据聚合逻辑的过程。
评估一个离线优先的文档编辑器要不要把数据存进浏览器时,IndexedDB 的异步 API 在高频写入场景下写起来啰嗦、性能也一般,OPFS 提供的同步访问句柄和更接近真实文件的操作方式是另一条路,这篇讲清楚它的存储模型、权限模型、和 IndexedDB/Cache Storage 的分工,以及配额和数据清除时该怎么应对。
Speculation Rules API 能让浏览器提前预取甚至预渲染下一跳页面,比 link rel=prefetch 和悬停预加载库更进一步,但预渲染错页面会白白浪费带宽,预渲染有副作用的页面还可能提前触发埋点或写操作,这些代价得先算清楚。
长任务把主线程堵住的时候,setTimeout(fn, 0) 和 requestIdleCallback 都救不了场——scheduler.postTask() 的优先级参数和 scheduler.yield() 的循环内让出,才是浏览器原生给出的任务调度方案。
light-dark() 函数和 color-scheme 属性能不能替换项目里现有的暗色模式实现,这篇给出具体判断标准:暗色变量数量、是否依赖 data-theme 做第三方组件适配,以及原生表单控件、滚动条怎么借 color-scheme 自动换色。
记录给后台表格行加一个操作菜单时,把原本要手写的 z-index、点击外部关闭、Esc、焦点管理和定位计算,逐步换成 popover 属性、dialog 元素和 CSS 锚点定位的过程,附选型判断和可运行代码。
Date 对象在时区、夏令时和月份索引上的历史包袱一直没解决,这篇讲 TC39 Temporal API 的对象设计、时区处理方式、不可变性的实际收益,以及在账单周期计算这类场景里落地的判断过程。
shadcn/ui 不发 npm 包、直接把组件源码装进你的仓库。聊聊这种 copy-in 模式的好处、维护成本、和传统组件库(Antd/MUI)的取舍。
页面不大、主线程也不忙,首屏却迟迟不出来——把 TTFB、FP、数据包、IP、TCP 握手这些网络层细节和前端性能连起来讲清楚。
Zod 4 的性能改进和 API 变化落到真实项目里:表单校验、接口出入参解析、和 TypeScript 类型互推,以及 schema 复用时容易踩的坑。
大型前端项目的类型检查、编辑器响应和 CI 等待为什么会拖慢反馈链路,以及我会怎么评估 TypeScript 7 Beta(Go 重写)的性能收益和升级风险。
不可变数据、资源管理、新语法这些 ES2026/ESNext 能力,怎么判断它什么时候能真正进业务代码:分清标准阶段、核对工具链转译和 polyfill 成本。
把项目的 lint 和格式化从 ESLint+Prettier 换成 Biome 的过程:速度提升有多明显、规则迁移缺了什么、以及哪些场景我还是留着 ESLint。
同文档 View Transitions 之外,跨文档(MPA)过渡终于可用。记录我给一个传统多页站点加上页面切换动画的过程、view-transition-name 的配对和降级处理。
原生嵌套和 @scope 落地后,我在项目里逐步去掉一部分 Sass 的过程:嵌套的坑、@scope 的下边界 donut scope、以及现在还不能完全替代预处理器的地方。
从 Vue ref、Solid signal 到 TC39 的 Signals 提案,聊聊信号这套响应式模型解决了什么、polyfill 怎么用、以及它和现有框架的关系。
用过一段时间 TanStack Router 后的复盘:文件式与代码式路由、search params 的类型校验、loader 数据预取,以及它和 React Router 的取舍。
Rolldown 把 Vite 的打包从 esbuild/Rollup 双引擎统一成一套 Rust 实现,记录我在中型项目里切过去的体感、兼容性问题和回退策略。
从 v3 升到 v4 的真实迁移过程:Oxide 引擎带来的速度变化、配置从 JS 搬到 CSS、@theme 和 CSS 变量怎么用,以及几个升级时踩的坑。
query string、格式化、深拷贝、请求取消这些场景,很多时候不需要额外装库——JavaScript 原生 API 已经能表达清楚,前提是先看兼容性和团队成本。
Bun 的速度收益到底落在哪一段反馈链路,兼容性能扛到什么程度,成熟前端项目又为什么不该一口气全量迁移,从低风险脚本切入才是稳妥的验证方式。
首屏指标再好看,用户点一下筛选还是能卡半拍——INP、长任务拆分、React 重渲染边界,才是交互性能真正要盯的地方。
同一个错误码在不同页面提示不一致、表单字段错误只会弹 toast,这篇讲清楚怎么把网络错误、业务错误、表单错误和页面反馈重新分层。
手写 scroll 监听算进度容易卡顿,也难维护;CSS view() 能把这类动画交还给浏览器,但兼容降级和动效克制要做到位。
Shadow DOM 里重复插入 style 的维护成本有多高,Constructable Stylesheets 适合什么场景,它和普通 CSS 该怎么分工,这篇讲清楚。
Tooltip、Dropdown、Popover 的定位维护成本一直很高,这篇讲清楚 CSS Anchor Positioning 能省掉哪部分测量代码,以及真实项目里为什么不会立刻全量替换。
AI 对话的逐字输出不是前端定时器假装出来的;SSE 和 fetch 流式读取各有适用场景和失败处理。
批量请求不能只写一个 Promise.all;我更关心同时执行数量、失败重试、取消和用户等待时间怎么平衡。
React Server Components 语法不难,难在判断哪些组件该留在服务端、哪些交互必须下放到客户端,数据获取、缓存和错误处理都要跟着这条线重新划分。
页面慢不一定该上 Edge——渲染位置离用户近了,数据如果还在中心区域,那一跳只是换了个地方出现,缓存策略和运行时限制才是真正要先算清的账。
用户输入一旦被当成 HTML 插进页面,风险就已经埋下了:XSS 的常见入口、富文本清洗、Token 存储的取舍,以及 CSP 从 Report-Only 到正式收紧的落地路径。
国际化不是把文案抽成 JSON 那么简单:文案 key 怎么组织才不冲突、日期数字格式为什么不能手写、长文案怎么撑坏布局、RTL 和翻译流程各自要提前踩的坑。
媒体查询看的是屏幕宽度,但组件真正关心的是自己被放进了多宽的容器——CSS Container Queries 的写法、containment 带来的副作用、适用场景,以及和媒体查询的分工。
把几十个字段都塞进一个 `useState` 对象,短期顺手,字段一多就会失控——字段状态、校验分层、联动逻辑和提交错误各自该放在表单架构的哪一层。
Service Worker 注册容易,但缓存策略想不清楚,用户会长期停留在旧版本、接口数据错乱——生命周期、不同资源的缓存策略、版本更新和断网时的退路该怎么分工。
React 组件为什么会被牵连着重新渲染:状态边界怎么划、memo 和 useCallback 什么时候真的有用、长列表和 Profiler 排查该按什么顺序来,而不是页面一卡就到处加缓存。
列表页的筛选条件到底该放在组件 state 还是 URL 里,判断标准很直接:能不能分享、刷新后要不要保留、需不需要被搜索引擎理解。梳理参数分类、URL 解析防御、push/replace 的选择,以及几个真实会踩的编码坑。
`await fetch()` 加 `try/catch` 只是异步的语法层。真正决定代码经不经得住真实用户折腾的,是请求竞态怎么处理、多个异步任务里一个失败要不要拖累全部、以及循环里的 await 有没有被正确等待。
构建慢不一定是打包工具的锅:依赖体积、类型检查覆盖范围、缓存命中率、代码生成方式,任何一处出问题都会拖慢构建,换工具往往只是把慢延后了。
用户已经觉得页面慢了,开发手上却没有任何证据——Web Vitals 怎么采集才可靠、错误监控怎么带上下文、接口耗时和用户行为怎么串成一条能复现问题的时间线。
覆盖率 80% 不代表核心链路安全:测试资源该按风险而不是按代码行数分配,单元测试、组件测试、E2E 和 Mock 各自该守住哪一层。
TypeScript 5.5 让 filter 之后的类型收窄不再需要手写类型谓词,本文梳理这个推断改进能覆盖到哪一步、satisfies 与 as 的取舍、以及严格模式分阶段落地的具体做法。
手动维护 isSubmitting、error、formValues 这套状态组合,是表单代码变臃肿的根源。React 19 的 Actions、useActionState、useFormStatus 和 useOptimistic 把提交状态、乐观更新和错误处理从组件状态里拆出来,本文梳理具体的写法取舍和并发提交下的坑。
微前端不是性能优化手段,也不是万能拆分方案,它换来的是组织协作上的独立交付,代价是运行时复杂度——判断该不该拆、边界怎么划才是真正的难点。
TypeScript 类型只能保证前端自己代码里的一致性,保护不了后端实际返回的数据——接口类型来源、错误码结构、运行时校验和 Mock 数据,怎么设计才能真正拦住脏数据。
Vite 的开发体验快不代表生产构建就稳:依赖预构建缓存失效、Rollup 分包策略、环境变量该暴露给谁、CJS/ESM 混用踩的坑,以及发版窗口期 chunk 404 该怎么从架构层面接住,这些才是工具链落地时真正要处理的问题。
首屏慢很多时候不是 JS 的问题,而是图片显示 360px 却下载了 2000px 的原图——LCP 图片怎么排查、响应式图片怎么配置、懒加载和占位尺寸各自该怎么取舍。
同一个页面卡顿,可能是 JavaScript 占住了主线程,也可能是布局计算太频繁,还可能是绘制区域太大——不搞清楚 DOM、CSSOM、布局、绘制、合成这几层各自在干什么,排查只能靠试。
React Hydration 为什么要把整个组件重新执行一遍,Qwik 的 Resumability 又是怎么绕开这次重复执行的:从两者的底层机制差异,拆到 mismatch 排查和第三方脚本对主线程的争用。
同一个主色在项目里同时以 `#1677ff`、`rgb(22, 119, 255)`、`var(--blue-6)` 三种形式存在,谁也说不清哪个是标准——Design Token 怎么分层、怎么落地才能让颜色和间距不再散落在业务代码里。
桌面端选型不该从'哪个更新潮'开始,该从三个问题开始:目标机器是什么环境、包体和内存有多敏感、团队有没有人能写 Rust。拿一个内部工具在 Tauri 1.5 和 Electron 28 上各跑了一遍,体积、内存、WebView 兼容性、Rust 侧 invoke、生态成熟度的实测差异都在这里。
了解 Docker 的基础知识,记录前端和 Node 项目在镜像构建、缓存、多阶段构建、健康检查和运行安全上的实践。
aria 属性补不出交互行为:语义化标签、键盘操作、焦点管理和表单提示各自该做到什么程度,什么时候该用原生元素、什么时候才轮到 aria 出场。
新手引导选库只解决遮罩和定位,触发时机、权限差异、异步渲染下的目标缺失和完成记录才是真正的工程成本,也是效果好坏的分水岭。
TypeScript 5.3 的导入属性、类型收窄和运行时互操作看着分散,实际都指向同一件事:编译器认得的语法,构建工具和运行环境未必认得,升级前 dev/build/test 三条链路要分别验。
组件从能复用到真好用,差的是抽象边界、受控状态和组合 API 的取舍。什么时候该抽、什么时候该忍住重复,业务表格越抽越大是最直接的反例。
Next.js 14 该不该跟,要看 Turbopack、Server Actions、部分预渲染背后 App Router 改变了哪些默认认知,而不是新特性列表。我们主用 Vue,这篇是隔壁生态的一次评估。
Web Components 值不值得用,判断标准是组件要不要跨框架、跨页面分发。这篇讲清它适合用在什么场景,以及表单集成、样式互不干扰、事件通信这几处必须提前踩过的成本。
无限级菜单看着是个递归组件,实际牵着路由高亮、权限过滤、图标映射和接口数据清洗。这篇把该在数据层收干净的活,和只留给递归模板的活拆清楚。
XSS、开放跳转、依赖漏洞这些前端安全问题往往不需要高深攻击技巧,一个未过滤的富文本就能捅出娄子。这篇把日常项目该守住的几条底线一条条讲清楚。
WebP 能把图片体积压下去,但这份收益要拿兼容回退、缓存协商和响应式尺寸的工程成本来换。这篇算清楚 WebP 到底省了多少、又要多担哪些事。
CSS 项目做久了没人敢删、改一处崩一片,常被归咎为选型不对,其实根子在归属不清。职责分层、cascade layers、设计变量、命名归属和第三方覆盖集中,才是治理样式的抓手。
CSS 原生滚动时间线 scroll()/view() 上个月刚随 Chrome 115 落地,只有 Chrome 支持、还带实验性质。生产上怎么继续用 JS + IntersectionObserver 稳住,怎么在内部项目里小心尝鲜原生方案,是这篇要说清的。
什么布局该用 Grid、什么该用 Flex,判断依据不是喜好,而是这块结构里有没有需要同时对齐的行和列。轨道、minmax、区域命名、min-width:0 这些细节决定 Grid 好不好用。
WebSocket 断开不触发 onclose、页面显示在线却收不到消息,这类半开连接怎么发现、怎么重连、重连后数据怎么对齐,是实时前端真正难的部分。
Hooks 难的不是记 API,而是理解闭包和依赖数组:请求重复发、按钮读到旧状态、effect 死循环,背后都是同一套渲染机制。这篇整理了我验证这几个问题时留下的笔记。
条件类型的分布式行为为什么会把 boolean 拆成 true | false?infer 到底在推断什么?路由参数能不能直接从路径字符串里提取出类型?半年来在真实项目里用条件类型和模板字面量类型攒下的笔记,以及类型编程该在哪里停下来。
哪些图该懒加载、哪些绝不能懒,是这篇要讲清楚的判断标准:屏外的列表图该延后请求,首屏的 LCP 主图一旦被 loading=lazy 延后反而拖慢首屏。文中覆盖原生 lazy、fetchpriority、IntersectionObserver、占位尺寸与加载失败的补救。
包体积膨胀真正的成本不在压缩,而在分析、拆分和取舍:图表库富文本被打进首屏、公共 chunk 越抽越大、一行 import 引回大依赖,本文讲清楚这些代价怎么算、怎么用体积预算把它卡住。
flex item 被内容撑出容器、z-index 加到六位数仍被遮住、overflow: hidden 一开就连累 sticky,这些布局问题背后都是浏览器的布局与层叠规则,本文按盒模型、收缩、层叠上下文一路拆到底。
响应式规则、props 单向流、watch 该管什么这些 Vue3 坑大多不是语法问题,而是组件逻辑该怎么组织没理清。这篇把自己从 Vue2 迁过来踩过的几个坑连同验证方法一起记下来。
页面卡顿时该先看什么:先把慢分成首屏、切换、滚动、输入四类,再用 Performance 面板、Web Vitals 和真实用户指标把资源、请求、主线程逐层验证,而不是先归因给框架。
组件的可复用性不等于可配置项越多越好,边界该划在哪:基础组件收着做、业务组件贴场景做,props 表达语义而非样式细节,扩展口只当逃生通道。这篇把这几条判断标准讲清楚。
Postgres、Blob、KV 分别对应结构化数据、大文件和临时缓存,边界一旦划不清,小工具很快就会变成谁都说不清结构的烂摊子。三者的分工、Serverless 下的连接数陷阱和迁移前置代价,按数据特征逐一说清。
请求库管的范围正从单纯的 HTTP 客户端往请求状态管理扩展:loading/data/error 三件套重复、旧请求覆盖新结果、缓存 key 设计,这些问题不是换个库名就能解决的,引入新方案的工程代价也要算清。
一个子组件抛错就能让整棵 React 树卸载、整页白屏。Error Boundary 怎么让错误只炸自己那一块、它捕获不到哪些错误、边界放在哪几层,以及 fallback 与错误上报该带什么。
CSS Custom Highlight API 让文本高亮不必再往 DOM 里插 mark 标签:怎么用 Range 注册高亮、多节点匹配的复杂度、::highlight() 的样式边界,以及 Safari 尚未支持时的降级取舍。
E2E 测试该测什么、不该测什么:关键路径优先于覆盖率,选择器、网络等待、登录态复用和 CI 稳定性都要服务于这个取舍。
响应式布局不是让页面在窄屏下不溢出,而是在不同设备上重新分配内容优先级;媒体查询只是实现手段之一,Grid 自适应、容器查询、单位选择、真机适配各解决其中一环。
TypeScript 的类型只在编译期成立,用户输入、接口返回、localStorage 都在运行时进来,类型管不着;这篇讲怎么用 Zod 把运行时校验和类型收敛到同一份 schema,避免两套规则各说各话。
代码评审真正该拦的是接口失败后 loading 不恢复、权限变化菜单不刷新、按钮能重复点这类维护风险,而不是分号和命名;这篇讲怎么按状态流转、异常路径、组件职责给同事讲清楚一条评审意见值不值得改。
同一份状态该进 store、进 URL 还是交给 React Query,判断依据是它的生命周期和归属,而不是写起来方不方便;这篇把 Zustand 的拆分、选择器、派生和持久化这几个取舍讲清楚。
H5 调起摄像头本身没什么难度,难的是拍完之后的图片压缩、方向修正、权限提示、上传重试和 WebView 兼容。
移动端适配别只盯 rem 公式,真机视口、安全区、动态地址栏和表单键盘才是上线后最容易翻车的地方。
服务端状态和本地状态是两回事:缓存新鲜度、mutation 后的失效范围、错误结构统一,这些 React Query 要解决的问题,手写 loading/data/error 很难兜住。
表单草稿、权限开关、接口 payload 经常是同一个业务模型的不同视角,如果每份都手写类型,字段一改就容易漏同步;映射类型能让这些类型互相推导出来。
拆成 Monorepo 要担的代价是什么:pnpm 的硬链接和符号链接策略跟 npm/yarn 的提升策略在幽灵依赖上表现不一样,包之间怎么引用、依赖装在哪一层、CI 要不要全量跑,这些问题不先想清楚,多包项目很快会变成一个更大的混乱仓库。
接口有没有走缓存、样式为什么被覆盖、点击为什么没触发、页面为什么卡、移动端为什么和桌面不一样——这些问题靠 console.log 很难查。梳理 Elements、Network、Sources、Performance、Application 几个面板各自该在什么时候用,以及断点、火焰图、waterfall 这几种排查手段具体怎么落地。
Web Worker 该用在哪、结构化克隆和 Transferable 对象的性能差异、错误处理和任务取消要怎么设计,以及它解决不了什么问题——这篇把这次挪计算逻辑到 Worker 的判断过程理一遍。
Fetch 不会对 4xx/5xx 状态码 reject,必须自己检查 response.ok;结合 Response.clone()、Headers 大小写不敏感、AbortController 超时封装等细节,讨论请求层封装该收多深、和 axios 拦截器比起来各自的取舍。
主题切换不是给 body 加个 class 就完事,CSS 变量、组件库主题和设计 token 分层决定后面好不好维护。
强缓存和协商缓存到底谁优先、命中了会不会发请求,这些问题只看文档很容易记混。这篇拆清 Cache-Control、ETag、文件 hash、HTML 入口和接口缓存该怎么配,顺带讲清楚发布后用户还在看旧页面到底是哪一层出的问题。
scripts 目录堆到没人敢删——Node 自动化脚本写得靠不靠谱,看的是它该失败的时候会不会主动失败。
从 lint、test、build、缓存、预览环境和回滚几个环节,记录我在前端项目里使用 GitHub Actions 搭建发布流程的思路。
全局样式、命名、变量、第三方覆盖到 @layer,讨论中型前端项目里样式优先级怎么从失控收回来。
拖拽排序自己写起来容易,但移动端手势、并发保存、可访问性这几个生产问题决定了什么时候该选库、什么时候不用。
localStorage 用着顺手,但容量、同步读写和跨标签页这几个限制不搞清楚,迟早会踩到该用 IndexedDB 却没用的坑。
文件上传的难点不在选文件,而在选完之后:进度从哪来、取消和失败怎么区分、大文件怎么分片、并发怎么控制。整理这些机制背后的具体判断。
测试工具不缺,缺的是判断标准:什么逻辑值得写单元测试,什么流程只能靠 Cypress 兜底,团队新引入的 Vitest 又该放在什么位置上尝试。
写 Vite 内部插件时,钩子名字只是入口,真正容易出问题的是调试方式、产物路径和插件该不该管到哪一步。
Git 协作出问题时,很少是命令不会敲,更多是提交粒度、分支约定和冲突处理没有共识。
前端能拦住的只是显示,动态路由、菜单和按钮权限背后,真正该由谁负责校验安全,还得看接口。
从图表复杂度、数据规模、交互深度三个维度拆解 ECharts、D3、Chart.js、Recharts、deck.gl 分别适合什么场景,聊聊中后台看板选型时该问清楚的问题。
从 Vuex 迁移到 Pinia,state/getters/actions 这几个 API 名字换起来最快,哪些状态值得全局化、模块该怎么拆、持久化和 SSR 水合的坑怎么避开,才是真正花时间的地方。
旧版 axios CancelToken 和原生 AbortController 两套取消机制并存,判断方式不一样,搜索联想、页面切换这类竞态场景很容易两头踩空。
组件 API 一旦被多个页面引用就很难改。这篇整理 props 粒度、事件命名、v-model 边界和插槽尺度的判断标准,附带一个从 Vuex 挪到 Pinia 时暴露出来的耦合案例。
老项目拆模块时,语法不是重点,依赖关系、循环引用和构建工具怎么理解 ESM/CJS 才是坑。
把 Vue CLI 项目切到 Vite,命令改起来只要五分钟,真正的成本在环境变量、路径别名、静态资源和 CommonJS 依赖这些藏在历史代码里的构建假设上。
工具类方案要不要用,关键看它能不能收住样式复用、响应式、设计约束和团队协作成本这几件事,这篇把 Tailwind 的取舍标准和几个容易踩的坑理清楚。
Composition API 好不好用,关键不在 API 本身,而在按什么维度拆代码——`setup` 里没有强制分区,状态、请求、事件、表单全塞进一个函数体也能跑,但两个月后改起来会很难受。
5 月起 Core Web Vitals 成了 Google 的搜索排名信号,LCP、FID、CLS 这三个词第一次要认真对待。拆开讲这三个指标各自衡量什么、为什么比白屏时间更贴近真实体验,以及图片、字体、长任务、布局稳定性具体怎么优化。
命名含糊、边界条件漏了、可读性差、还有一个不容易一眼看出来的性能隐患——一次具体的 PR 评审里,前端代码评审真正该盯的几个重点。
捕获冒泡和事件委托是老知识,这篇讲的是另外三件事:用 Pointer Events 统一鼠标/触摸/笔输入,用 passive 选项让滚动不被 JS 拖后腿,以及用 CustomEvent 在框架边界之外做组件通信。
自定义下拉框鼠标点没问题、键盘却完全操作不了,图标按钮读屏只念得出“按钮”两个字——这类问题背后是 ARIA 属性、焦点管理和键盘导航没有正确实现,对照 WCAG 2.1 的几条关键判定标准逐一理清。
transition 只管一次状态过渡,animation 管的是一段有起止、可循环、可暂停的时间线。这篇讲清楚 @keyframes 的多关键帧序列、animation-fill-mode 决定动画结束后停在哪、animation-play-state 配合 infinite 做可暂停的加载指示器,以及 Web Animations API 这几年成熟起来后能不能替代 CSS 动画。
BEM 命名规则写在文档里没人真正遵守,这篇讲怎么用 stylelint 的正则把命名校验做进 CI,以及大型项目里 BEM 类名过长、和 CSS Modules 该怎么取舍这些落地层面的真问题。
webpack 5 发布快一年了,这篇聚焦一次真实的 4 到 5 升级:持久化缓存怎么把二次构建砍掉大半、资源模块如何替掉 file-loader 和 url-loader 这几个内置 loader、Tree Shaking 对嵌套导出的改进,以及升级路上撞到的插件兼容性问题。
导航、文章列表、侧边栏全用 div 套 div 实现,样式和交互都没问题,搜索引擎却抓不出结构——语义化标签该怎么选、div 和具体标签的分工怎么定,以及它和可维护性、SEO 之间的真实关系。
路由级、组件级的动态 import 拆分久了会遇到瓶颈:多个独立部署的应用之间怎么在运行时共享模块,而不是各自打包一份。这篇聚焦 webpack 5 的 Module Federation 解决了什么问题,以及和 iframe、npm 包共享组件比起来的取舍。
Google 从 5 月起把 CLS 纳入 Core Web Vitals 排名信号,图片没留高度、字体换脸、动态插入的公告条,都会让页面在用户眼皮底下跳一下。这篇梳理布局偏移的成因、怎么量化、以及从预留空间到合成层动画的一整套应对办法。
安全性和幂等性是两个正交的维度,PUT 和 PATCH 的边界、要不要自动重试、超时该怎么用 AbortController 真正取消请求,这几个问题的答案都落在这两个维度上,而不是死记方法该配哪个动词。
localStorage 本身的机制大家都熟,真正难的是在它之上搭一层能长期维护的存储层:多个业务模块共用同一个源时怎么设计键名规范避免互相覆盖,容量逼近上限时怎么做淘汰而不是简单地报错阻断,以及业务字段调整之后,旧版本浏览器里已经写好的数据结构要怎么平滑过渡。这篇整理的是这一层封装的具体设计。
debounce/throttle 的基础实现网上一搜一大把,真正决定能不能扛住生产场景的,是 leading、trailing、maxWait 这几个选项怎么组合,cancel、flush 这类方法内部靠什么状态支撑,以及搜索请求乱序这种防抖管不住的问题该怎么补。
宏任务微任务的顺序不是这篇的重点,这篇讲 Node 事件循环六个阶段具体怎么运作、process.nextTick 和 setImmediate 谁先谁后、requestIdleCallback 与 requestAnimationFrame 在浏览器里怎么配合调度,以及一次微任务堆积导致页面失去响应的排查过程。
闭包的定义 2018 年那篇已经讲透,这篇往下走一层:闭包封装私有状态的工程代价、和 TypeScript 里刚能用的 class 私有字段 `#field` 的取舍、以及模块模式在 ES Module 普及之后是不是还有存在的必要。
圣杯布局、双飞翼布局、footer 永远贴底、多层嵌套 Flex 的性能账、`row-reverse` 遇上 RTL 语言——这几种经典布局结构换成 Flex 实现之后,原来的取舍标准也跟着变了,值得把新旧方案摆在一起过一遍。
this 的绑定规则不是这篇的重点:class 字段箭头函数怎么自动锁定 this、Vue 2 Options API 靠框架帮你绑好 this、Vue 3 setup() 里 this 整个心智模型的转变、代理对象里 this 指向的陷阱,这几处才是真正容易踩空的地方。
Chrome 88 落地之后,`:is()` 和 `:where()` 不再是观望中的草案,而是能直接用来合并重复选择器、给组件库默认样式主动降权的两个工具,用法和权重差异要分清楚。
整理 ES2021 几个刚定案的新特性在业务代码里的实际用法:String.prototype.replaceAll 怎么替掉正则全局替换的老写法,Promise.any 和 race/allSettled 的区别在哪,逻辑赋值运算符怎么简化默认值赋值,以及数字分隔符和 WeakRef 值不值得现在就用。
字段级正则谁都会写,真正难的是异步校验的竞态取消、多个字段互相牵制的联合校验怎么组织、以及字段和规则都由配置决定的动态表单校验引擎怎么设计。
强缓存和协商缓存的排查规则前几年已经讲过。这篇往下一层:Service Worker 的 Cache API 该选 cache-first 还是 network-first、webpack 5 的 contenthash 稳定性改进、CDN 与源站的两层缓存怎么协同、发布新版本后用户还停在旧页面时的具体修复手段。
吸顶筛选栏在某个页面突然失效,问题往往不在 sticky 本身,而在包含块怎么算、层叠上下文怎么形成——这几条规则理清楚,定位相关的坑基本都能对上号。
盒模型的基础换算大多数人都清楚,真正麻烦的是它和 Grid 轨道尺寸、打印样式、第三方组件库默认样式撞在一起时的连锁反应——这篇不讲 width 加减法,讲这几类交叉场景怎么排查。
SPA 挂一整天不刷新,内存从一百多 MB 涨到一个多 GB,页面卡到点不动——这类泄漏光看代码基本查不出来。整理这次用 DevTools 排查的完整路径:Performance 面板确认泄漏趋势、堆快照三连拍与 Comparison 视图的读法、Detached DOM 树、闭包持有和定时器未清理各自在快照里长什么样。
选择器权重看起来更高,样式却没生效——问题几乎都出在优先级计算规则没吃透。梳理 id/class/标签的权重演算、`!important` 和内联样式的边界,以及 Vue scoped、`::v-deep` 对权重的影响。
同样是往列表里塞一千条数据,直接循环 append 和先用 DocumentFragment 离线拼装再一次性插入,流畅度差得很明显。这篇讲清楚这个差异背后的重排重绘原理,以及和 innerHTML 拼接、事件委托、虚拟滚动这几个相邻方案的取舍。
flex-grow、flex-shrink、flex-basis 的计算规则,align-items 与 align-content 的区别,gap 属性在 flex 容器上的兼容现状和 IE11 的几个已知 bug——一个不定数量标签的自适应工具栏需求把这几个属性的实际行为全部逼了出来。
中后台巨石应用要不要拆成微前端,光看社区文章下不了结论。拿内部一个报表子系统对 qiankun 2.0 做了两周试点:主/子应用的最小接入改造、样式冲突和全局变量的第一印象、公共依赖的现实困境,以及为什么最后的评估结论是小范围试点、不急于全面推开。
`new Array(3)` 和 `[undefined, undefined, undefined]` 看起来一样,`map` 一遍却截然不同;`arguments` 长得像数组却调不了 `.map`。这篇整理数组底层结构、稀疏数组、类数组转换和扩展运算符在数组上的实际边界。
JWT 到底放 HttpOnly Cookie 还是 localStorage,判断标准其实是两个问题:这份凭证谁需要读、被偷走的代价是什么。结合 Chrome 80 把 SameSite 默认改为 Lax 的新背景,梳理 token 的存储位置、刷新续期、多标签页同步和退出登录的完整生命周期。
骨架屏不是所有页面的标配:什么页面值得上骨架屏、什么页面转圈就够,判断标准比实现更重要。手写 CSS 骨架的实现细节、page-skeleton-webpack-plugin 这类构建期自动生成方案的取舍、SSR 场景的直出骨架、骨架和真实内容布局不一致导致的跳动怎么治,都在这次四个页面的落地里过了一遍。
前端联调被后端进度卡住,本质是缺一层可控的接口供应层。用 Express 搭独立 mock 服务的完整方案:中间件模型和路由组织、http-proxy-middleware 做未 mock 接口的透传、mock 数据热更新、延迟与异常模拟,以及它和 devServer.proxy 的分工、要不要往 BFF 方向演进的边界判断。
label 关联、input type 选择、原生校验 API 和自定义校验的边界、submit 事件与按钮 type、提交防重复——这些表单里最容易被随手糊弄过去的细节,在一个多字段资料编辑表单里全部暴露了出来。
用 Canvas 2D 在前端合成营销分享海报,要跨过的坑比想象中多:drawImage 的图片加载时序、measureText 手动实现文本换行、clip 裁圆角头像、跨域图片污染画布导致 toDataURL 报错、devicePixelRatio 不处理导出图就是糊的,还有自定义字体没加载完就绘制的时序问题,逐个记录踩坑和解法。
HappyPack 已经停止维护,webpack 4 官方更推荐 thread-loader、cache-loader 这条路,但项目里的历史配置到底要不要换、什么时候该换,值得掰开讲清楚。
同一份筛选条件,换个存储方式行为就完全不一样:请求体积莫名变大、多标签页数据不同步、刷新后该丢的没丢、不该丢的却丢了。从这几个具体的行为差异,拆开 Cookie、sessionStorage、localStorage 和 IndexedDB 的机制本质,梳理清楚各自该用在什么地方。
线上 JS 报错没人知道、用户截图报障才发现白屏,暴露的是前端错误监控的缺位。window.onerror 和 unhandledrejection 各自能捕获什么、资源加载错误为什么要用捕获阶段监听、跨域脚本的 Script error 怎么破,加上错误聚合去重和 Sentry 接入的取舍,一套采集上报层的完整落地记录。
同样是判断'元素进入视口',scroll 事件加 getBoundingClientRect 和 IntersectionObserver 的差别不只是性能,语义上前者是'我不停地问'、后者是'浏览器主动告诉我'。整理列表曝光埋点和触底加载两个场景下 IO 的 threshold/rootMargin 用法、曝光去重与可见时长统计,以及 root、iframe 相关的几个坑。
线上堆栈只剩 `t.default.a` 这类压缩符号时,问题已经不只是定位某个组件,而是要把 source map、构建产物和断点映射整条链路一起查清。
组件通信真正难的不是传不到,而是状态在谁手里、该由谁负责更新。这里围着 props、emit、provide/inject、事件总线和 Vuex 的边界,重新讲一遍怎么选。
从嵌套数据到可用统计结果,`map`、`filter`、`reduce` 和 `sort` 看起来都不难,真正连起来用时却很容易踩坑。这里把一张报表处理链路里的典型问题集中拆开。
页面慢不一定慢在你的代码开始执行之后,Timing 面板里的 Stalled、Initial connection、SSL 这些阶段同样能拖垮整个请求。这里结合一次抓包结果,把 TCP 握手、挥手、Keep-Alive 和 HTTPS 建连重新挂回真实请求。
页面滚动掉帧,不一定是 JavaScript 算慢了。把 DOM、CSSOM、渲染树、重排、重绘和合成层放回一次真实排查里,看瓶颈到底出在哪一段。
一条存储型 XSS 工单,顺着用户内容渲染这条链路把 XSS、CSRF、转义、DOMPurify、CSP 和 Cookie 策略重新过一遍。
同一个请求失败,前端说接口挂了,后端说参数不对,真正最值钱的信息往往是 Network 面板里那串状态码。文章按 2xx、3xx、4xx、5xx 梳理联调时该怎么用状态码判断问题出在哪一层。
点遮罩却跳进底下详情页、点输入框反而把弹窗关掉,这类问题最后都会回到浏览器的事件模型本身。文章梳理捕获、冒泡、事件委托和移动端点击穿透的成因与修法。
同一份代码强刷是新的,普通刷新却还是旧页面。把强缓存、协商缓存、304 和前端发版策略放回同一个场景里,讲清浏览器为什么会这样表现。
emoji 昵称变问号、CSV 打开像天书、接口中文偶发乱码,看起来像三类问题,根因却都在同一条字符到字节的链路上。这里把 ASCII、Unicode、UTF-8 和常见排查方式串起来。
重置弹窗却把列表数据一起改脏,问题表面在重置,根因却在对象引用。这里从浅拷贝失效一路拆到 JSON 深拷贝的边界、递归复制和循环引用处理。
Promise 最容易让人产生“已经会了”的错觉。这里按七组常见问题,把状态流转、微任务、链式调用、错误传播、并发方法和手写实现重新串起来。