大型前端项目的国际化配置管理实践
之前写过一篇 将vite项目进行国际化改造的文章,里面简单介绍了一下简单项目的国际化落地方案。
国际化原理本身不复杂,但在大型前端项目、尤其是多客户定制的saas项目里面,国际化的工程化问题比技术问题要复杂很多。
假设要把一个按钮从“删除”改成“移除”,源码里只需要改几个字。但放进完整的国际化流程之后,还需要知道:它会不会生成新的词条?已有翻译怎么处理?公共组件里的文案有没有一起提取?后台改过的值会不会被下一次导入覆盖?用户已经打开的页面什么时候拿到更新?
本文总结一种大型前端项目中工程化维护国际化配置的方案。
这套国际化方案有几个直接影响日常维护的决策:静态和动态词条共用映射结构,源码保留中文,类型和命名空间参与 key 的生成,提取与构建保持一致,翻译独立维护。先把这些选择及其原因说明白,再看应用规模增长之后,为什么需要按应用拆分、缓存和版本更新。
Mini-Agent源码分析
发表于 | 分类于 源码分析
最近安排了一些 Agent 开发任务,找了几个项目作为学习材料。这篇分析的是社区基于 MiniMax 官方 Mini-Agent 实现的 TypeScript 版本。官方原版使用 Python,主要用于展示 Agent 的核心执行流程。
两个版本的仓库地址:
- Python 原版:MiniMax-AI/Mini-Agent,由 MiniMax 官方维护。
- TypeScript 版本:Code-MonkeyZhang/mini-agent-ts,由社区开发者基于原项目实现。
这个 TypeScript 版本包含模型推理、工具执行、结果反馈的 ReAct 循环,支持 MCP、Agent Skills,以及 Bash、文件读写等基础工具。代码组织比较直接,可以沿着一次请求读完主要执行链路,适合作为 Agent 开发的入门项目。
本文基于 TypeScript 仓库提交 f0666ad。先把模块关系和执行流程画出来,再沿着一次用户请求往下看。下文关于上下文管理、会话保存和内置工具的判断,均以这一版本为准。
一个具体的问题是:用户说“帮我读一下这个文件”,模型返回一个读取文件的工具调用,后面的文件读取是谁执行的?读取结果又是怎么进入下一次模型请求的?
顺着这条链路,可以把入口、消息历史、模型适配、工具执行,以及 Skills、MCP 的关系串起来。下面的分析依据当前源码,没有运行模型调用和外部 MCP 服务;涉及运行效果的部分,只讨论代码能够说明的行为。
一种统一技术栈的微前端方案
目前参与的前端项目,把业务拆成了多个分别开发、构建和部署的工程,再在浏览器里组合成完整的应用。这套方案主要面向业务持续增长、多个工程共同维护的大型前端项目:各部分有自己的迭代节奏,同时需要统一的产品体验,以及可以持续复用的公共技术能力。
拆开之后,用户的操作仍然会跨越这些项目。比如从订单列表进入账号详情,再打开权限编辑弹窗,几个页面和组件可能由不同项目提供,却需要使用相同的账号上下文、主题和交互规则。
工程拆开之后,还有公共能力怎样更新的问题。一个请求模块或基础组件的修复,如果需要各个业务项目逐一升级依赖、重新构建和部署,公共改动的落地就会涉及多个项目的发布安排。
这篇围绕这些场景整理这套架构:哪些东西需要统一,运行时共享如何减少公共能力更新时的发包和重复构建,项目之间怎样保留独立开发和发布的空间,以及浏览器最终如何把它们加载起来。原工程相关的模块名称、业务场景、资源地址和代码均作通用示意;另有一个配套 Demo,用来展开工程拆分、版本选择和运行时组合的具体实现。
一种用Chrome扩展做自动化采集的方案
发表于 | 分类于 客户端/Chrome扩展程序
写爬虫时,有一类比较麻烦的情况:页面在浏览器里可以正常打开,换成脚本请求,却拿不到相同的内容。
有时返回的是一个等待执行 JavaScript 的页面,有时需要登录,有时还要先经过几个页面操作。即使把请求地址和参数复制出来,也不一定能在另一个环境里直接复现。
我写的 petty-spider 里有一个 Chrome 扩展,就是用来处理这类问题的。它直接在已经打开的网页里提取数据,再通过点击页面上的按钮继续采集。
这篇文章介绍为什么选择这个方案,以及单页提取、连续翻页和结果保存的实现思路。
数据结构与算法可视化
发表于 | 分类于 数据结构和算法
之前在博客里整理过一些数据结构和算法的笔记,包括二分查找、滑动窗口、动态规划、并查集等。阅读这些内容时,经常需要拿一组输入,在纸上记录变量和中间状态,才能确认每一步发生了什么。
最近做了一个数据结构与算法可视化网站,把原理、JavaScript 代码和执行动画放在同一个页面里,可以修改输入、单步执行,也可以自动播放。
全部的代码都是
codex生成的,最后部署在cloudflare上面,我只是给出了大概的实现需求和技术选型~
网站地址:数据结构与算法可视化。
这篇文章介绍网站目前包含的内容,以及代码与动画同步、执行轨迹和静态预渲染的实现思路。
网页标注工具的技术原理与实现
发表于 | 分类于 杂项
阅读网页时,经常需要给某段文字划线、圈出某个区域,或者留下一条笔记。最近整理了一个网页标注项目 annotate,将文本定位、覆盖层渲染和绘图交互提取成独立的 TypeScript 核心包,再通过原生 JavaScript、Vue 示例和 Chrome 扩展接入。
这篇文章主要记录其中的技术原理:一次选区如何变成可以保存的数据,刷新页面后如何找回原文,以及滚动、缩放和布局变化时如何重新绘制标注。
两次 Wi-Fi 故障排查:DNS 无响应、AP 去认证与端口扫描告警
发表于 | 分类于 网络
先后遇到过两次表面相似的 Wi-Fi 故障:
- 第一次是在酒店。Mac 显示 Wi-Fi 已连接,但网站无法访问,改用公共 DNS 后恢复。
- 第二次是在公司。网络间歇性中断,系统日志同时出现 DNS 无响应、无线 AP 去认证和 DHCP 失效;公司的安全系统还把本机标记为端口扫描攻击来源。
两次问题都表现为“连着 Wi-Fi 但无法正常上网”,实际故障层次并不相同。第一次主要位于 DNS 解析链路;第二次同时涉及 DNS、无线链路和可能的网络安全策略。
AI编码的一些体会
发表于 | 分类于 杂项
从 2023 年开始,我每年都会写一篇与 AI 有关的文章,记录自己在当时阶段对 AI 的认识和实际使用感受。
2023 年的《初识 ChatGPT》主要是在了解 ChatGPT、AIGC 和大语言模型等基本概念;2024 年的《我对于 AIGC 的一些看法》讨论了 AIGC 的理解与创作能力,以及它可能带来的影响;2025 年的《一个 AI 独立完成的游戏自动化脚本》则记录了第一次让 AI 基本独立完成一个实际项目的过程。
到了今年,AI 已经从问答和辅助编码工具,逐渐变成可以持续读取项目、修改代码和执行任务的 Agent。这篇文章是这组年度记录的第四篇,关注点也从“AI 能不能写代码”转向了“人应该如何与 AI 一起完成工程开发”。
现在已经没有必要再质疑 AI 能不能参与实际开发了。至少在代码生成、局部修改、调研验证和问题排查等任务上,它已经具备明确的实用价值。
但 AI 能不能替代开发者,是我今年一直在思考的问题。
ENNotes on Coding with AI
发表于
Since 2023 I have written one article a year about AI, recording what I understood about it at the time and what actually using it felt like.
The 2023 piece was about getting acquainted with ChatGPT, AIGC and large language models. The 2024 piece discussed AIGC's comprehension and generative abilities and their likely consequences. The 2025 piece documented the first time I let an AI complete a real project largely on its own. (All three are in Chinese: 初识 ChatGPT, 我对于 AIGC 的一些看法, 一个 AI 独立完成的游戏自动化脚本.)
This year AI has moved from a question-answering and autocomplete tool to an agent that continuously reads a project, edits code and executes tasks. This is the fourth entry in that annual series, and the question has shifted from "can AI write code" to "how should a person work with AI to build software".
There is no longer any point in debating whether AI can participate in real development. For code generation, localised edits, research, verification and debugging, it has clear practical value.
Whether AI can replace developers is the question I have been sitting with all year.
VitePress博客从Valine迁移到Waline:部署、接入与数据迁移
发表于 | 分类于 博客
很久没看博客的留言了,最近登录一下,发现之前用的leancloud已经要停服了

