<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
            <title type="text">naugnaug</title>
    <updated>2026-09-12T15:02:59+08:00</updated>
        <id>http://naugnaug721.cn</id>
        <link rel="alternate" type="text/html" href="http://naugnaug721.cn" />
        <link rel="self" type="application/atom+xml" href="http://naugnaug721.cn/atom.xml" />
    <rights>Copyright © 2026, naugnaug</rights>
    <generator uri="https://halo.run/" version="1.6.1">Halo</generator>
            <entry>
                <title><![CDATA[TypeScript 类型体操入门：从零到能用]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/typescript-type-gymnastics" />
                <id>tag:http://naugnaug721.cn,2026-09-12:typescript-type-gymnastics</id>
                <published>2026-09-12T15:02:59+08:00</published>
                <updated>2026-09-12T15:02:59+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="typescript-类型体操入门">TypeScript 类型体操入门</h2><p>类型体操（Type Gymnastics）指用 TypeScript 的类型系统做复杂推导，是进阶必学。</p><h3 id="条件类型">条件类型</h3><pre><code class="language-typescript">type IsString&lt;T&gt; = T extends string ? true : false;type A = IsString&lt;&quot;hello&quot;&gt;;  // truetype B = IsString&lt;123&gt;;       // false</code></pre><h3 id="映射类型">映射类型</h3><pre><code class="language-typescript">type Readonly&lt;T&gt; = {  readonly [K in keyof T]: T[K];};type Partial&lt;T&gt; = {  [K in keyof T]?: T[K];};</code></pre><h3 id="模板字面量类型">模板字面量类型</h3><pre><code class="language-typescript">type Greeting = `hello ${string}`;const a: Greeting = &quot;hello world&quot;;  // ✅// const b: Greeting = &quot;hi&quot;;        // ❌// 实用：事件名推导type EventName = &quot;click&quot; | &quot;focus&quot;;type Handler = `on${Capitalize&lt;EventName&gt;}`;// &quot;onClick&quot; | &quot;onFocus&quot;</code></pre><h3 id="infer-提取类型">infer 提取类型</h3><pre><code class="language-typescript">type ReturnType&lt;T&gt; = T extends (...args: any[]) =&gt; infer R ? R : never;type Fn = (a: string) =&gt; number;type R = ReturnType&lt;Fn&gt;;  // number</code></pre><p>掌握类型体操，能写出类型安全、智能提示完善的库代码。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[React 编译器：自动优化告别 useMemo]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/react-compiler" />
                <id>tag:http://naugnaug721.cn,2026-09-12:react-compiler</id>
                <published>2026-09-12T15:02:59+08:00</published>
                <updated>2026-09-12T15:02:59+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="react-编译器正式登场">React 编译器正式登场</h2><p>React 编译器（React Compiler）能自动分析组件、插入最优的 memoization，让开发者不再手写 useMemo 和 useCallback。</p><h3 id="问题背景">问题背景</h3><p>传统 React 中，为了避免不必要的重渲染，开发者要手动优化：</p><pre><code class="language-jsx">function ProductList({ products, filter }) {  const filtered = useMemo(    () =&gt; products.filter(p =&gt; p.category === filter),    [products, filter]  );  const handleClick = useCallback((id) =&gt; {    console.log(id);  }, []);  return &lt;List items={filtered} onClick={handleClick} /&gt;;}</code></pre><p>手写依赖数组容易出错，也增加心智负担。</p><h3 id="编译器写法">编译器写法</h3><p>启用编译器后，同样的逻辑直接写，无需手动优化：</p><pre><code class="language-jsx">function ProductList({ products, filter }) {  const filtered = products.filter(p =&gt; p.category === filter);  const handleClick = (id) =&gt; console.log(id);  return &lt;List items={filtered} onClick={handleClick} /&gt;;}</code></pre><p>编译器会在构建时自动分析依赖，插入等价的缓存逻辑，性能不降反升。</p><h3 id="启用方式">启用方式</h3><pre><code class="language-bash">npm install babel-plugin-react-compiler</code></pre><pre><code class="language-javascript">// babel.config.jsmodule.exports = {  plugins: [[&quot;babel-plugin-react-compiler&quot;, {}]],};</code></pre><p>React 编译器代表了 React 的重要方向：让开发者专注业务逻辑，性能优化交给工具。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[AI 辅助代码重构实战]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/ai-assisted-refactor" />
                <id>tag:http://naugnaug721.cn,2026-09-12:ai-assisted-refactor</id>
                <published>2026-09-12T15:02:59+08:00</published>
                <updated>2026-09-12T15:02:59+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="ai-辅助代码重构">AI 辅助代码重构</h2><p>重构是程序员的日常，AI 能大幅加速这个过程。</p><h3 id="场景一class-转-hooks">场景一：Class 转 Hooks</h3><p>把 React Class 组件迁移到函数组件，AI 能一次性完成：</p><p>输入（选中）：</p><pre><code class="language-jsx">class Timer extends React.Component {  state = { seconds: 0 };  componentDidMount() {    this.interval = setInterval(      () =&gt; this.setState(s =&gt; ({ seconds: s.seconds + 1 })), 1000    );  }  componentWillUnmount() { clearInterval(this.interval); }  render() { return &lt;div&gt;{this.state.seconds}s&lt;/div&gt;; }}</code></pre><p>让 AI 转换，得到：</p><pre><code class="language-jsx">function Timer() {  const [seconds, setSeconds] = useState(0);  useEffect(() =&gt; {    const id = setInterval(() =&gt; setSeconds(s =&gt; s + 1), 1000);    return () =&gt; clearInterval(id);  }, []);  return &lt;div&gt;{seconds}s&lt;/div&gt;;}</code></pre><h3 id="场景二消除重复代码">场景二：消除重复代码</h3><p>选中几段相似代码，问 AI：&quot;抽象出公共函数&quot;。</p><h3 id="场景三性能优化">场景三：性能优化</h3><p>贴一段代码问：&quot;哪里可以优化&quot;，AI 会指出重复计算、不必要的重渲染等问题。</p><h3 id="注意事项">注意事项</h3><p>AI 重构后<strong>务必测试</strong>，尤其是涉及业务逻辑的部分。AI 理解不了你的业务语境，边界情况需要人工确认。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Tailwind CSS v4.5 实用技巧]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/tailwind-v45-tricks" />
                <id>tag:http://naugnaug721.cn,2026-08-07:tailwind-v45-tricks</id>
                <published>2026-08-07T10:00:02+08:00</published>
                <updated>2026-08-07T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="tailwind-css-v45-实用技巧">Tailwind CSS v4.5 实用技巧</h2><p>Tailwind CSS v4.x 系列持续更新，带来了许多提升开发效率的功能。</p><h3 id="自定义动画">自定义动画</h3><p>在 CSS 中直接用 @theme 定义：</p><pre><code class="language-css">@theme {  --animate-slide-up: slide-up 0.3s ease-out;}@keyframes slide-up {  from { transform: translateY(10px); opacity: 0; }  to { transform: translateY(0); opacity: 1; }}</code></pre><pre><code class="language-html">&lt;div class=&quot;animate-slide-up&quot;&gt;内容&lt;/div&gt;</code></pre><h3 id="容器查询">容器查询</h3><p>Tailwind v4.5 原生支持容器查询：</p><pre><code class="language-html">&lt;div class=&quot;@container&quot;&gt;  &lt;div class=&quot;@max-md:flex-col @min-md:flex-row&quot;&gt;    &lt;div class=&quot;@min-md:w-1/3&quot;&gt;侧边栏&lt;/div&gt;    &lt;div class=&quot;@min-md:w-2/3&quot;&gt;主内容&lt;/div&gt;  &lt;/div&gt;&lt;/div&gt;</code></pre><h3 id="实用组合">实用组合</h3><pre><code class="language-html">&lt;button class=&quot;bg-blue-500 hover:bg-blue-600 active:scale-95 transition-transform               disabled:opacity-50 focus-visible:ring-2 focus-visible:ring-blue-400&quot;&gt;  提交&lt;/button&gt;</code></pre><p>Tailwind 在 2026 年依然是 CSS 框架的首选，v4.5 的容器查询支持让响应式开发更加灵活。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[React Server Actions 深入实践]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/server-actions-deep" />
                <id>tag:http://naugnaug721.cn,2026-08-05:server-actions-deep</id>
                <published>2026-08-05T10:00:02+08:00</published>
                <updated>2026-08-05T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="server-actions-理论与实践">Server Actions 理论与实践</h2><p>Server Actions 是 React 19 最重要的新特性之一，允许客户端组件直接调用服务端函数，无需手动创建 API 路由。</p><h3 id="基础使用">基础使用</h3><pre><code class="language-typescript">// app/actions.ts&quot;use server&quot;;import { db } from &quot;@/lib/db&quot;;import { revalidatePath } from &quot;next/cache&quot;;export async function createPost(formData: FormData) {  const title = formData.get(&quot;title&quot;);  const content = formData.get(&quot;content&quot;);  const post = await db.post.create({ data: { title, content } });  revalidatePath(&quot;/posts&quot;);  return post;}</code></pre><p>在客户端组件中使用：</p><pre><code class="language-tsx">&quot;use client&quot;;import { useTransition } from &quot;react&quot;;import { createPost } from &quot;./actions&quot;;export function PostForm() {  const [pending, startTransition] = useTransition();  return (    &lt;form action={createPost}&gt;      &lt;input name=&quot;title&quot; required /&gt;      &lt;textarea name=&quot;content&quot; /&gt;      &lt;button type=&quot;submit&quot; disabled={pending}&gt;发布&lt;/button&gt;    &lt;/form&gt;  );}</code></pre><p>Server Actions 配合 revalidatePath 可以实现 mutations 后自动刷新页面数据，配合 useOptimistic 可以实现乐观更新，无需手动管理 loading 状态。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[TypeScript 5.8 新特性速览]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/typescript-58" />
                <id>tag:http://naugnaug721.cn,2026-08-05:typescript-58</id>
                <published>2026-08-05T10:00:02+08:00</published>
                <updated>2026-08-05T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="typescript-58-新特性">TypeScript 5.8 新特性</h2><p>TypeScript 5.8 在类型系统上做了不少值得关注的改进。</p><h3 id="内联类型导入">内联类型导入</h3><p>以前必须分开写 import type 和 import，现在可以写在一起：</p><pre><code class="language-typescript">import { type User, fetchData, type Config } from &quot;./types&quot;;</code></pre><p>编译时 type 会被移除，不会产生运行时开销。</p><h3 id="const-类型参数">const 类型参数</h3><p>当需要保留字面量类型的精确性时，const 类型参数非常有用：</p><pre><code class="language-typescript">function tuple&lt;T extends readonly any[]&gt;(items: T): T {  return items;}// 推断为 readonly [1, &quot;hello&quot;, true]const result = tuple([1, &quot;hello&quot;, true] as const);</code></pre><h3 id="枚举增强">枚举增强</h3><p>枚举现在可以引用其他枚举的值，这在主题系统中特别有用：</p><pre><code class="language-typescript">enum Color { Red, Green, Blue }enum Theme {  Primary = Color.Blue,  Secondary = Color.Green,}</code></pre><p>TypeScript 在 2026 年已经成为前端项目的标配，这些新特性让类型编程更加流畅。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Prompt Engineering 实战技巧]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/prompt-engineering" />
                <id>tag:http://naugnaug721.cn,2026-08-04:prompt-engineering</id>
                <published>2026-08-04T10:00:01+08:00</published>
                <updated>2026-08-04T10:00:01+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="prompt-engineering-实战">Prompt Engineering 实战</h2><p>写好 prompt 是 2026 年 AI 时代的核心技能。</p><h3 id="结构化-prompt">结构化 Prompt</h3><p>一个好的 prompt 应该包含明确的角色、任务、输出格式和约束：</p><pre><code class="language-markdown">## 角色你是一名资深前端工程师## 任务审查以下代码，找出所有性能问题## 输出格式每条按「问题 → 原因 → 优化方案」的格式输出## 约束- 只关注性能问题- 给出具体的代码示例- 优先级从高到低排列</code></pre><h3 id="few-shot-示例">Few-shot 示例</h3><p>通过示例来引导模型输出：</p><pre><code class="language-typescript">const prompt = `将以下用户反馈分类：反馈：&quot;登录页面加载太慢了&quot; → 性能反馈：&quot;点击按钮没有反应&quot; → Bug反馈：&quot;能不能加个导出功能&quot; → 需求反馈：&quot;${newFeedback}&quot; → `;</code></pre><p>好的 prompt 是 AI 应用成功的一半。花时间设计 prompt 比反复调模型参数更有效。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[AI 文生图工具链 2026：Midjourney vs DALL-E vs SD3]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/ai-image-gen" />
                <id>tag:http://naugnaug721.cn,2026-08-03:ai-image-gen</id>
                <published>2026-08-03T10:00:02+08:00</published>
                <updated>2026-08-03T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="2026-年-ai-文生图工具链">2026 年 AI 文生图工具链</h2><p>AI 图像生成已经从新奇玩具变成实用工具。</p><h3 id="主流工具对比">主流工具对比</h3><table><thead><tr><th>工具</th><th>特点</th><th>适用场景</th></tr></thead><tbody><tr><td>Midjourney</td><td>艺术感最强</td><td>营销素材、海报</td></tr><tr><td>DALL-E 3</td><td>文字理解精准</td><td>快速原型</td></tr><tr><td>Stable Diffusion 3</td><td>开源可定制</td><td>私有化部署</td></tr></tbody></table><h3 id="工程化集成">工程化集成</h3><pre><code class="language-typescript">import Together from &quot;together-ai&quot;;const together = new Together({ apiKey: process.env.TOGETHER_KEY });const response = await together.images.create({  model: &quot;black-forest-labs/FLUX.1-schnell&quot;,  prompt: &quot;简约毛玻璃风格的卡片设计，蓝色调&quot;,  width: 1024,  height: 768,});</code></pre><p>AI 生图在前端开发中常用于生成配图、占位图和设计探索。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[2026 AI 编程未来：开发者何去何从]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/future-ai-developer" />
                <id>tag:http://naugnaug721.cn,2026-08-03:future-ai-developer</id>
                <published>2026-08-03T10:00:02+08:00</published>
                <updated>2026-08-03T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="ai-时代的前端开发者">AI 时代的前端开发者</h2><p>2026 年每个前端开发者都在思考这个问题。</p><h3 id="ai-擅长的">AI 擅长的</h3><ul><li>生成模板代码和组件骨架</li><li>编写单元测试和文档</li><li>CSS 样式调整</li><li>简单 Bug 修复</li><li>API 调用封装</li></ul><h3 id="人类不可替代的">人类不可替代的</h3><ul><li>系统架构设计和技术选型</li><li>用户体验决策和交互设计</li><li>代码审查和关键决策</li><li>与产品和设计的沟通协作</li></ul><h3 id="结论">结论</h3><p>2027 年的前端开发者不是被 AI 取代，而是掌握 AI 工具的开发者取代了不用的。学会与 AI 协作是生存的基本技能。最好的策略是把 AI 当作一个高效的同事，而不是威胁。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[大模型 API 调用最佳实践]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/llm-api-practice" />
                <id>tag:http://naugnaug721.cn,2026-08-03:llm-api-practice</id>
                <published>2026-08-03T10:00:02+08:00</published>
                <updated>2026-08-03T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="大模型-api-调用实践指南">大模型 API 调用实践指南</h2><p>2026 年，调用大模型 API 已经成为后端开发的基本功。</p><h3 id="流式响应">流式响应</h3><pre><code class="language-typescript">const response = await fetch(&quot;https://api.deepseek.com/chat/completions&quot;, {  method: &quot;POST&quot;,  headers: { &quot;Authorization&quot;: &quot;Bearer sk-xxx&quot; },  body: JSON.stringify({    model: &quot;deepseek-chat&quot;,    messages: [{ role: &quot;user&quot;, content: &quot;写一首诗&quot; }],    stream: true,  }),});const reader = response.body.getReader();const decoder = new TextDecoder();while (true) {  const { done, value } = await reader.read();  if (done) break;  process.stdout.write(decoder.decode(value));}</code></pre><h3 id="函数调用tools">函数调用（Tools）</h3><pre><code class="language-typescript">const response = await fetch(&quot;https://api.deepseek.com/v1/chat/completions&quot;, {  method: &quot;POST&quot;,  headers: { &quot;Authorization&quot;: &quot;Bearer sk-xxx&quot; },  body: JSON.stringify({    model: &quot;deepseek-chat&quot;,    messages: [{ role: &quot;user&quot;, content: &quot;北京今天多少度？&quot; }],    tools: [{      type: &quot;function&quot;,      function: {        name: &quot;get_weather&quot;,        description: &quot;获取天气信息&quot;,        parameters: {          type: &quot;object&quot;,          properties: { city: { type: &quot;string&quot; } },          required: [&quot;city&quot;],        },      },    }],  }),});</code></pre><p>掌握大模型 API 调用在 2026 年就像当年掌握 REST API 一样重要。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[AI Agent 模式与实践]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/ai-agent-practice" />
                <id>tag:http://naugnaug721.cn,2026-08-02:ai-agent-practice</id>
                <published>2026-08-02T10:00:02+08:00</published>
                <updated>2026-08-02T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="ai-agent-模式">AI Agent 模式</h2><p>AI Agent 正在从实验性项目走向生产环境。</p><h3 id="单-agent-工作流">单 Agent 工作流</h3><pre><code class="language-typescript">async function customerAgent(query: string) {  // 1. 意图识别  const intent = await llm.classify(query, [    &quot;订单查询&quot;, &quot;退换货&quot;, &quot;产品咨询&quot;  ]);  // 2. 信息检索  const info = intent === &quot;订单查询&quot;    ? await db.orders.findByUser(query)    : await db.products.search(query);  // 3. 生成回复  return llm.generate(query, info);}</code></pre><h3 id="多-agent-协作">多 Agent 协作</h3><pre><code class="language-typescript">// 路由 Agent → 专业 Agent → 汇总 Agentconst specialist = await routerAgent(query);const answer = await specialist.execute(query);const final = await summaryAgent(answer);</code></pre><h3 id="实际应用">实际应用</h3><p>AI Agent 在客服自动化、代码审查、数据分析等场景已经取得显著效果。关键在于合理的 Agent 分工和清晰的指令定义。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[前端错误监控最佳实践 2026]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/error-monitoring-2026" />
                <id>tag:http://naugnaug721.cn,2026-08-01:error-monitoring-2026</id>
                <published>2026-08-01T10:00:01+08:00</published>
                <updated>2026-08-01T10:00:01+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="2026-年前端错误监控">2026 年前端错误监控</h2><p>错误监控是前端工程的必修课。</p><h3 id="全局错误捕获">全局错误捕获</h3><pre><code class="language-javascript">window.addEventListener(&quot;unhandledrejection&quot;, (event) =&gt; {  console.error(&quot;未处理的 Promise 错误:&quot;, event.reason);  fetch(&quot;/api/log-error&quot;, {    method: &quot;POST&quot;,    body: JSON.stringify({      message: event.reason?.message,      stack: event.reason?.stack,      url: window.location.href,      userAgent: navigator.userAgent,    }),  });});</code></pre><h3 id="react-错误边界">React 错误边界</h3><pre><code class="language-tsx">class ErrorBoundary extends React.Component {  state = { hasError: false, error: null };  static getDerivedStateFromError(error) {    return { hasError: true, error };  }  componentDidCatch(error, info) {    console.error(error, info.componentStack);  }  render() {    if (this.state.hasError) {      return &lt;h1&gt;出错了，请刷新页面&lt;/h1&gt;;    }    return this.props.children;  }}</code></pre><h3 id="core-web-vitals-监控">Core Web Vitals 监控</h3><pre><code class="language-javascript">new PerformanceObserver((list) =&gt; {  for (const entry of list.getEntries()) {    if (entry.name === &quot;LCP&quot;) {      console.log(`LCP: ${entry.startTime}ms`);    }  }}).observe({ type: &quot;largest-contentful-paint&quot;, buffered: true });</code></pre>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[前端测试策略 2026：从单元到 E2E]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/testing-strategy-2026" />
                <id>tag:http://naugnaug721.cn,2026-07-31:testing-strategy-2026</id>
                <published>2026-07-31T14:56:51+08:00</published>
                <updated>2026-07-31T14:56:51+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="2026-年的前端测试">2026 年的前端测试</h2><p>前端测试不再追求 100% 覆盖率，而是关注 ROI。</p><h3 id="测试金字塔-2026">测试金字塔 2026</h3><pre><code>          ╱  E2E (5-10%)  ╲      Playwright         ╱  集成 (20-30%)   ╲    Testing Library        ╱   单元 (60-70%)    ╲   Vitest</code></pre><h3 id="playwright-组件测试">Playwright 组件测试</h3><pre><code class="language-typescript">import { test, expect } from &quot;@playwright/experimental-ct-react&quot;;import { Counter } from &quot;./Counter&quot;;test(&quot;点击增加计数&quot;, async ({ mount }) =&gt; {  const component = await mount(&lt;Counter /&gt;);  await component.getByText(&quot;增加&quot;).click();  await expect(component).toContainText(&quot;1&quot;);});</code></pre><p>2026 年的测试策略强调测试用户行为而非实现细节。组件测试比单元测试更有价值，E2E 测试覆盖关键用户流程。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[2026 年 CSS Container Queries 完全指南]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/container-queries-complete" />
                <id>tag:http://naugnaug721.cn,2026-07-31:container-queries-complete</id>
                <published>2026-07-31T10:00:01+08:00</published>
                <updated>2026-07-31T10:00:01+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="container-queries-从入门到精通">Container Queries 从入门到精通</h2><p>容器查询是 2026 年响应式设计的新基石。</p><h3 id="基础用法">基础用法</h3><pre><code class="language-css">.card-container {  container-type: inline-size;  container-name: card;}@container card (min-width: 400px) {  .card { display: grid; grid-template-columns: 200px 1fr; }}</code></pre><h3 id="与媒体查询配合">与媒体查询配合</h3><p>媒体查询管页面级布局，容器查询管组件级适配：</p><pre><code class="language-css">@media (max-width: 768px) {  .grid { grid-template-columns: 1fr; }}@container (min-width: 400px) {  .card { flex-direction: row; }}</code></pre><p>容器查询让组件真正做到&quot;一次编写，到处适配&quot;，是组件化开发的理想方案。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Claude Code vs Cursor：AI 编程工具实测对比]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/ai-coding-tools-compare" />
                <id>tag:http://naugnaug721.cn,2026-07-31:ai-coding-tools-compare</id>
                <published>2026-07-31T10:00:01+08:00</published>
                <updated>2026-07-31T10:00:01+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="2026-年主流-ai-编程工具实测">2026 年主流 AI 编程工具实测</h2><p>AI 编程助手在 2026 年已经成为开发者标配工具。</p><h3 id="claude-code终端级">Claude Code（终端级）</h3><p>直接在终端运行，能够理解整个项目的上下文：</p><pre><code class="language-bash">claude &quot;找出所有未使用的 CSS 类并删除&quot;claude &quot;将这个组件从 Class 组件改为函数组件，添加 TypeScript 类型&quot;</code></pre><p>Claude Code 的优势在于它可以自主阅读代码、运行命令、修改文件，适合重构和代码审查场景。</p><h3 id="cursoride-级">Cursor（IDE 级）</h3><p>Cursor 的核心功能包括：</p><ul><li><strong>Tab 补全</strong>：不只是补一行，而是预测下一步操作</li><li><strong>Composer</strong>：多文件同时编辑</li><li><strong>Agent 模式</strong>：自动运行终端命令</li></ul><h3 id="选型建议">选型建议</h3><p>全栈开发推荐 Cursor，终端脚本和代码审查推荐 Claude Code。两者配合使用效果最佳。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[View Transitions API 实战：多页应用也能流畅过渡]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/view-transitions-practical" />
                <id>tag:http://naugnaug721.cn,2026-07-31:view-transitions-practical</id>
                <published>2026-07-31T10:00:01+08:00</published>
                <updated>2026-07-31T10:00:01+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="view-transitions-api-实战">View Transitions API 实战</h2><p>View Transitions API 让页面之间的过渡动画变得简单，而且能在多页应用中实现 SPA 般的流畅体验。</p><h3 id="基础用法">基础用法</h3><pre><code class="language-javascript">// 页面切换时触发过渡动画document.startViewTransition(() =&gt; {  updateDOM();});</code></pre><h3 id="多页面应用">多页面应用</h3><p>MPA 中可以使用 Cross-document View Transitions：</p><pre><code class="language-css">@view-transition { navigation: auto; }::view-transition-old(root) { animation: fade-out 0.3s ease; }::view-transition-new(root) { animation: fade-in 0.3s ease; }</code></pre><p>View Transitions API 让多页应用也能拥有流畅的页面过渡，是 2026 年值得掌握的新技术。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Biome：Rust 编写的前端工具链新选择]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/biome-toolchain" />
                <id>tag:http://naugnaug721.cn,2026-07-30:biome-toolchain</id>
                <published>2026-07-30T10:00:02+08:00</published>
                <updated>2026-07-30T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="biome-正在改变前端工具链">Biome 正在改变前端工具链</h2><p>Biome 是用 Rust 编写的前端工具链，统一了 lint 和 format，目标是取代 ESLint + Prettier。</p><h3 id="性能对比">性能对比</h3><p>格式化同样的大项目：Biome 只需约 200ms，而 Prettier 需要 3.5 秒，差距接近 20 倍。</p><h3 id="配置简单">配置简单</h3><pre><code class="language-json">{  &quot;formatter&quot;: {    &quot;indentStyle&quot;: &quot;space&quot;,    &quot;indentWidth&quot;: 2,    &quot;lineWidth&quot;: 100  },  &quot;linter&quot;: { &quot;rules&quot;: { &quot;recommended&quot;: true } }}</code></pre><h3 id="迁移">迁移</h3><pre><code class="language-bash">npm uninstall eslint prettiernpm install --save-dev @biomejs/biomenpx biome initnpx biome format --write .</code></pre><p>Biome 的 Rust 底层让它比传统 JS 工具快 10-20 倍，2026 年越来越多的项目正在迁移。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[RAG 技术实战：构建知识库问答系统]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/rag-implementation" />
                <id>tag:http://naugnaug721.cn,2026-07-30:rag-implementation</id>
                <published>2026-07-30T10:00:02+08:00</published>
                <updated>2026-07-30T10:00:02+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="rag-实战指南">RAG 实战指南</h2><p>RAG（检索增强生成）是 2026 年构建企业知识库问答的标准方案。</p><h3 id="架构设计">架构设计</h3><pre><code>用户问题 → 向量化 → 向量检索 → 相关文档 → LLM 生成 → 最终回答</code></pre><h3 id="python-实现">Python 实现</h3><pre><code class="language-python">import chromadbfrom openai import OpenAI# 1. 向量化存储文档collection = chromadb.Client().create_collection(&quot;docs&quot;)collection.add(    documents=[&quot;Halo 是一个开源博客系统&quot;],    ids=[&quot;doc1&quot;],)# 2. 检索相关文档results = collection.query(query_texts=[&quot;Halo 是什么？&quot;], n_results=3)context = &quot;&quot;.join(results[&quot;documents&quot;][0])# 3. 生成回答client = OpenAI()response = client.chat.completions.create(    model=&quot;gpt-4o-mini&quot;,    messages=[{        &quot;role&quot;: &quot;user&quot;,        &quot;content&quot;: f&quot;基于以下资料回答：{context}问题：Halo 是什么？&quot;    }],)</code></pre><p>RAG 解决了 LLM 知识固定的问题，是企业 AI 应用的核心模式。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[React 19 正式发布：Actions 与新 Hooks 实战]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/react-19" />
                <id>tag:http://naugnaug721.cn,2026-07-09:react-19</id>
                <published>2026-07-09T14:10:22+08:00</published>
                <updated>2026-07-09T14:10:22+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="react-19-正式到来">React 19 正式到来</h2><p>React 19 是近年来最重要的版本更新，带来了多项改变游戏规则的新特性。</p><h3 id="actions动作">Actions（动作）</h3><p>Actions 是 React 19 最核心的新概念——它让异步状态管理变得前所未有的简单：</p><pre><code class="language-tsx">&quot;use client&quot;;function SubmitButton() {  // useActionState 管理表单提交状态  const [state, action, pending] = useActionState(    async (prev, formData) =&gt; {      const name = formData.get(&quot;name&quot;);      const res = await fetch(&quot;/api/users&quot;, {        method: &quot;POST&quot;,        body: JSON.stringify({ name }),      });      return { success: true, id: (await res.json()).id };    },    { success: false, id: null }  );  return (    &lt;form action={action}&gt;      &lt;input name=&quot;name&quot; required disabled={pending} /&gt;      &lt;button type=&quot;submit&quot; disabled={pending}&gt;        {pending ? &quot;提交中...&quot; : &quot;提交&quot;}      &lt;/button&gt;      {state.success &amp;&amp; &lt;p&gt;创建成功 ID: {state.id}&lt;/p&gt;}    &lt;/form&gt;  );}</code></pre><h3 id="use--hook">use  Hook</h3><p>可以直接在组件中读取 Promise 和 Context：</p><pre><code class="language-tsx">function Comments({ promise }) {  const comments = use(promise); // 直接 resolve Promise  return comments.map(c =&gt; &lt;p key={c.id}&gt;{c.text}&lt;/p&gt;);}</code></pre><h3 id="ref-作为-prop">ref 作为 prop</h3><p>不再需要 <code>forwardRef</code>：</p><pre><code class="language-tsx">function Input({ ref, ...props }) {  return &lt;input ref={ref} {...props} /&gt;;}</code></pre><p>React 19 标志着 React 进入了新的时代——服务端组件成熟、Actions 简化开发、API 更加直观。</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[2026 年 Web 性能优化完全指南]]></title>
                <link rel="alternate" type="text/html" href="http://naugnaug721.cn/archives/web-perf-2026" />
                <id>tag:http://naugnaug721.cn,2026-07-09:web-perf-2026</id>
                <published>2026-07-09T14:10:22+08:00</published>
                <updated>2026-07-09T14:10:22+08:00</updated>
                <author>
                    <name>Jie</name>
                    <uri>http://naugnaug721.cn</uri>
                </author>
                <content type="html">
                        <![CDATA[<h2 id="2026-年性能优化的新标准">2026 年性能优化的新标准</h2><p>Core Web Vitals 的指标在 2026 年有了新的门槛，以下是当前最佳实践。</p><h3 id="lcp最大内容绘制">LCP（最大内容绘制）</h3><p>2026 年最佳做法：</p><pre><code class="language-html">&lt;!-- 关键资源预加载 --&gt;&lt;link rel=&quot;preload&quot; href=&quot;/fonts/inter.woff2&quot; as=&quot;font&quot; crossorigin&gt;&lt;link rel=&quot;preload&quot; href=&quot;/hero.webp&quot; as=&quot;image&quot;&gt;&lt;!-- 使用 fetchpriority 提示优先级 --&gt;&lt;img src=&quot;hero.webp&quot; fetchpriority=&quot;high&quot; alt=&quot;&quot;&gt;</code></pre><h3 id="inp交互到下次绘制">INP（交互到下次绘制）</h3><p>INP 取代了 FID，衡量的是页面交互的响应速度：</p><pre><code class="language-javascript">// 使用 requestIdleCallback 延迟非关键任务requestIdleCallback(() =&gt; {  loadAnalytics();  initChatWidget();}, { timeout: 2000 });// 避免长任务function processData(data) {  const chunkSize = 50;  for (let i = 0; i &lt; data.length; i += chunkSize) {    setTimeout(() =&gt; {      processChunk(data.slice(i, i + chunkSize));    }, 0);  }}</code></pre><h3 id="图片优化">图片优化</h3><pre><code class="language-html">&lt;!-- AVIF 格式 + 响应式 --&gt;&lt;picture&gt;  &lt;source srcset=&quot;image.avif&quot; type=&quot;image/avif&quot;&gt;  &lt;source srcset=&quot;image.webp&quot; type=&quot;image/webp&quot;&gt;  &lt;img src=&quot;image.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; alt=&quot;&quot;&gt;&lt;/picture&gt;</code></pre><h3 id="性能预算">性能预算</h3><p>每个项目都应该设性能预算：</p><table><thead><tr><th>指标</th><th>目标</th></tr></thead><tbody><tr><td>LCP</td><td>&lt; 2.5s</td></tr><tr><td>INP</td><td>&lt; 200ms</td></tr><tr><td>CLS</td><td>&lt; 0.1</td></tr><tr><td>JS 总大小</td><td>&lt; 300KB</td></tr><tr><td>首屏 HTML</td><td>&lt; 50KB</td></tr></tbody></table><p>2026 年性能优化不再是&quot;加分项&quot;，而是用户体验的基础要求。</p>]]>
                </content>
            </entry>
</feed>