决定来迁移一下,把相关的数据迁移到一个新的留言系统,经过调研,最终决定迁移到Valine。
本文涉及Waline 客户端、Vercel 服务端和 Neon PostgreSQL。内容从账号和项目创建开始,依次完成数据库初始化、VitePress 接入、LeanCloud 历史数据转换、导入校验和上线检查。即使没有历史数据,也可以只使用前半部分完成一个新的 Waline 评论系统。
基于 Puppeteer 与 Chrome Trace 的前端性能自动化测量工具
复杂前端应用的性能问题,往往不发生在首屏加载阶段,而是发生在页面已经运行之后:大批量数据进入、组件持续更新、列表滚动、图表刷新或用户连续操作时,页面开始出现 CPU 占用升高、内存增长、掉帧和响应变慢。
Chrome DevTools 很适合定位一次具体问题,但手工录制难以稳定复现相同场景,也不方便比较两个版本。要让性能评测可以重复执行,需要把浏览器启动、场景操作、性能采集、指标解析和结果对比串成一条自动化链路。
本文整理一种基于 Puppeteer、Chrome Trace Event 和 Chrome DevTools Protocol(下文简称 CDP)的实现思路,重点讨论工具的边界、模块设计和指标提取规则,不涉及任何具体业务代码。
ENAutomating Frontend Performance Measurement with Puppeteer and Chrome Trace
发表于
Performance problems in complex frontend applications usually do not happen during initial load. They happen after the page is already running: large data sets arrive, components keep updating, lists scroll, charts refresh, or a user performs a rapid sequence of actions — and CPU climbs, memory grows, frames drop, and interactions get slower.
Chrome DevTools is excellent for diagnosing one specific occurrence. It is a poor tool for reproducing the same scenario reliably, and a worse one for comparing two builds. Making performance evaluation repeatable means wiring browser launch, scenario steps, data collection, metric extraction and result comparison into a single automated chain.
This post describes an approach built on Puppeteer, Chrome Trace Events and the Chrome DevTools Protocol (CDP). The emphasis is on the tool's boundaries, its module design, and the exact extraction rules for each metric. There is no application-specific code here.
记一次图片缺少EOI导致的渲染异常
最近排查了一个图片预览切换偶发空白的问题,前前后后试了好几种前端方案都没修好,最后发现根因根本不在前端逻辑,而是一张JPEG缺少了EOI结束标记。整个过程有点绕,记录一下。
ENA Truncated JPEG Broke Every Image After It in Chrome
发表于
An image preview would intermittently go blank when stepping through a gallery. I spent a long time inside compositing layers, React render timing and cache behaviour, and fixed none of it. The root cause was two missing bytes at the end of one JPEG.
The detour is the interesting part, so this write-up keeps it.
AMD异步模块配合webpack代码拆分实现业务模块按需加载
最近做了一个业务模块库的按需加载改造。这个库聚合了十几个业务子模块,原来宿主应用一上来就把所有模块全量加载,随着模块越来越多,首屏时间肉眼可见地变长。
目标是:宿主侧零改造,消费方无感知,用到哪个模块才去加载哪个模块对应的 chunk。这篇文章整理了这个过程中的核心技术细节,重点在两块:AMD loader 怎么改造才能支持异步模块,以及 webpack 的 import() 到底做了什么让 factory 变成异步的。
初识Web3之从零构建许愿墙DApp
发表于 | 分类于 杂项
春节假期闲来无聊,打算了解一下web3,借助AI构建了一个简单的许愿墙 DApp,学习Web2应用和Web3应用有什么差异。
这篇文章主要整理一下整个过程,包括遇到的坑和解决方案。
基于monorepo的antd二次开发调试方案
最近在做 Ant Design 的二次开发,需要深度定制一些组件,甚至要改底层的 rc-* 组件。这个过程并不是很顺利,遇到了很多流程上的问题。
本文将介绍一种基于monorepo 二开antd代码的方案,解决antd 二开遇到的一些问题。
cssText和setAttribute在CSP中的差异
最近测试反馈了几个组件库的样式问题,在 dev 和 sit 线上环境可以复现,本地 dev server 却无法复现。排查了一下,发现居然跟对应环境是否开启 CSP 有关。
这个问题挺有意思的,涉及到浏览器对不同样式设置方式的处理差异,值得记录一下。
ENWhy CSP Blocks setAttribute('style') but Not style.cssText
发表于
QA reported styling glitches in a component library that reproduced on the dev and staging deployments but never on a local dev server. The distinguishing factor turned out to be whether the environment sent a Content-Security-Policy header.
Under CSP, styles set with setAttribute('style', …) silently did not apply. Styles set with style.cssText — the same declarations, the same element — applied fine. The DOM inspector showed the attribute present on the element, and the page rendered as though it were not.
基于 Codemod 的前端代码迁移工具开发
前端基础设施升级很少只是修改 package.json。以 React 18 和 Ant Design 4 升级为 React 18 和 Ant Design 5 为例,真正消耗时间的通常是散落在大量项目中的兼容性修改:组件属性更名、路由 API 变化、旧模块导入、样式覆盖失效,以及无法安全自动判断的边界场景。
这类工作如果完全依赖人工,会遇到三个问题:容易遗漏、修改口径不一致、迁移结果难以统计。Codemod 的价值,就是把已经确认的迁移规则固化成可重复执行的程序。
本文总结一个实际迁移工具的设计与实现。示例中的包名、组件名和配置均已泛化,不包含具体业务代码。