<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>世界尽头のWasteland</title>
  
  
  <link href="https://blog.rezedge.com/atom.xml" rel="self"/>
  
  <link href="https://blog.rezedge.com/"/>
  <updated>2026-08-17T06:09:03.163Z</updated>
  <id>https://blog.rezedge.com/</id>
  
  <author>
    <name>边缘坐标</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>git_worktree_claude_code</title>
    <link href="https://blog.rezedge.com/posts/78e9e48a/"/>
    <id>https://blog.rezedge.com/posts/78e9e48a/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.163Z</updated>
    
    <content type="html"><![CDATA[<p>[toc]</p><h1 id="Git-Worktree-with-Claude-Code"><a href="#Git-Worktree-with-Claude-Code" class="headerlink" title="Git Worktree with Claude Code"></a>Git Worktree with Claude Code</h1><h3 id="A-Complete-Usage-Guide"><a href="#A-Complete-Usage-Guide" class="headerlink" title="A Complete Usage Guide"></a>A Complete Usage Guide</h3><p><em>Parallel development workflows without stashing or branch switching</em></p><hr><h2 id="1-Overview"><a href="#1-Overview" class="headerlink" title="1. Overview"></a>1. Overview</h2><p>Git Worktree is a built-in Git feature that lets you check out multiple branches simultaneously, each in its own dedicated directory, while sharing a single <code>.git</code> repository. When used together with Claude Code, it enables parallel, isolated AI-assisted development sessions — each session working on a different branch without interfering with one another.</p><h3 id="1-1-Why-Use-Worktrees"><a href="#1-1-Why-Use-Worktrees" class="headerlink" title="1.1 Why Use Worktrees?"></a>1.1 Why Use Worktrees?</h3><p>Traditional git workflow forces you to stash changes, switch branches, work, then switch back. Every context switch disrupts your flow. Worktrees solve this by giving each task a permanent, isolated directory:</p><ul><li>No stashing — each worktree has its own working tree and index.</li><li>Run multiple Claude Code sessions simultaneously on different features.</li><li>Keep a stable main branch always ready to read or run.</li><li>Drastically reduce cognitive overhead when juggling multiple tasks.</li></ul><h3 id="1-2-How-Worktrees-Relate-to-Claude-Code"><a href="#1-2-How-Worktrees-Relate-to-Claude-Code" class="headerlink" title="1.2 How Worktrees Relate to Claude Code"></a>1.2 How Worktrees Relate to Claude Code</h3><p>Claude Code is a terminal-based AI coding agent. Because it operates on the filesystem inside a directory, it respects worktree boundaries naturally. You can:</p><ul><li>Open a separate terminal tab for each worktree.</li><li>Start a dedicated Claude Code session per tab with <code>claude</code>.</li><li>Let Claude work independently on each feature without cross-contamination.</li></ul><blockquote><p><strong>Key Concept:</strong> A worktree is NOT a clone — it shares the same <code>.git</code> database. Creating 5 worktrees uses almost no extra disk space for the repo history. Only the working files are separate.</p></blockquote><hr><h2 id="2-Prerequisites"><a href="#2-Prerequisites" class="headerlink" title="2. Prerequisites"></a>2. Prerequisites</h2><ul><li>Git 2.5 or later (worktrees were introduced in 2.5).</li><li>Claude Code installed: <code>npm install -g @anthropic-ai/claude-code</code> (requires Node.js 18+).</li><li>A local Git repository with at least one commit.</li><li>Familiarity with basic Git concepts (branches, commits, merges).</li></ul><hr><h2 id="3-Core-Concepts"><a href="#3-Core-Concepts" class="headerlink" title="3. Core Concepts"></a>3. Core Concepts</h2><h3 id="3-1-Linked-Worktree-vs-Main-Worktree"><a href="#3-1-Linked-Worktree-vs-Main-Worktree" class="headerlink" title="3.1 Linked Worktree vs Main Worktree"></a>3.1 Linked Worktree vs Main Worktree</h3><p>Every repository has exactly one <strong>main worktree</strong> (where <code>.git/</code> lives). All additional worktrees created with <code>git worktree add</code> are called <strong>linked worktrees</strong>. They store a small <code>.git</code> file (not a directory) pointing back to the main repository’s object database.</p><h3 id="3-2-Branch-Exclusivity"><a href="#3-2-Branch-Exclusivity" class="headerlink" title="3.2 Branch Exclusivity"></a>3.2 Branch Exclusivity</h3><p>Git enforces that a branch can be checked out in <strong>at most one worktree at a time</strong>. Attempting to check out a branch that is already checked out elsewhere will produce an error. This prevents accidental conflicts between worktree sessions.</p><blockquote><p><strong>Important:</strong> If you try to check out the same branch in two worktrees, Git will refuse with:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fatal: &#x27;feature/my-branch&#x27; is already checked out at &#x27;/path/to/other-worktree&#x27;</span><br></pre></td></tr></table></figure><p>Always use distinct branch names per worktree.</p></blockquote><hr><h2 id="4-Creating-a-Worktree-Based-on-Your-Latest-Local-Commit"><a href="#4-Creating-a-Worktree-Based-on-Your-Latest-Local-Commit" class="headerlink" title="4. Creating a Worktree Based on Your Latest Local Commit"></a>4. Creating a Worktree Based on Your Latest Local Commit</h2><p>The most common scenario is creating a new worktree that starts from where your current work is — the latest commit on your main (or current) branch.</p><h3 id="4-1-Verify-Your-Starting-Point"><a href="#4-1-Verify-Your-Starting-Point" class="headerlink" title="4.1 Verify Your Starting Point"></a>4.1 Verify Your Starting Point</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Show current branch and last commit</span></span><br><span class="line">git <span class="built_in">log</span> --oneline -5</span><br><span class="line"></span><br><span class="line"><span class="comment"># Make sure everything is committed (no dirty state on main)</span></span><br><span class="line">git status</span><br></pre></td></tr></table></figure><h3 id="4-2-Create-the-Worktree-with-a-New-Branch"><a href="#4-2-Create-the-Worktree-with-a-New-Branch" class="headerlink" title="4.2 Create the Worktree with a New Branch"></a>4.2 Create the Worktree with a New Branch</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Syntax: git worktree add &lt;path&gt; -b &lt;new-branch&gt; [&lt;start-point&gt;]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Create from the current HEAD (latest local commit):</span></span><br><span class="line">git worktree add ../my-project-feature -b feature/my-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Create from a specific branch tip:</span></span><br><span class="line">git worktree add ../my-project-fix -b fix/critical-bug main</span><br><span class="line"></span><br><span class="line"><span class="comment"># Create from a specific commit hash:</span></span><br><span class="line">git worktree add ../my-project-exp -b experiment/alpha abc1234</span><br></pre></td></tr></table></figure><p>Use a <strong>sibling directory</strong> (<code>../project-feature</code>) to keep worktrees organised alongside your main repo:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~/projects/</span><br><span class="line">  my-project/          ← main worktree (.git lives here)</span><br><span class="line">  my-project-feature/  ← linked worktree for feature/my-feature</span><br><span class="line">  my-project-fix/      ← linked worktree for fix/critical-bug</span><br></pre></td></tr></table></figure><h3 id="4-3-What-Happens-Under-the-Hood"><a href="#4-3-What-Happens-Under-the-Hood" class="headerlink" title="4.3 What Happens Under the Hood"></a>4.3 What Happens Under the Hood</h3><ul><li>Git creates the directory at the specified path.</li><li>It creates a <code>.git</code> file (not folder) inside that directory pointing to the main repo.</li><li>A new branch is created at the specified start point (defaults to HEAD).</li><li>The branch is checked out into the new directory.</li><li>The new branch is registered in <code>.git/worktrees/</code> inside the main repo.</li></ul><h3 id="4-4-Open-Claude-Code-in-the-New-Worktree"><a href="#4-4-Open-Claude-Code-in-the-New-Worktree" class="headerlink" title="4.4 Open Claude Code in the New Worktree"></a>4.4 Open Claude Code in the New Worktree</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># In a new terminal tab:</span></span><br><span class="line"><span class="built_in">cd</span> ../my-project-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Start Claude Code</span></span><br><span class="line">claude</span><br><span class="line"></span><br><span class="line"><span class="comment"># Or for trusted projects (skips permission prompts):</span></span><br><span class="line">claude --dangerously-skip-permissions</span><br></pre></td></tr></table></figure><blockquote><p><strong>Pro Tip:</strong> Use terminal multiplexers like <code>tmux</code> or iTerm2 with named panes:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Pane 1: cd ~/projects/my-project       &amp;&amp; claude   (main branch — read-only reference)</span><br><span class="line">Pane 2: cd ~/projects/my-project-feat  &amp;&amp; claude   (feature branch — active development)</span><br><span class="line">Pane 3: cd ~/projects/my-project-fix   &amp;&amp; claude   (hotfix branch — urgent fix)</span><br></pre></td></tr></table></figure></blockquote><hr><h2 id="5-Making-Commits-Inside-a-Worktree"><a href="#5-Making-Commits-Inside-a-Worktree" class="headerlink" title="5. Making Commits Inside a Worktree"></a>5. Making Commits Inside a Worktree</h2><p>Once inside a linked worktree, all standard Git commands work exactly as expected. The worktree has its own index (staging area) and working tree, completely isolated from other worktrees.</p><h3 id="5-1-Normal-Commit-Workflow"><a href="#5-1-Normal-Commit-Workflow" class="headerlink" title="5.1 Normal Commit Workflow"></a>5.1 Normal Commit Workflow</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Navigate to the worktree</span></span><br><span class="line"><span class="built_in">cd</span> ../my-project-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Stage changes</span></span><br><span class="line">git add .</span><br><span class="line"><span class="comment"># or selectively:</span></span><br><span class="line">git add src/components/Button.tsx</span><br><span class="line"></span><br><span class="line"><span class="comment"># Commit</span></span><br><span class="line">git commit -m <span class="string">&quot;feat: add responsive button component&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Check status</span></span><br><span class="line">git <span class="built_in">log</span> --oneline -3</span><br></pre></td></tr></table></figure><h3 id="5-2-Committing-from-Within-Claude-Code"><a href="#5-2-Committing-from-Within-Claude-Code" class="headerlink" title="5.2 Committing from Within Claude Code"></a>5.2 Committing from Within Claude Code</h3><p>You can ask Claude Code to commit directly. Inside the worktree directory, Claude will use the correct branch automatically:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt; Please implement the search filter component, then commit the changes</span><br><span class="line">&gt;   with a conventional commit message.</span><br></pre></td></tr></table></figure><p>Claude Code will run <code>git add</code>, write a commit message, and execute <code>git commit</code> on your behalf. Because it is running inside the linked worktree directory, it commits to <code>feature/my-feature</code> — not <code>main</code>.</p><h3 id="5-3-Pushing-the-Branch-to-Remote"><a href="#5-3-Pushing-the-Branch-to-Remote" class="headerlink" title="5.3 Pushing the Branch to Remote"></a>5.3 Pushing the Branch to Remote</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># From within the worktree directory:</span></span><br><span class="line">git push -u origin feature/my-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Subsequent pushes (tracking is set):</span></span><br><span class="line">git push</span><br></pre></td></tr></table></figure><hr><h2 id="6-Listing-and-Inspecting-Worktrees"><a href="#6-Listing-and-Inspecting-Worktrees" class="headerlink" title="6. Listing and Inspecting Worktrees"></a>6. Listing and Inspecting Worktrees</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># List all worktrees for the current repository:</span></span><br><span class="line">git worktree list</span><br><span class="line"></span><br><span class="line"><span class="comment"># Example output:</span></span><br><span class="line"><span class="comment"># /Users/alice/projects/my-project          a3f91bc [main]</span></span><br><span class="line"><span class="comment"># /Users/alice/projects/my-project-feature  d4e82ca [feature/my-feature]</span></span><br><span class="line"><span class="comment"># /Users/alice/projects/my-project-fix      a3f91bc [fix/critical-bug]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Verbose output with full details:</span></span><br><span class="line">git worktree list --porcelain</span><br></pre></td></tr></table></figure><hr><h2 id="7-Merging-the-Worktree-Branch-Back-Into-Main"><a href="#7-Merging-the-Worktree-Branch-Back-Into-Main" class="headerlink" title="7. Merging the Worktree Branch Back Into Main"></a>7. Merging the Worktree Branch Back Into Main</h2><p>When your feature or fix is ready, you have two primary strategies for integrating it back into <code>main</code>:</p><table><thead><tr><th>Strategy</th><th>History Shape</th><th>Merge Commit?</th><th>Best For</th></tr></thead><tbody><tr><td>Merge (<code>--no-ff</code>)</td><td>Diverges + converges</td><td>Yes</td><td>Shared branches, full auditability</td></tr><tr><td>Rebase + FF</td><td>Linear</td><td>No</td><td>Clean PRs, solo branches</td></tr><tr><td>Squash Merge</td><td>Linear, single commit</td><td>No</td><td>Keeping main pristine</td></tr></tbody></table><hr><h3 id="Strategy-A-Merge-Commit-—-Preserving-Branch-History-Diverge-Converge"><a href="#Strategy-A-Merge-Commit-—-Preserving-Branch-History-Diverge-Converge" class="headerlink" title="Strategy A: Merge Commit — Preserving Branch History (Diverge + Converge)"></a>Strategy A: Merge Commit — Preserving Branch History (Diverge + Converge)</h3><p>A standard <code>git merge</code> creates a merge commit that explicitly records the point where two diverged histories converged. This is the safest strategy and is preferred for shared, long-lived branches.</p><p><strong>Step 1 — Ensure the feature branch is ready</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project-feature</span><br><span class="line"></span><br><span class="line">git status              <span class="comment"># must be clean</span></span><br><span class="line">git <span class="built_in">log</span> --oneline -5   <span class="comment"># verify your commits look right</span></span><br><span class="line">git push origin feature/my-feature</span><br></pre></td></tr></table></figure><p><strong>Step 2 — Switch to main and pull latest changes</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project</span><br><span class="line"></span><br><span class="line">git checkout main</span><br><span class="line">git pull origin main</span><br></pre></td></tr></table></figure><p><strong>Step 3 — Merge the feature branch</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Merge with an explicit merge commit (no fast-forward):</span></span><br><span class="line">git merge --no-ff feature/my-feature -m <span class="string">&quot;Merge feature/my-feature into main&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># If you want a fast-forward when possible (linear if no divergence):</span></span><br><span class="line">git merge feature/my-feature</span><br></pre></td></tr></table></figure><p><strong>Step 4 — Resolve conflicts (if any)</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Git will mark conflicted files with &lt;&lt;&lt;&lt;&lt;&lt;&lt;, =======, &gt;&gt;&gt;&gt;&gt;&gt;&gt;</span></span><br><span class="line"><span class="comment"># Edit the files to resolve, then:</span></span><br><span class="line">git add &lt;resolved-file&gt;</span><br><span class="line">git merge --<span class="built_in">continue</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Or abort and start over:</span></span><br><span class="line">git merge --abort</span><br></pre></td></tr></table></figure><p><strong>Step 5 — Push main</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin main</span><br></pre></td></tr></table></figure><p><strong>Resulting history graph:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">* 9f4a1bc (main) Merge feature/my-feature into main</span><br><span class="line">|\</span><br><span class="line">| * d4e82ca feat: add responsive button component</span><br><span class="line">| * c3d71ab feat: add button props interface</span><br><span class="line">|/</span><br><span class="line">* a3f91bc Initial commit (the shared start point)</span><br></pre></td></tr></table></figure><hr><h3 id="Strategy-B-Rebase-—-Linear-History-Replay-Without-Divergence"><a href="#Strategy-B-Rebase-—-Linear-History-Replay-Without-Divergence" class="headerlink" title="Strategy B: Rebase — Linear History (Replay Without Divergence)"></a>Strategy B: Rebase — Linear History (Replay Without Divergence)</h3><p>A rebase moves your feature commits on top of the latest <code>main</code>, rewriting them so the history appears linear. There are no merge commits. This is ideal for clean pull request histories or personal feature branches not yet shared with others.</p><blockquote><p><strong>Warning:</strong> Never rebase branches that have already been pushed and shared with other developers. Rewriting shared history forces others to do a hard reset. Only rebase private or PR branches.</p></blockquote><p><strong>Step 1 — Rebase the feature branch onto main</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Fetch latest main first:</span></span><br><span class="line">git fetch origin main</span><br><span class="line"></span><br><span class="line"><span class="comment"># Rebase: replay our commits on top of origin/main:</span></span><br><span class="line">git rebase origin/main</span><br><span class="line"></span><br><span class="line"><span class="comment"># Interactive rebase (squash/edit/reorder commits before integrating):</span></span><br><span class="line">git rebase -i origin/main</span><br></pre></td></tr></table></figure><p><strong>Step 2 — Resolve conflicts during rebase</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># If a conflict occurs, Git pauses at the offending commit.</span></span><br><span class="line"><span class="comment"># Fix the conflict in your editor, then:</span></span><br><span class="line">git add &lt;resolved-file&gt;</span><br><span class="line">git rebase --<span class="built_in">continue</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Skip a particular commit (use with care):</span></span><br><span class="line">git rebase --skip</span><br><span class="line"></span><br><span class="line"><span class="comment"># Abort and return to the original state:</span></span><br><span class="line">git rebase --abort</span><br></pre></td></tr></table></figure><p><strong>Step 3 — Fast-forward main to include the rebased branch</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project</span><br><span class="line"></span><br><span class="line">git checkout main</span><br><span class="line">git pull origin main        <span class="comment"># ensure main is up-to-date</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Fast-forward merge (no merge commit needed — history is linear):</span></span><br><span class="line">git merge feature/my-feature</span><br><span class="line"></span><br><span class="line">git push origin main</span><br></pre></td></tr></table></figure><p><strong>Resulting history graph:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">* d4e82ca&#x27; (main) feat: add responsive button component  ← rebased copy</span><br><span class="line">* c3d71ab&#x27; feat: add button props interface               ← rebased copy</span><br><span class="line">* a3f91bc Initial commit</span><br><span class="line"></span><br><span class="line"># Note the &#x27; marks — commits are rewritten with new hashes.</span><br></pre></td></tr></table></figure><hr><h3 id="Strategy-C-Squash-Merge-—-Collapse-All-Commits-into-One"><a href="#Strategy-C-Squash-Merge-—-Collapse-All-Commits-into-One" class="headerlink" title="Strategy C: Squash Merge — Collapse All Commits into One"></a>Strategy C: Squash Merge — Collapse All Commits into One</h3><p>A squash merge condenses all commits from the feature branch into a single staged change, which you then commit manually onto <code>main</code>. The individual commit history is discarded. This keeps <code>main</code>‘s history extremely clean.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project</span><br><span class="line">git checkout main</span><br><span class="line">git pull origin main</span><br><span class="line"></span><br><span class="line"><span class="comment"># Squash all feature commits into the working tree (staged, not committed):</span></span><br><span class="line">git merge --squash feature/my-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Commit with a single descriptive message:</span></span><br><span class="line">git commit -m <span class="string">&quot;feat: add responsive button component with props (#42)&quot;</span></span><br><span class="line"></span><br><span class="line">git push origin main</span><br></pre></td></tr></table></figure><hr><h2 id="8-Comparison-of-Integration-Strategies"><a href="#8-Comparison-of-Integration-Strategies" class="headerlink" title="8. Comparison of Integration Strategies"></a>8. Comparison of Integration Strategies</h2><table><thead><tr><th><strong>Strategy</strong></th><th><strong>History Shape</strong></th><th><strong>Merge Commit?</strong></th><th><strong>Best For</strong></th></tr></thead><tbody><tr><td>Merge (–no-ff)</td><td>Diverges + converges</td><td>Yes</td><td>Shared branches, full auditability</td></tr><tr><td>Rebase + FF</td><td>Linear</td><td>No</td><td>Clean PRs, solo branches</td></tr><tr><td>Squash Merge</td><td>Linear, single commit</td><td>No</td><td>Keeping main pristine</td></tr></tbody></table><h2 id="9-Removing-a-Worktree-After-Merging"><a href="#9-Removing-a-Worktree-After-Merging" class="headerlink" title="9. Removing a Worktree After Merging"></a>9. Removing a Worktree After Merging</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># From the main worktree directory (or anywhere in the repo):</span></span><br><span class="line">git worktree remove ../my-project-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># If the worktree has untracked or uncommitted changes, force removal:</span></span><br><span class="line">git worktree remove --force ../my-project-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># Prune stale references (e.g., if you deleted the directory manually):</span></span><br><span class="line">git worktree prune</span><br><span class="line"></span><br><span class="line"><span class="comment"># Optionally delete the branch as well:</span></span><br><span class="line">git branch -d feature/my-feature</span><br><span class="line">git push origin --delete feature/my-feature</span><br></pre></td></tr></table></figure><hr><h2 id="10-Full-End-to-End-Example"><a href="#10-Full-End-to-End-Example" class="headerlink" title="10. Full End-to-End Example"></a>10. Full End-to-End Example</h2><p><strong>Scenario:</strong> Add a dark-mode toggle while a hotfix is in progress.</p><p><strong>Step 1 — Check current state</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/projects/my-app</span><br><span class="line">git <span class="built_in">log</span> --oneline -3</span><br><span class="line"><span class="comment"># e7a3c1b (HEAD -&gt; main, origin/main) chore: update dependencies</span></span><br><span class="line"><span class="comment"># 4f92d88 feat: add user profile page</span></span><br><span class="line"><span class="comment"># 1a8bc34 init: scaffold project</span></span><br></pre></td></tr></table></figure><p><strong>Step 2 — Create two worktrees from HEAD</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">git worktree add ../my-app-darkmode  -b feature/dark-mode</span><br><span class="line">git worktree add ../my-app-hotfix    -b fix/login-crash</span><br><span class="line"></span><br><span class="line">git worktree list</span><br><span class="line"><span class="comment"># ~/projects/my-app          e7a3c1b [main]</span></span><br><span class="line"><span class="comment"># ~/projects/my-app-darkmode e7a3c1b [feature/dark-mode]</span></span><br><span class="line"><span class="comment"># ~/projects/my-app-hotfix   e7a3c1b [fix/login-crash]</span></span><br></pre></td></tr></table></figure><p><strong>Step 3 — Work on both in parallel with Claude Code</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Terminal tab 1 — dark mode feature:</span></span><br><span class="line"><span class="built_in">cd</span> ~/projects/my-app-darkmode &amp;&amp; claude</span><br><span class="line">&gt; Implement a dark-mode toggle that persists <span class="keyword">in</span> localStorage.</span><br><span class="line"></span><br><span class="line"><span class="comment"># Terminal tab 2 — hotfix:</span></span><br><span class="line"><span class="built_in">cd</span> ~/projects/my-app-hotfix &amp;&amp; claude</span><br><span class="line">&gt; Fix the login crash when email contains a + character.</span><br></pre></td></tr></table></figure><p><strong>Step 4 — Commit in each worktree independently</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># In my-app-hotfix (fix is urgent, merge first):</span></span><br><span class="line">git add src/auth/login.ts</span><br><span class="line">git commit -m <span class="string">&quot;fix: handle + character in email during login&quot;</span></span><br><span class="line">git push origin fix/login-crash</span><br></pre></td></tr></table></figure><p><strong>Step 5 — Merge the hotfix (fast-forward, linear history)</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/projects/my-app</span><br><span class="line">git checkout main</span><br><span class="line">git pull origin main</span><br><span class="line">git merge fix/login-crash</span><br><span class="line">git push origin main</span><br></pre></td></tr></table></figure><p><strong>Step 6 — Rebase dark-mode onto updated main</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/projects/my-app-darkmode</span><br><span class="line">git fetch origin main</span><br><span class="line">git rebase origin/main   <span class="comment"># replays dark-mode commits on top of the hotfix</span></span><br></pre></td></tr></table></figure><p><strong>Step 7 — Merge dark-mode with a merge commit (to preserve history)</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/projects/my-app</span><br><span class="line">git merge --no-ff feature/dark-mode -m <span class="string">&quot;Merge feature/dark-mode into main&quot;</span></span><br><span class="line">git push origin main</span><br></pre></td></tr></table></figure><p><strong>Step 8 — Clean up</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git worktree remove ../my-app-darkmode</span><br><span class="line">git worktree remove ../my-app-hotfix</span><br><span class="line">git branch -d feature/dark-mode fix/login-crash</span><br><span class="line">git push origin --delete feature/dark-mode fix/login-crash</span><br></pre></td></tr></table></figure><hr><h2 id="11-Quick-Reference"><a href="#11-Quick-Reference" class="headerlink" title="11. Quick Reference"></a>11. Quick Reference</h2><table><thead><tr><th>Command</th><th>Description</th></tr></thead><tbody><tr><td><code>git worktree add &lt;path&gt; -b &lt;branch&gt;</code></td><td>Create new worktree with a new branch from HEAD</td></tr><tr><td><code>git worktree add &lt;path&gt; -b &lt;branch&gt; &lt;start&gt;</code></td><td>Create from specific branch or commit</td></tr><tr><td><code>git worktree list</code></td><td>List all worktrees</td></tr><tr><td><code>git worktree list --porcelain</code></td><td>Machine-readable worktree details</td></tr><tr><td><code>git worktree remove &lt;path&gt;</code></td><td>Remove a linked worktree</td></tr><tr><td><code>git worktree remove --force &lt;path&gt;</code></td><td>Force-remove even with uncommitted changes</td></tr><tr><td><code>git worktree prune</code></td><td>Remove stale worktree metadata</td></tr><tr><td><code>git merge --no-ff &lt;branch&gt;</code></td><td>Merge with explicit merge commit</td></tr><tr><td><code>git merge --squash &lt;branch&gt;</code></td><td>Collapse branch into staged changes</td></tr><tr><td><code>git rebase origin/main</code></td><td>Rebase current branch onto remote main</td></tr><tr><td><code>git rebase -i origin/main</code></td><td>Interactive rebase (squash, edit, reorder)</td></tr><tr><td><code>git branch -d &lt;branch&gt;</code></td><td>Delete local branch after merging</td></tr><tr><td><code>git push origin --delete &lt;branch&gt;</code></td><td>Delete remote branch</td></tr></tbody></table><hr><h2 id="12-Troubleshooting"><a href="#12-Troubleshooting" class="headerlink" title="12. Troubleshooting"></a>12. Troubleshooting</h2><p><strong>Branch already checked out</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fatal: &#x27;feature/my-feature&#x27; is already checked out at &#x27;/path/to/worktree&#x27;</span><br></pre></td></tr></table></figure><p>Solution: use a different branch name, or remove the existing worktree first with <code>git worktree remove /path/to/worktree</code>.</p><p><strong>Detached HEAD in a worktree</strong></p><p>If you created a worktree without <code>-b</code>, it enters detached HEAD state. Create a branch to stabilise it:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git switch -c feature/my-new-branch</span><br></pre></td></tr></table></figure><p><strong>Rebase conflicts with many commits</strong></p><p>When rebasing a long-lived branch, squash your commits first to reduce conflict surface area:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git rebase -i HEAD~N     <span class="comment"># squash N commits into one</span></span><br><span class="line">git rebase origin/main   <span class="comment"># then rebase the single commit</span></span><br></pre></td></tr></table></figure><p><strong>Claude Code editing the wrong branch</strong></p><p>Always verify the branch before starting Claude Code:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project-feature</span><br><span class="line">git branch --show-current   <span class="comment"># must show: feature/my-feature</span></span><br><span class="line">claude</span><br></pre></td></tr></table></figure><hr><h2 id="13-Best-Practices"><a href="#13-Best-Practices" class="headerlink" title="13. Best Practices"></a>13. Best Practices</h2><ul><li>Name worktree directories after their branches for clarity (<code>my-app-feature-dark-mode</code>).</li><li>Keep worktrees as siblings of the main repo, not nested inside it.</li><li>Always commit or stash inside a worktree before removing it — <code>git worktree remove</code> will refuse if there are local changes.</li><li>Use <code>git worktree prune</code> periodically to clean stale references from deleted directories.</li><li>Prefer <code>merge --no-ff</code> for team branches to preserve history; use rebase only on private branches.</li><li>Run <code>git fetch</code> inside each worktree independently — fetch does not automatically propagate across worktrees.</li><li>For long-running features, periodically rebase onto <code>main</code> to minimise merge conflicts later.</li></ul><hr><h2 id="14-Summary"><a href="#14-Summary" class="headerlink" title="14. Summary"></a>14. Summary</h2><p>Git Worktree combined with Claude Code creates a powerful parallel development environment. Each worktree is a fully functional Git checkout — commits, pushes, rebases, and merges all work exactly as on any normal branch.</p><ol><li>Create a worktree from the latest local commit with <code>git worktree add &lt;path&gt; -b &lt;branch&gt;</code>.</li><li>Open a separate Claude Code session (<code>claude</code>) inside each worktree directory.</li><li>Commit and push from within the worktree — it always operates on the correct branch.</li><li>Integrate back into <code>main</code> using a <strong>merge commit</strong> (diverge + converge), a <strong>rebase</strong> (linear), or a <strong>squash merge</strong> (single commit).</li><li>Clean up with <code>git worktree remove</code> and <code>git branch -d</code> once merged.</li></ol><blockquote><p>Git Worktrees do not replace your understanding of branches — they amplify it. Every workflow that works with branches works equally well with worktrees. The only constraint is that each branch can live in at most one worktree at a time.</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;[toc]&lt;/p&gt;
&lt;h1 id=&quot;Git-Worktree-with-Claude-Code&quot;&gt;&lt;a href=&quot;#Git-Worktree-with-Claude-Code&quot; class=&quot;headerlink&quot; title=&quot;Git Worktree with Cla</summary>
      
    
    
    
    <category term="Agent" scheme="https://blog.rezedge.com/categories/Agent/"/>
    
    <category term="claude" scheme="https://blog.rezedge.com/categories/Agent/claude/"/>
    
    
  </entry>
  
  <entry>
    <title>vite dev problem on firefox</title>
    <link href="https://blog.rezedge.com/posts/d4ffbb40/"/>
    <id>https://blog.rezedge.com/posts/d4ffbb40/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.165Z</updated>
    
    <content type="html"><![CDATA[<p>如果 vite 服務器關閉可能導致循環報錯，進一步導致 firefox 卡死崩潰，內存高佔用，什麼網站都打不開，這時候建議 直接 kill，可以保存標籤頁狀態的重開。</p><p>可能導致 localstorage 被清空的副作用，進一步導致登錄狀態失效</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;如果 vite 服務器關閉可能導致循環報錯，進一步導致 firefox 卡死崩潰，內存高佔用，什麼網站都打不開，這時候建議 直接 kill，可以保存標籤頁狀態的重開。&lt;/p&gt;
&lt;p&gt;可能導致 localstorage 被清空的副作用，進一步導致登錄狀態失效&lt;/p&gt;
</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="Browser" scheme="https://blog.rezedge.com/categories/Environment/Browser/"/>
    
    
  </entry>
  
  <entry>
    <title>font-setup-report</title>
    <link href="https://blog.rezedge.com/posts/3e07a109/"/>
    <id>https://blog.rezedge.com/posts/3e07a109/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.166Z</updated>
    
    <content type="html"><![CDATA[<h1 id="字體配置變更報告"><a href="#字體配置變更報告" class="headerlink" title="字體配置變更報告"></a>字體配置變更報告</h1><p>時間：2026-04-30<br>系統：Fedora 43 KDE Plasma 6.6.4 (Wayland)<br>備份目錄：<code>~/.font-config-backup/20260430-120735/</code></p><hr><h2 id="目標"><a href="#目標" class="headerlink" title="目標"></a>目標</h2><p>把系統全局默認字體換成 <strong>CaskaydiaMono Nerd Font</strong>（拉丁&#x2F;代碼）+<br><strong>Sarasa Gothic TC</strong>（繁中），解決原來 Noto Sans CJK 在 Bold 字重下繁中<br>“糊成一團”的問題；同時修復 Ghostty 沒加粗、沒上色的配置缺失。</p><p>範圍覆蓋：KDE 桌面、Konsole、Ghostty、GTK 應用、Flatpak 沙盒應用。<br>未動：VS Code &#x2F; Cursor（用戶確認無問題，且兩者各有獨立字體設定）。</p><hr><h2 id="關鍵發現（執行前的診斷）"><a href="#關鍵發現（執行前的診斷）" class="headerlink" title="關鍵發現（執行前的診斷）"></a>關鍵發現（執行前的診斷）</h2><ol><li><strong>CascadiaMono 完全不含 CJK 字形</strong>（fc-scan 驗證：CJK Unified<br>Ideographs 0&#x2F;20992，Hiragana 0&#x2F;96，Hangul 0&#x2F;11184）。所以 Chinese<br>渲染必須由 fallback 字體承擔。原以爲它支持中文是 fontconfig fallback<br>到 Noto Sans CJK 在背後工作的錯覺。</li><li>系統原本繁中 Bold 解析到 <code>NotoSansCJK-VF.ttc Bold</code> —— 是真實 Bold，<br>不是合成。問題出在 Variable Font 在小字號 + 繁中 + Bold 三重壓力下<br>hinting 退化。</li><li>Ghostty <code>~/.config/ghostty/config</code> 只有一行 <code>shell-integration = zsh</code>，<br>完全沒設字體 &#x2F; 主題 &#x2F; bold 行爲。</li><li>Konsole 沒有自定義 profile，跑系統默認。</li><li>Plasma 6 + <code>kwriteconfig6</code> 可用。</li><li>已裝 7 個 Flatpak 應用（DataGrip &#x2F; Spotify &#x2F; GoldenDict &#x2F; PodmanDesktop<br>&#x2F; Typora &#x2F; Inkscape &#x2F; LocalSend），需要 fonts 目錄掛載授權才能看到<br>新字體。</li></ol><hr><h2 id="安裝的字體"><a href="#安裝的字體" class="headerlink" title="安裝的字體"></a>安裝的字體</h2><h3 id="CaskaydiaMono-Nerd-Font（來源：-Downloads-CascadiaMono-zip）"><a href="#CaskaydiaMono-Nerd-Font（來源：-Downloads-CascadiaMono-zip）" class="headerlink" title="CaskaydiaMono Nerd Font（來源：~/Downloads/CascadiaMono.zip）"></a>CaskaydiaMono Nerd Font（來源：<code>~/Downloads/CascadiaMono.zip</code>）</h3><ul><li>路徑：<code>~/.local/share/fonts/CaskaydiaMono/</code></li><li>數量：36 個 ttf</li><li>變體：<ul><li><strong>Nerd Font</strong>（雙寬圖標，通用）</li><li><strong>Nerd Font Mono</strong>（單寬圖標，終端嚴格對齊）</li><li><strong>Nerd Font Propo</strong>（比例間距，UI 用）</li><li>各含 12 個字重&#x2F;斜體（ExtraLight &#x2F; Light &#x2F; SemiLight &#x2F; Regular &#x2F;<br>SemiBold &#x2F; Bold + 各自 Italic）</li></ul></li></ul><h3 id="Sarasa-Gothic（來源：GitHub-be5invis-Sarasa-Gothic-v1-0-37）"><a href="#Sarasa-Gothic（來源：GitHub-be5invis-Sarasa-Gothic-v1-0-37）" class="headerlink" title="Sarasa Gothic（來源：GitHub be5invis/Sarasa-Gothic v1.0.37）"></a>Sarasa Gothic（來源：GitHub <code>be5invis/Sarasa-Gothic</code> v1.0.37）</h3><ul><li>路徑：<code>~/.local/share/fonts/SarasaGothic/</code></li><li>數量：4 個 ttc（<code>Sarasa-&#123;Regular,Bold,Italic,BoldItalic&#125;.ttc</code>，總 322MB）</li><li>每個 ttc 內含全部區域（TC&#x2F;SC&#x2F;J&#x2F;HC&#x2F;CL）× 全部變體（Gothic&#x2F;Mono&#x2F;Term&#x2F;<br>Fixed&#x2F;UI&#x2F;Slab）</li><li>我們實際使用的是 TC 子集中的：<ul><li><strong>Sarasa Gothic TC</strong>（比例，UI 用）</li><li><strong>Sarasa Mono TC</strong>（等寬 1.0× 配 Cascadia Mono）</li></ul></li></ul><hr><h2 id="配置變更"><a href="#配置變更" class="headerlink" title="配置變更"></a>配置變更</h2><h3 id="1-config-fontconfig-fonts-conf（新建）"><a href="#1-config-fontconfig-fonts-conf（新建）" class="headerlink" title="1. ~/.config/fontconfig/fonts.conf（新建）"></a>1. <code>~/.config/fontconfig/fonts.conf</code>（新建）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">generic family aliases:</span><br><span class="line">  monospace  → CaskaydiaMono Nerd Font Mono → Sarasa Mono TC → Noto fallback</span><br><span class="line">  sans-serif → CaskaydiaMono Nerd Font Propo → Sarasa Gothic TC → Noto fallback</span><br><span class="line">  serif      → Noto Serif → Noto Serif CJK TC</span><br><span class="line"></span><br><span class="line">per-language strong bindings：</span><br><span class="line">  zh-tw  monospace  → Sarasa Mono TC</span><br><span class="line">  zh-tw  sans-serif → Sarasa Gothic TC</span><br><span class="line">  zh-tw  serif      → Noto Serif CJK TC</span><br><span class="line">  zh-hk  → Sarasa *-HC</span><br><span class="line">  zh-cn  → Sarasa *-SC</span><br><span class="line">  ja     → Sarasa *-J</span><br><span class="line"></span><br><span class="line">global rules：</span><br><span class="line">  embolden = false       (禁用合成加粗，避免雙重加粗導致糊)</span><br><span class="line">  embeddedbitmap = false</span><br><span class="line">  hinting = slight, antialias = true, lcdfilter = lcddefault</span><br></pre></td></tr></table></figure><h3 id="2-config-kdeglobals（修改-6-個鍵）"><a href="#2-config-kdeglobals（修改-6-個鍵）" class="headerlink" title="2. ~/.config/kdeglobals（修改 6 個鍵）"></a>2. <code>~/.config/kdeglobals</code>（修改 6 個鍵）</h3><table><thead><tr><th>Key</th><th>Value</th></tr></thead><tbody><tr><td><code>[General] font</code></td><td>CaskaydiaMono Nerd Font Propo, 10 (Regular)</td></tr><tr><td><code>[General] fixed</code></td><td>CaskaydiaMono Nerd Font Mono, 10 (Regular)</td></tr><tr><td><code>[General] smallestReadableFont</code></td><td>CaskaydiaMono Nerd Font Propo, 8 (Regular)</td></tr><tr><td><code>[General] toolBarFont</code></td><td>CaskaydiaMono Nerd Font Propo, 10 (Regular)</td></tr><tr><td><code>[General] menuFont</code></td><td>CaskaydiaMono Nerd Font Propo, 10 (Regular)</td></tr><tr><td><code>[WM] activeFont</code></td><td>CaskaydiaMono Nerd Font Propo, 10 (Bold)</td></tr></tbody></table><h3 id="3-Konsole"><a href="#3-Konsole" class="headerlink" title="3. Konsole"></a>3. Konsole</h3><ul><li><code>~/.config/konsolerc</code> 加 <code>[Desktop Entry] DefaultProfile=Cascadia.profile</code></li><li><code>~/.local/share/konsole/Cascadia.profile</code>（新建）：<ul><li>Font &#x3D; CaskaydiaMono Nerd Font Mono, 11pt</li><li>BoldIntense &#x3D; true</li><li>UseFontLineCharacters &#x3D; true</li><li>HistorySize &#x3D; 10000</li></ul></li></ul><h3 id="4-Ghostty-config-ghostty-config（從-1-行擴展爲完整配置）"><a href="#4-Ghostty-config-ghostty-config（從-1-行擴展爲完整配置）" class="headerlink" title="4. Ghostty ~/.config/ghostty/config（從 1 行擴展爲完整配置）"></a>4. Ghostty <code>~/.config/ghostty/config</code>（從 1 行擴展爲完整配置）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">shell-integration = zsh</span><br><span class="line"></span><br><span class="line">font-family             = CaskaydiaMono Nerd Font Mono</span><br><span class="line">font-family-bold        = CaskaydiaMono Nerd Font Mono</span><br><span class="line">font-family-italic      = CaskaydiaMono Nerd Font Mono</span><br><span class="line">font-family-bold-italic = CaskaydiaMono Nerd Font Mono</span><br><span class="line">font-size               = 11</span><br><span class="line"></span><br><span class="line">font-synthetic-style = no-bold,no-italic,no-bold-italic</span><br><span class="line">bold-is-bright       = false</span><br><span class="line">theme                = catppuccin-mocha</span><br></pre></td></tr></table></figure><p>這裏 <code>bold-is-bright = false</code> 是關鍵 —— 之前”沒加粗”是因爲 Ghostty<br>默認把 bold 屬性當成”變亮顏色”，我們強制它走真實 Bold 字體文件。</p><h3 id="5-GTK-應用（gsettings-org-gnome-desktop-interface）"><a href="#5-GTK-應用（gsettings-org-gnome-desktop-interface）" class="headerlink" title="5. GTK 應用（gsettings org.gnome.desktop.interface）"></a>5. GTK 應用（gsettings org.gnome.desktop.interface）</h3><table><thead><tr><th>Key</th><th>Before</th><th>After</th></tr></thead><tbody><tr><td>font-name</td><td><code>Noto Sans 10</code></td><td><code>CaskaydiaMono Nerd Font Propo 10</code></td></tr><tr><td>monospace-font-name</td><td><code>Noto Sans Mono 10</code></td><td><code>CaskaydiaMono Nerd Font Mono 10</code></td></tr><tr><td>document-font-name</td><td><code>Noto Sans 10</code></td><td><code>CaskaydiaMono Nerd Font Propo 10</code></td></tr></tbody></table><h3 id="6-Flatpak（7-個應用全部加-read-only-掛載）"><a href="#6-Flatpak（7-個應用全部加-read-only-掛載）" class="headerlink" title="6. Flatpak（7 個應用全部加 read-only 掛載）"></a>6. Flatpak（7 個應用全部加 read-only 掛載）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">flatpak override --user --filesystem=~/.local/share/fonts:ro &lt;app&gt;</span><br></pre></td></tr></table></figure><p>應用：<code>com.jetbrains.DataGrip</code> &#x2F; <code>com.spotify.Client</code> &#x2F;<br><code>io.github.xiaoyifang.goldendict_ng</code> &#x2F; <code>io.podman_desktop.PodmanDesktop</code> &#x2F;<br><code>io.typora.Typora</code> &#x2F; <code>org.inkscape.Inkscape</code> &#x2F; <code>org.localsend.localsend_app</code></p><hr><h2 id="驗證結果（fc-match）"><a href="#驗證結果（fc-match）" class="headerlink" title="驗證結果（fc-match）"></a>驗證結果（fc-match）</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">默認 monospace            → CaskaydiaMono Nerd Font Mono Regular ✓</span><br><span class="line">繁中 monospace            → Sarasa Mono TC Regular              ✓</span><br><span class="line">繁中 monospace Bold       → Sarasa Mono TC Bold (real)          ✓</span><br><span class="line">默認 sans-serif           → CaskaydiaMono Nerd Font Propo Regular ✓</span><br><span class="line">繁中 sans-serif           → Sarasa Gothic TC Regular            ✓</span><br><span class="line">繁中 sans-serif Bold      → Sarasa Gothic TC Bold (Sarasa-Bold.ttc) ✓</span><br><span class="line">繁中 serif                → Noto Serif CJK TC Regular           ✓</span><br></pre></td></tr></table></figure><p><strong>繁中 Bold 從原來的 NotoSansCJK-VF（VF hinting 退化）切到了<br>Sarasa-Bold.ttc（手工逐像素 hinting）—— 這是本次修復的核心。</strong></p><hr><h2 id="備份與還原"><a href="#備份與還原" class="headerlink" title="備份與還原"></a>備份與還原</h2><h3 id="備份內容（-font-config-backup-20260430-120735-）"><a href="#備份內容（-font-config-backup-20260430-120735-）" class="headerlink" title="備份內容（~/.font-config-backup/20260430-120735/）"></a>備份內容（<code>~/.font-config-backup/20260430-120735/</code>）</h3><table><thead><tr><th>文件</th><th>用途</th></tr></thead><tbody><tr><td><code>manifest.json</code></td><td>描述變更全貌</td></tr><tr><td><code>kdeglobals.bak</code></td><td>原 kdeglobals 完整副本</td></tr><tr><td><code>konsolerc.bak</code></td><td>原 konsolerc 完整副本</td></tr><tr><td><code>ghostty-config.bak</code></td><td>原 ghostty config（只有 shell-integration &#x3D; zsh）</td></tr><tr><td><code>.fontsconf-was-absent</code></td><td>標記文件：原本沒有 fonts.conf（還原時要刪除新建的）</td></tr><tr><td><code>gsettings.json</code></td><td>三個 GTK font-name 鍵的原始值</td></tr><tr><td><code>flatpak-overrides-global.txt</code></td><td>全局 flatpak 配置原樣</td></tr><tr><td><code>flatpak-per-app/&lt;app&gt;.txt</code></td><td>每個應用的原始 override（7 個）</td></tr><tr><td><code>restore.ts</code></td><td>Bun TypeScript 還原腳本</td></tr></tbody></table><h3 id="還原命令"><a href="#還原命令" class="headerlink" title="還原命令"></a>還原命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 完整還原（默認）</span></span><br><span class="line">bun ~/.font-config-backup/20260430-120735/restore.ts</span><br><span class="line"></span><br><span class="line"><span class="comment"># 還原配置但保留字體文件（之後想自己選用）</span></span><br><span class="line">bun ~/.font-config-backup/20260430-120735/restore.ts --keep-fonts</span><br><span class="line"></span><br><span class="line"><span class="comment"># 預演（不實際修改任何東西）</span></span><br><span class="line">bun ~/.font-config-backup/20260430-120735/restore.ts --dry-run</span><br></pre></td></tr></table></figure><p>restore.ts 已用 <code>--dry-run</code> 驗證可正常運行。</p><hr><h2 id="後續事項"><a href="#後續事項" class="headerlink" title="後續事項"></a>後續事項</h2><ol><li><p><strong>重啓會話讓 Plasma shell 拾取新字體</strong>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kquitapp6 plasmashell &amp;&amp; kstart plasmashell &amp;</span><br></pre></td></tr></table></figure><p>或者直接登出再登錄。已開的 Konsole &#x2F; Ghostty &#x2F; Firefox &#x2F; Typora<br>窗口需要關了重開。</p></li><li><p><strong>Ghostty 主題</strong>改：編輯 <code>~/.config/ghostty/config</code> 最後一行，<br><code>ghostty +list-themes</code> 看可選項。</p></li><li><p><strong>DataGrip</strong>（JetBrains Flatpak）字體要在 IDE 內 Settings → Editor →<br>Font 裏手動選 <code>CaskaydiaMono Nerd Font Mono</code>。權限掛載已做完。</p></li><li><p><strong>可選清理</strong>：<code>~/Downloads/Sarasa-TTC-1.0.37.7z</code>（143MB）已用完<br>可刪。</p></li><li><p><strong>如果繁中加粗仍然偏糊</strong>：可以再加一條 fontconfig 規則把繁中 Bold<br>重映射到 Medium 字重（Sarasa 有 Medium&#x2F;SemiBold 字重可選）。在<br>實際使用幾天後再評估。</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;字體配置變更報告&quot;&gt;&lt;a href=&quot;#字體配置變更報告&quot; class=&quot;headerlink&quot; title=&quot;字體配置變更報告&quot;&gt;&lt;/a&gt;字體配置變更報告&lt;/h1&gt;&lt;p&gt;時間：2026-04-30&lt;br&gt;系統：Fedora 43 KDE Plasma 6.6.4</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="Linux" scheme="https://blog.rezedge.com/categories/Environment/Linux/"/>
    
    
  </entry>
  
  <entry>
    <title>activitywatch-fix-report</title>
    <link href="https://blog.rezedge.com/posts/98d44b61/"/>
    <id>https://blog.rezedge.com/posts/98d44b61/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.165Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ActivityWatch-on-Fedora-43-KDE-Plasma-6-Wayland-—-Fix-Report"><a href="#ActivityWatch-on-Fedora-43-KDE-Plasma-6-Wayland-—-Fix-Report" class="headerlink" title="ActivityWatch on Fedora 43 &#x2F; KDE Plasma 6 Wayland — Fix Report"></a>ActivityWatch on Fedora 43 &#x2F; KDE Plasma 6 Wayland — Fix Report</h1><p><strong>Date:</strong> 2026-04-30<br><strong>Environment:</strong> Fedora 43, KDE Plasma 6, Wayland session, kwin 6.6.4<br><strong>Install location:</strong> <code>/home/edge/.local/share/activitywatch/</code> (官方 bundle 直接解壓)</p><hr><h2 id="TL-DR"><a href="#TL-DR" class="headerlink" title="TL;DR"></a>TL;DR</h2><p>ActivityWatch 在登入後並沒有「真正壞掉」——子模組 (<code>aw-server</code>, <code>aw-watcher-window</code>, <code>aw-watcher-afk</code>) 一直在背景記錄；但 <strong>tray 管理器 <code>aw-qt</code> 在 Wayland session 下啟動時 crash</strong>，所以工作列看不到圖示，也無法用 tray 選單控制服務。額外地，autostart 引用的 <code>Icon=activitywatch</code> 從未被安裝到 hicolor 主題，KDE 自動啟動面板裡的條目顯示空白圖示。</p><p>兩個問題都已修復，登出&#x2F;登入後 tray 圖示會自動出現。</p><hr><h2 id="動了什麼"><a href="#動了什麼" class="headerlink" title="動了什麼"></a>動了什麼</h2><table><thead><tr><th>Path</th><th>Change</th></tr></thead><tbody><tr><td><code>~/.local/share/icons/hicolor/512x512/apps/activitywatch.png</code></td><td>create — 從 <code>media/logo/logo.png</code> (512×512) 複製</td></tr><tr><td><code>~/.local/share/icons/hicolor/128x128/apps/activitywatch.png</code></td><td>create — 從 <code>media/logo/logo-128.png</code> 複製</td></tr><tr><td><code>~/.local/share/icons/hicolor/scalable/apps/activitywatch.svg</code></td><td>create — 從 <code>media/logo/logo.svg</code> 複製</td></tr><tr><td><code>~/.local/share/icons/hicolor/icon-theme.cache</code></td><td>regenerate — <code>gtk-update-icon-cache -f -t</code></td></tr><tr><td><code>~/.config/autostart/aw-qt.desktop</code></td><td>modify — <code>Exec=</code> 前綴加 <code>env QT_QPA_PLATFORM=xcb</code>；<code>Icon=</code> 改為 freedesktop 名稱 <code>activitywatch</code></td></tr></tbody></table><p>最終 autostart <code>.desktop</code> 內容：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Desktop Entry]</span></span><br><span class="line"><span class="attr">Name</span>=ActivityWatch</span><br><span class="line"><span class="attr">GenericName</span>=Time-tracking application</span><br><span class="line"><span class="attr">Comment</span>=Open source time-tracking application with a focus <span class="literal">on</span> extensibility and privacy.</span><br><span class="line"><span class="attr">Exec</span>=env QT_QPA_PLATFORM=xcb /home/edge/.local/share/activitywatch/aw-qt</span><br><span class="line"><span class="attr">Hidden</span>=<span class="literal">false</span></span><br><span class="line"><span class="attr">StartupNotify</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">Terminal</span>=<span class="literal">false</span></span><br><span class="line"><span class="attr">Type</span>=Application</span><br><span class="line"><span class="attr">X-GNOME-Autostart-enabled</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">Version</span>=<span class="number">1.0</span></span><br><span class="line"><span class="attr">Icon</span>=activitywatch</span><br><span class="line"><span class="attr">Categories</span>=Utility<span class="comment">;</span></span><br></pre></td></tr></table></figure><hr><h2 id="診斷過程"><a href="#診斷過程" class="headerlink" title="診斷過程"></a>診斷過程</h2><h3 id="1-先排除「以為設過-systemctl」的記憶"><a href="#1-先排除「以為設過-systemctl」的記憶" class="headerlink" title="1. 先排除「以為設過 systemctl」的記憶"></a>1. 先排除「以為設過 systemctl」的記憶</h3><ul><li><code>~/.config/systemd/user/</code> 整個目錄不存在</li><li><code>systemctl --user list-unit-files | grep activitywatch</code> 空</li><li><code>/usr/lib/systemd/user/</code> 只有 <code>plasma-kactivitymanagerd.service</code>（KDE 自家 kactivitymanagerd，名字相像但跟 ActivityWatch 無關，可能是這個導致記憶混淆）</li></ul><p>→ 結論：systemd user unit <strong>從未被裝起來</strong>，過去能跑是靠 XDG autostart。</p><h3 id="2-autostart-機制本身正常"><a href="#2-autostart-機制本身正常" class="headerlink" title="2. autostart 機制本身正常"></a>2. autostart 機制本身正常</h3><p><code>~/.config/autostart/aw-qt.desktop</code> 存在，且 <code>Exec=</code> 已是絕對路徑。今天 10:10 的 log 顯示 aw-qt 確實有被登入時拉起來。所以 autostart 不是問題。</p><h3 id="3-子模組還在跑、但-aw-qt-自己不見了"><a href="#3-子模組還在跑、但-aw-qt-自己不見了" class="headerlink" title="3. 子模組還在跑、但 aw-qt 自己不見了"></a>3. 子模組還在跑、但 aw-qt 自己不見了</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">ps -ef | grep aw-</span><br><span class="line">edge  3524  2386  ...  aw-server/aw-server         (10:10 起)</span><br><span class="line">edge  3603  2386  ...  aw-watcher-window/...       (10:10 起)</span><br><span class="line">edge  3606  2386  ...  aw-watcher-afk/...          (10:10 起)</span><br><span class="line"># 沒有 aw-qt</span><br></pre></td></tr></table></figure><p>這三個的 PPID &#x3D; 2386，而 PID 2386 是 <code>systemd --user</code>——表示它們本來的父進程 (aw-qt) 死了，被 systemd 收養。子進程沒掛是因為 aw-qt 以 <code>subprocess.Popen</code> 啟動它們，並沒有在自身退出時 kill 掉它們。</p><h3 id="4-在前景重跑-aw-qt-抓到真正的錯誤"><a href="#4-在前景重跑-aw-qt-抓到真正的錯誤" class="headerlink" title="4. 在前景重跑 aw-qt 抓到真正的錯誤"></a>4. 在前景重跑 aw-qt 抓到真正的錯誤</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ /home/edge/.local/share/activitywatch/aw-qt</span><br><span class="line">... [INFO] Creating trayicon... (aw_qt.trayicon:208)</span><br><span class="line">/home/edge/.local/share/activitywatch/aw-qt: symbol lookup error:</span><br><span class="line">  /home/edge/.local/share/activitywatch/libQt6WaylandClient.so.6:</span><br><span class="line">  undefined symbol: wl_proxy_marshal_flags</span><br></pre></td></tr></table></figure><p><strong>找到了。</strong> 之前 log 永遠停在 <code>Creating trayicon...</code> 是因為 dynamic linker 在 trayicon 階段才 lazy-load Qt wayland plugin，符號解析失敗 → 進程被 kernel 直接幹掉，沒有機會寫任何錯誤到 log file。</p><h3 id="5-改用-XWayland-驗證假設"><a href="#5-改用-XWayland-驗證假設" class="headerlink" title="5. 改用 XWayland 驗證假設"></a>5. 改用 XWayland 驗證假設</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ env QT_QPA_PLATFORM=xcb /home/edge/.local/share/activitywatch/aw-qt</span><br><span class="line">... [INFO] Creating trayicon...</span><br><span class="line">... [INFO] Initialized aw-qt and trayicon successfully</span><br></pre></td></tr></table></figure><p>成功。tray 圖示出現。</p><hr><h2 id="根本原因"><a href="#根本原因" class="headerlink" title="根本原因"></a>根本原因</h2><h3 id="問題-A-—-aw-qt-在-Wayland-下-crash"><a href="#問題-A-—-aw-qt-在-Wayland-下-crash" class="headerlink" title="問題 A — aw-qt 在 Wayland 下 crash"></a>問題 A — aw-qt 在 Wayland 下 crash</h3><p>ActivityWatch bundle 內附 <code>libQt6WaylandClient.so.6</code>，這個 .so 引用 <code>wl_proxy_marshal_flags</code> 這個 symbol（屬於 <code>libwayland-client</code>，在 wayland <strong>1.20 之後</strong>才加入）。</p><p>Bundle 內<strong>同時</strong>附了一份較舊的 <code>libwayland-client.so.0</code>，aw-qt 啟動時 <code>LD_LIBRARY_PATH</code> 把 bundle 目錄擺在最前，於是 Qt6WaylandClient 解析 <code>wl_proxy_marshal_flags</code> 時去 bundle 裡的舊 libwayland 找——找不到——symbol lookup error。</p><p>換句話說這是 <strong>bundle 內部的版本不一致 bug</strong>：打包者把新版 Qt wayland plugin 跟舊版 libwayland 放在一起。在 Wayland session（KDE Plasma 6、GNOME 都是）才會踩到，X11 session 不會，因為不會去 dlopen Qt wayland plugin。</p><p><strong>為什麼 Windows 沒這問題？</strong> Windows 平台根本沒有 Qt wayland plugin，aw-qt 只走 Win32 native，不踩這條程式碼路徑。</p><p><strong>修法：</strong> <code>QT_QPA_PLATFORM=xcb</code> 強制 Qt 走 XCB plugin（XWayland），跳過 wayland plugin 的載入。tray icon 走 StatusNotifierItem D-Bus protocol，KDE 對 XWayland 的 SNI 支援很好，視覺體驗跟 native Wayland 沒差。</p><h3 id="問題-B-—-desktop-圖示渲染不出來"><a href="#問題-B-—-desktop-圖示渲染不出來" class="headerlink" title="問題 B — .desktop 圖示渲染不出來"></a>問題 B — <code>.desktop</code> 圖示渲染不出來</h3><p>KDE 自動啟動面板裡 ActivityWatch 條目的圖示空白。</p><p>之前 <code>Icon=</code> 雖然指了絕對路徑 <code>/home/edge/.local/share/activitywatch/media/logo/logo.png</code>，<strong>但 KDE Plasma 6 自動啟動面板不接受絕對路徑</strong>——它只查 freedesktop icon theme 的 name。Bundle 從未把 <code>activitywatch</code> 圖示安裝到 <code>~/.local/share/icons/hicolor/</code>，所以查不到 → 顯示空白。</p><p><strong>修法：</strong> 把 bundle <code>media/logo/</code> 下的三種尺寸 (512×512 PNG, 128×128 PNG, scalable SVG) 安裝到對應的 hicolor 目錄，跑 <code>gtk-update-icon-cache</code>，並把 <code>Icon=</code> 改回 freedesktop name <code>activitywatch</code>。</p><hr><h2 id="解決辦法（最終做法）"><a href="#解決辦法（最終做法）" class="headerlink" title="解決辦法（最終做法）"></a>解決辦法（最終做法）</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 安裝 hicolor 圖示</span></span><br><span class="line"><span class="built_in">mkdir</span> -p ~/.local/share/icons/hicolor/&#123;512x512,128x128,scalable&#125;/apps</span><br><span class="line"><span class="built_in">cp</span> ~/.local/share/activitywatch/media/logo/logo.png      ~/.local/share/icons/hicolor/512x512/apps/activitywatch.png</span><br><span class="line"><span class="built_in">cp</span> ~/.local/share/activitywatch/media/logo/logo-128.png  ~/.local/share/icons/hicolor/128x128/apps/activitywatch.png</span><br><span class="line"><span class="built_in">cp</span> ~/.local/share/activitywatch/media/logo/logo.svg      ~/.local/share/icons/hicolor/scalable/apps/activitywatch.svg</span><br><span class="line">gtk-update-icon-cache -f -t ~/.local/share/icons/hicolor/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 修 autostart .desktop</span></span><br><span class="line"><span class="comment">#    將 Exec= 改成 `env QT_QPA_PLATFORM=xcb /home/edge/.local/share/activitywatch/aw-qt`</span></span><br><span class="line"><span class="comment">#    將 Icon= 改成 `activitywatch`</span></span><br><span class="line"><span class="variable">$EDITOR</span> ~/.config/autostart/aw-qt.desktop</span><br></pre></td></tr></table></figure><hr><h2 id="驗證"><a href="#驗證" class="headerlink" title="驗證"></a>驗證</h2><p>登出&#x2F;登入後：</p><ul><li>Plasma 工作列 system tray 出現 ActivityWatch 圖示</li><li>點開 tray 選單能看到 Modules 列表（aw-server &#x2F; aw-watcher-window &#x2F; aw-watcher-afk 都 running）</li><li>KDE「系統設定 → 啟動與關機 → 自動啟動」面板裡 ActivityWatch 條目有正確圖示</li><li><code>http://localhost:5600</code> web UI 可訪問</li></ul><hr><h2 id="後續建議"><a href="#後續建議" class="headerlink" title="後續建議"></a>後續建議</h2><ul><li><strong>bundle 升級時可重新測試 native Wayland</strong>：哪天上游打包修好 Qt wayland plugin 跟 libwayland 的版本錯位，可以拿掉 <code>QT_QPA_PLATFORM=xcb</code>。判斷方法：直接 <code>~/.local/share/activitywatch/aw-qt</code>（不帶 env），看是否有 <code>Initialized aw-qt and trayicon successfully</code>。</li><li><strong>若想要 systemctl 化管理</strong>（重啟、status、journald log），可改成 systemd user service：建 <code>~/.config/systemd/user/aw-qt.service</code>，<code>ExecStart=env QT_QPA_PLATFORM=xcb /home/edge/.local/share/activitywatch/aw-qt</code>，<code>PartOf=graphical-session.target</code>，<code>WantedBy=graphical-session.target</code>，並把 <code>~/.config/autostart/aw-qt.desktop</code> 設 <code>Hidden=true</code> 避免雙重啟動。本次採用 XDG autostart 簡單方案，未動 systemd。</li><li><strong>目前的 orphan 子進程</strong>：今天 10:10 起的 server&#x2F;watcher 由 systemd 收養而非新 aw-qt，新的 aw-qt tray 選單裡的 Stop&#x2F;Restart 控制不到那批。日常使用無影響（資料都進同一個 sqlite）。如果在意，重開機或手動 <code>pkill -f &#39;aw-(server|watcher)&#39;</code> + 重啟 aw-qt 即可重新接管。</li></ul><hr><h2 id="參考檔案"><a href="#參考檔案" class="headerlink" title="參考檔案"></a>參考檔案</h2><ul><li>Crash log（保留樣本）：<code>~/.cache/activitywatch/log/aw-qt/aw-qt_2026-04-30T11-37-26.log</code> 之後的前景輸出</li><li>Bundle desktop template (上游原始)：<code>/home/edge/.local/share/activitywatch/aw-qt.desktop</code></li><li>修改後的 autostart：<code>~/.config/autostart/aw-qt.desktop</code></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ActivityWatch-on-Fedora-43-KDE-Plasma-6-Wayland-—-Fix-Report&quot;&gt;&lt;a href=&quot;#ActivityWatch-on-Fedora-43-KDE-Plasma-6-Wayland-—-Fix-Report</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="APP" scheme="https://blog.rezedge.com/categories/Environment/APP/"/>
    
    <category term="System" scheme="https://blog.rezedge.com/categories/Environment/APP/System/"/>
    
    
  </entry>
  
  <entry>
    <title>icon-lib</title>
    <link href="https://blog.rezedge.com/posts/2e6ea009/"/>
    <id>https://blog.rezedge.com/posts/2e6ea009/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.170Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ICON-Lib"><a href="#ICON-Lib" class="headerlink" title="ICON Lib"></a>ICON Lib</h1><h3 id="Font-Awesome"><a href="#Font-Awesome" class="headerlink" title="Font Awesome"></a>Font Awesome</h3><h3 id="tabler"><a href="#tabler" class="headerlink" title="tabler"></a>tabler</h3><p>url: <a href="https://tabler.io/icons">https://tabler.io/icons</a></p><h2 id="Brand-SVG"><a href="#Brand-SVG" class="headerlink" title="Brand SVG"></a>Brand SVG</h2><p><a href="https://simpleicons.org/">https://simpleicons.org/</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ICON-Lib&quot;&gt;&lt;a href=&quot;#ICON-Lib&quot; class=&quot;headerlink&quot; title=&quot;ICON Lib&quot;&gt;&lt;/a&gt;ICON Lib&lt;/h1&gt;&lt;h3 id=&quot;Font-Awesome&quot;&gt;&lt;a href=&quot;#Font-Awesome&quot; cla</summary>
      
    
    
    
    <category term="Framework" scheme="https://blog.rezedge.com/categories/Framework/"/>
    
    <category term="Web" scheme="https://blog.rezedge.com/categories/Framework/Web/"/>
    
    <category term="resource" scheme="https://blog.rezedge.com/categories/Framework/Web/resource/"/>
    
    
  </entry>
  
  <entry>
    <title>LangChain 与 Dify：AI 应用开发的两种方式</title>
    <link href="https://blog.rezedge.com/posts/76667553/"/>
    <id>https://blog.rezedge.com/posts/76667553/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.171Z</updated>
    
    <content type="html"><![CDATA[<h1 id="LangChain-与-Dify：AI-应用开发的两种方式"><a href="#LangChain-与-Dify：AI-应用开发的两种方式" class="headerlink" title="LangChain 与 Dify：AI 应用开发的两种方式"></a>LangChain 与 Dify：AI 应用开发的两种方式</h1><p>随着大语言模型（LLM）的快速发展，越来越多开发者开始构建基于 AI 的应用，例如聊天机器人、智能助手、自动化工作流等。在这一领域，<strong>LangChain</strong> 和 <strong>Dify</strong> 是两个非常流行的工具，但它们解决的问题并不相同。</p><p>本文将用简单清晰的方式介绍它们的概念、功能，以及它们之间的区别。</p><hr><h1 id="一、什么是-LangChain"><a href="#一、什么是-LangChain" class="headerlink" title="一、什么是 LangChain"></a>一、什么是 LangChain</h1><p>LangChain</p><p>LangChain 是一个 <strong>开源框架</strong>，用于开发基于大型语言模型（LLM）的应用程序，例如聊天机器人、智能助手或自动化工具。([IBM][1])</p><p>它提供了一套工具和组件，帮助开发者：</p><ul><li>调用各种 AI 模型（如 OpenAI、Claude、Llama 等）</li><li>构建复杂的 AI 工作流程</li><li>连接外部数据源</li><li>构建智能代理（AI Agent）</li></ul><p>简单来说：</p><blockquote><p><strong>LangChain 是一个用代码构建 AI 应用的开发框架。</strong></p></blockquote><hr><h2 id="LangChain-的核心能力"><a href="#LangChain-的核心能力" class="headerlink" title="LangChain 的核心能力"></a>LangChain 的核心能力</h2><h3 id="1-统一调用大模型"><a href="#1-统一调用大模型" class="headerlink" title="1 统一调用大模型"></a>1 统一调用大模型</h3><p>LangChain 可以作为不同 AI 模型的统一接口。</p><p>例如：</p><ul><li>OpenAI</li><li>Anthropic</li><li>HuggingFace</li><li>本地模型</li></ul><p>开发者可以在不同模型之间切换，而无需大量修改代码。([Elastic][2])</p><hr><h3 id="2-Chain（链式工作流）"><a href="#2-Chain（链式工作流）" class="headerlink" title="2 Chain（链式工作流）"></a>2 Chain（链式工作流）</h3><p>LangChain 的核心概念是 <strong>Chain（链）</strong>。</p><p>它允许将多个 AI 步骤串联成一个流程，例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">用户问题</span><br><span class="line"> ↓</span><br><span class="line">检索相关文档</span><br><span class="line"> ↓</span><br><span class="line">生成 Prompt</span><br><span class="line"> ↓</span><br><span class="line">调用 LLM</span><br><span class="line"> ↓</span><br><span class="line">返回答案</span><br></pre></td></tr></table></figure><p>这种方式可以构建复杂的 AI 工作流程。</p><hr><h3 id="3-RAG（检索增强生成）"><a href="#3-RAG（检索增强生成）" class="headerlink" title="3 RAG（检索增强生成）"></a>3 RAG（检索增强生成）</h3><p>RAG 是现代 AI 应用的重要架构。</p><p>流程通常是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">用户提问</span><br><span class="line"> ↓</span><br><span class="line">向量数据库搜索</span><br><span class="line"> ↓</span><br><span class="line">找到相关文档</span><br><span class="line"> ↓</span><br><span class="line">交给 LLM 生成回答</span><br></pre></td></tr></table></figure><p>LangChain 可以很方便地连接各种数据库和数据源，实现 AI 知识库。</p><hr><h3 id="4-Agent（AI-Agent）"><a href="#4-Agent（AI-Agent）" class="headerlink" title="4 Agent（AI Agent）"></a>4 Agent（AI Agent）</h3><p>LangChain 还支持 <strong>AI Agent</strong>。</p><p>AI 可以：</p><ul><li>调用 API</li><li>使用工具</li><li>访问数据库</li><li>自动执行任务</li></ul><p>例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">用户：查一下东京天气</span><br><span class="line">AI → 调用天气 API</span><br><span class="line">AI → 生成回答</span><br></pre></td></tr></table></figure><hr><h1 id="二、什么是-Dify"><a href="#二、什么是-Dify" class="headerlink" title="二、什么是 Dify"></a>二、什么是 Dify</h1><p>Dify</p><p>Dify 是一个 <strong>开源 AI 应用开发平台</strong>，用于快速创建和部署 AI 应用。</p><p>与 LangChain 不同：</p><blockquote><p><strong>Dify 更像一个可视化平台，而不是代码框架。</strong></p></blockquote><p>它提供了一套界面，可以让开发者甚至非程序员通过配置构建 AI 应用。([Information Development Europe B.V.][3])</p><hr><h2 id="Dify-的核心功能"><a href="#Dify-的核心功能" class="headerlink" title="Dify 的核心功能"></a>Dify 的核心功能</h2><h3 id="1-可视化-AI-应用构建"><a href="#1-可视化-AI-应用构建" class="headerlink" title="1 可视化 AI 应用构建"></a>1 可视化 AI 应用构建</h3><p>Dify 提供拖拽式界面，可以直接设计 AI 工作流。</p><p>例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">用户输入</span><br><span class="line"> ↓</span><br><span class="line">知识库搜索</span><br><span class="line"> ↓</span><br><span class="line">LLM 生成回答</span><br><span class="line"> ↓</span><br><span class="line">返回结果</span><br></pre></td></tr></table></figure><p>整个流程可以通过 UI 配置完成。</p><hr><h3 id="2-内置-RAG-知识库"><a href="#2-内置-RAG-知识库" class="headerlink" title="2 内置 RAG 知识库"></a>2 内置 RAG 知识库</h3><p>Dify 支持上传各种数据：</p><ul><li>PDF</li><li>文档</li><li>Markdown</li><li>网站内容</li></ul><p>系统会自动：</p><ul><li>切分文本</li><li>生成向量</li><li>构建知识库</li></ul><p>然后用于 AI 问答。</p><hr><h3 id="3-Workflow（AI-工作流）"><a href="#3-Workflow（AI-工作流）" class="headerlink" title="3 Workflow（AI 工作流）"></a>3 Workflow（AI 工作流）</h3><p>Dify 支持构建复杂工作流，例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">用户输入</span><br><span class="line"> ↓</span><br><span class="line">判断意图</span><br><span class="line"> ↓</span><br><span class="line">调用 API</span><br><span class="line"> ↓</span><br><span class="line">生成 AI 回答</span><br></pre></td></tr></table></figure><p>很多企业用它来构建：</p><ul><li>AI 客服</li><li>AI 知识库</li><li>自动化助手</li></ul><hr><h3 id="4-API-与部署"><a href="#4-API-与部署" class="headerlink" title="4 API 与部署"></a>4 API 与部署</h3><p>Dify 创建的 AI 应用可以直接变成 API，供前端调用。</p><p>因此它也可以作为 AI 后端服务。</p><hr><h1 id="三、LangChain-与-Dify-的区别"><a href="#三、LangChain-与-Dify-的区别" class="headerlink" title="三、LangChain 与 Dify 的区别"></a>三、LangChain 与 Dify 的区别</h1><p>两者最重要的区别在于 <strong>开发方式不同</strong>。</p><table><thead><tr><th>对比</th><th>LangChain</th><th>Dify</th></tr></thead><tbody><tr><td>类型</td><td>开发框架</td><td>应用平台</td></tr><tr><td>使用方式</td><td>写代码</td><td>可视化配置</td></tr><tr><td>用户</td><td>开发者</td><td>开发者 &#x2F; 产品经理</td></tr><tr><td>灵活性</td><td>非常高</td><td>较高</td></tr><tr><td>上手难度</td><td>较高</td><td>较低</td></tr></tbody></table><p>简单理解：</p><ul><li><strong>LangChain &#x3D; AI 编程框架</strong></li><li><strong>Dify &#x3D; AI 应用平台</strong></li></ul><hr><h1 id="四、什么时候使用-LangChain"><a href="#四、什么时候使用-LangChain" class="headerlink" title="四、什么时候使用 LangChain"></a>四、什么时候使用 LangChain</h1><p>LangChain 更适合：</p><ul><li>开发复杂 AI 系统</li><li>构建自定义 Agent</li><li>深度控制 AI 工作流程</li><li>与现有系统深度集成</li></ul><p>例如：</p><ul><li>AI 搜索引擎</li><li>自动化分析系统</li><li>多 Agent 系统</li></ul><hr><h1 id="五、什么时候使用-Dify"><a href="#五、什么时候使用-Dify" class="headerlink" title="五、什么时候使用 Dify"></a>五、什么时候使用 Dify</h1><p>Dify 更适合：</p><ul><li>快速构建 AI 应用</li><li>AI 客服</li><li>AI 知识库</li><li>AI 产品原型</li></ul><p>例如：</p><ul><li>企业内部问答系统</li><li>AI 助手</li><li>AI 工作流工具</li></ul><hr><h1 id="六、LangChain-与-Dify-可以一起使用"><a href="#六、LangChain-与-Dify-可以一起使用" class="headerlink" title="六、LangChain 与 Dify 可以一起使用"></a>六、LangChain 与 Dify 可以一起使用</h1><p>在实际项目中，两者并不是竞争关系。</p><p>常见架构是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Frontend</span><br><span class="line">   ↓</span><br><span class="line">Dify API</span><br><span class="line">   ↓</span><br><span class="line">LangChain</span><br><span class="line">   ↓</span><br><span class="line">LLM</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">复杂逻辑 → LangChain</span><br><span class="line">应用管理 → Dify</span><br></pre></td></tr></table></figure><p>这样既能保持灵活性，也能提高开发效率。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;LangChain-与-Dify：AI-应用开发的两种方式&quot;&gt;&lt;a href=&quot;#LangChain-与-Dify：AI-应用开发的两种方式&quot; class=&quot;headerlink&quot; title=&quot;LangChain 与 Dify：AI 应用开发的两种方式&quot;&gt;&lt;/a</summary>
      
    
    
    
    <category term="Language" scheme="https://blog.rezedge.com/categories/Language/"/>
    
    <category term="AI" scheme="https://blog.rezedge.com/categories/Language/AI/"/>
    
    <category term="Project" scheme="https://blog.rezedge.com/categories/Language/AI/Project/"/>
    
    
  </entry>
  
  <entry>
    <title>Maximum update depth exceeded</title>
    <link href="https://blog.rezedge.com/posts/4accbda0/"/>
    <id>https://blog.rezedge.com/posts/4accbda0/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.172Z</updated>
    
    <content type="html"><![CDATA[<p>有非常多种情况能够导致这该死的问题，以下稍作列举</p><h2 id="zustand-selector"><a href="#zustand-selector" class="headerlink" title="zustand selector"></a>zustand selector</h2><p>需要使用多个独立 selector。</p><p>下面的写法每次<code>render</code>都会返回一个新对象，在 React 19 的 useSyncExternalStore 下会触发你看到的 The result of getSnapshot should be cached，然后一路把整个树拖进无限更新，最后又表现成 InputBase 被动 effect 爆栈。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123;</span><br><span class="line">authSession,</span><br><span class="line">capabilityLevel,</span><br><span class="line">hasAuthSession,</span><br><span class="line">needsOnboarding,</span><br><span class="line">needsVerification,</span><br><span class="line">status,</span><br><span class="line">&#125; = <span class="title function_">useAuthSessionStore</span>(<span class="function"><span class="params">state</span> =&gt;</span> (&#123;</span><br><span class="line"><span class="attr">authSession</span>: state.<span class="property">authSession</span>,</span><br><span class="line"><span class="attr">capabilityLevel</span>: state.<span class="property">capabilityLevel</span>,</span><br><span class="line"><span class="attr">hasAuthSession</span>: state.<span class="property">hasAuthSession</span>,</span><br><span class="line"><span class="attr">needsOnboarding</span>: state.<span class="property">needsOnboarding</span>,</span><br><span class="line"><span class="attr">needsVerification</span>: state.<span class="property">needsVerification</span>,</span><br><span class="line"><span class="attr">status</span>: state.<span class="property">status</span>,</span><br><span class="line">&#125;));</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;有非常多种情况能够导致这该死的问题，以下稍作列举&lt;/p&gt;
&lt;h2 id=&quot;zustand-selector&quot;&gt;&lt;a href=&quot;#zustand-selector&quot; class=&quot;headerlink&quot; title=&quot;zustand selector&quot;&gt;&lt;/a&gt;zustan</summary>
      
    
    
    
    <category term="Language" scheme="https://blog.rezedge.com/categories/Language/"/>
    
    <category term="Javascript" scheme="https://blog.rezedge.com/categories/Language/Javascript/"/>
    
    <category term="React" scheme="https://blog.rezedge.com/categories/Language/Javascript/React/"/>
    
    
  </entry>
  
  <entry>
    <title>求生之路2 崩溃解决办法 DXVK 替换，开启 vulkan API </title>
    <link href="https://blog.rezedge.com/posts/3b2bff5d/"/>
    <id>https://blog.rezedge.com/posts/3b2bff5d/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.173Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>原文地址 <a href="https://steamcommunity.com/workshop/filedetails/?l=tchinese&id=2987081908">steamcommunity.com</a></p></blockquote><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>吾辈的启动项：-vulkan -novid -console +m_rawinput 1 -heapsize 6000000 -processheap -high -num_edicts 4096</p><p>然后，<strong>一定</strong>要替换<code>dxvk_d3d9.dll</code>，详细办法见<a href="#%E4%BD%BF%E7%94%A8-dxvk-%E4%BD%BF-vulkan-api-%E6%95%88%E7%8E%87%E6%9B%B4%E9%AB%98">使用 DXVK 使 Vulkan API 效率更高</a>，启动项一定要加<code>-vulkan</code></p><h1 id="原文"><a href="#原文" class="headerlink" title="原文"></a>原文</h1><p>本收藏為個人自用的遊戲優化方法、指令、管理模組之用途。</p><p>我需要紀錄我是如何「自定義」遊戲內容，並做個資訊彙總，也助於有看見此收藏的玩家們（不保證 100% 對大家有效）。</p><h2 id="啟動選項（Launch-Options）"><a href="#啟動選項（Launch-Options）" class="headerlink" title="啟動選項（Launch Options）"></a>啟動選項（Launch Options）</h2><h3 id="版本一"><a href="#版本一" class="headerlink" title="版本一"></a>版本一</h3><p>-vulkan -autoconfig -lv -heapsize 6000000 -novid -processheap -high -num_edicts 4096 </p><p>-heapsize 调动内存<br>-novid 自动跳过开头动画<br>-lv 低血腥模式，千万不要开清理尸体<br>-autoconfig 解决核显玩家游戏黑的问题<br>-num_edicts 给求生最大内存缓存 -heapsize不能大于-num_edicts（不然会加载进不去地图,换算单位，600万&#x3D;4096）<br>-processheap：这个指令要求游戏使用指定的堆进行内存分配<br>high：将游戏的进程优先级设置为“高”，给予CPU最高优先级</p><h3 id="版本二"><a href="#版本二" class="headerlink" title="版本二"></a>版本二</h3><p>我個人使用的：</p><p>-novid -console +m_rawinput 1 +cl_crosshair_alpha 0</p><p>啟動選項個別說明：</p><ul><li>-novid：跳過遊戲片頭動畫。99% 的玩家必定要輸入的指令之一，節省你的時間。</li><li>-console：啟動時自動開啟控制台。只是為了方便看控制台，非必要參數。</li><li>+m_rawinput 1：啟用 Raw Input，讓遊戲直接讀滑鼠輸入，降低受 Windows 指標加速 &#x2F; 敏感度干擾的機率。</li><li>+cl_crosshair_alpha 0：關閉遊戲內準心，用於 Addons 的自定義準心。</li><li>-insecure：進入不安全模式。有修改遊戲的腳本 Addons，這是必要指令，因為你需要讓腳本 Addons「正常執行」，這對於開啟「本地伺服器」的主機玩家來說有幫助。（注意，這將會無法連接 Valve 官方伺服器）。</li><li>-vulkan：使用 Vulkan API 渲染遊戲。助於降低 CPU 使用率，也『可能』降低 RAM 使用率，一般來說這是給 Mac 和 Linux 系統使用的 API，有人實測 Vulkan API 在 Windows 系統下有「優化」的感覺，非必要選項，可嘗試。<br>DirectX9 vs Vulkan(DXVK 2.6.1)：<br><a href="https://www.youtube.com/watch?v=tRX-GR0hhvk">https://www.youtube.com/watch?v=tRX-GR0hhvk</a></li></ul><p>縮短遊戲載入時間</p><p>訂閱的 Addons 下載完成後，都放入 Addons 資料夾，並取消訂閱</p><p>實際做法是：</p><ol><li><p>訂閱一個 Addons 後進入遊戲。  </p></li><li><p>遊戲自動下載該 Addons，下載完畢後關閉遊戲。  </p></li><li><p>進入到「left4dead2」資料夾的「addons」。  </p></li><li><p>將「workshop」資料夾內的所有檔案複製到上一層「addons」資料夾，並取消訂閱所有 Addons。  </p></li><li><p>重啟遊戲發現不再檢查 Addons 更新，這使遊戲啟動速度更快。</p></li></ol><p>為何每次開遊戲都在等 Addons 載入？原因就是 L4D2 會自動檢查訂閱 Addons 是否需要更新，而訂閱越多 Addons 載入越久。其實不是每個 Addons 都需要一直更新。<br><a href="http://www.reddit.com/r/l4d2/comments/1392qc0/addons_on_startup_in_left_4_dead_2/#:~:text=addon%20folder%20and%20then%20unsubscribe">從此 Reddit 文章的回覆中習得到的方法。</a></p><p>終極 CFG 最佳設置</p><p><a href="http://github.com/theletterjwithadot/Ultimate-Config-for-L4D2">The Ultimate Left 4 Dead 2 Config (autoexec) by J.</a> [github.com]，是由 J 為 L4D2 修改的 CFG 配置檔，這是他花大量心血與時間研究出的終極方案。</p><h2 id="使用-DXVK-使-Vulkan-API-效率更高"><a href="#使用-DXVK-使-Vulkan-API-效率更高" class="headerlink" title="使用 DXVK 使 Vulkan API 效率更高"></a>使用 DXVK 使 Vulkan API 效率更高</h2><p>Vulkan API 透過 <a href="http://github.com/doitsujin/dxvk/releases">DXVK</a> [github.com] 使轉換效率越來越高，效能可能比 DirectX API 還要高。</p><p>安裝方法：</p><ol><li><p>下載最新版本的 <a href="http://github.com/doitsujin/dxvk/releases">DXVK</a> [github.com] tar.gz 壓縮檔。  </p></li><li><p>進到 tar.gz 壓縮檔內，路徑：「drvk - 版本號」資料夾 → 「x32」資料夾 → 複製「d3d9.dll」檔案  </p></li><li><p>打開「Left 4 Dead 2」資料夾 → 「bin」資料夾 → 先備份「dxvk_d3d9.dll」檔案 → 再用「d3d9.dll」去取代原始「dxvk_d3d9.dll」，記得檔案命名為「dxvk_d3d9.dll」。  </p></li><li><p>L4D2 啟動選項一定要添加<code>-vulkan</code></p></li></ol><p>測試方法：</p><p>非常簡單，打開遊戲後設定視窗化，並查看視窗名稱是否有「-vulkan」字樣，有就是成功了。</p><p>！免責聲明！</p><p>任何修改遊戲之行為導致帳戶被 Ben，由當事人自行承擔。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;原文地址 &lt;a href=&quot;https://steamcommunity.com/workshop/filedetails/?l=tchinese&amp;id=2987081908&quot;&gt;steamcommunity.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockq</summary>
      
    
    
    
    <category term="Life" scheme="https://blog.rezedge.com/categories/Life/"/>
    
    <category term="Game" scheme="https://blog.rezedge.com/categories/Life/Game/"/>
    
    <category term="Left4Dead2" scheme="https://blog.rezedge.com/categories/Life/Game/Left4Dead2/"/>
    
    
  </entry>
  
  <entry>
    <title>prsima monorepo 下多版本冲突</title>
    <link href="https://blog.rezedge.com/posts/ef274df5/"/>
    <id>https://blog.rezedge.com/posts/ef274df5/</id>
    <published>2026-08-17T13:15:15.000Z</published>
    <updated>2026-08-17T06:09:03.171Z</updated>
    
    <content type="html"><![CDATA[<h1 id="prsima-monorepo-下多版本冲突"><a href="#prsima-monorepo-下多版本冲突" class="headerlink" title="prsima monorepo 下多版本冲突"></a>prsima monorepo 下多版本冲突</h1><p>今天吾辈遇到了这个错误，<code>TypeError: undefined is not an object (evaluating &#39;t.graph&#39;)</code>，完整报错在底下，属实看不出任何猫腻，完完全全卡住了。</p><p>之后想到很多问题啊，比如，两个schema会不会导致冲突啊，然而在重新<code>bun install</code>，也解决不了问题的情况下思路卡住了，不过想到了bun.lock没删，再加上版本的确不匹配，</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">YOUR_WORKSPACE_DIR\package\auth $ bunx prisma --version  </span><br><span class="line">Loaded Prisma config from prisma.config.ts.</span><br><span class="line"></span><br><span class="line">Prisma schema loaded from prisma\schema.prisma.</span><br><span class="line">prisma               : 7.3.0</span><br><span class="line">@prisma/client       : 7.4.2</span><br><span class="line">Operating System     : win32</span><br><span class="line">Architecture         : x64</span><br><span class="line">Node.js              : v25.6.0</span><br><span class="line">TypeScript           : 5.9.2</span><br><span class="line">Query Compiler       : enabled</span><br><span class="line">PSL                  : @prisma/prisma-schema-wasm 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919</span><br><span class="line">Schema Engine        : schema-engine-cli 94a226be1cf2967af2541cca5529f0f7ba866919 (at ..\..\node_modules\.bun\@prisma+engines@7.4.2\node_modules\@prisma\engines\schema-engine-windows.exe)</span><br><span class="line">Default Engines Hash : 94a226be1cf2967af2541cca5529f0f7ba866919</span><br><span class="line">Studio               : 0.13.1</span><br></pre></td></tr></table></figure><p>我也不能确定，但是当时大概就是这个输出。</p><p>所幸更新了一下版本，最后确定了问题，得到的教训就是prisma一定要锁定版本，最好不要写”^7.4.2”，直接写”7.4.2”，不过吾辈目前还是写了^就是了，只不过因为有两个数据库，所以更新的话需要改8个地方（每个包四个），不知道怎么解决会比较好呢？</p><h2 id="完整报错"><a href="#完整报错" class="headerlink" title="完整报错"></a>完整报错</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">6 | `)&#125;&#125;;var Vu=&#123;red:be,gray:lt,dim:it,bold:G,underline:ot,highlightSource:e=&gt;e.highlight()&#125;,qu=&#123;red:e=&gt;e,gray:e=&gt;e,dim:e=&gt;e,bold:e=&gt;e,underline:e=&gt;e,highlightSource:e=&gt;e&#125;;function ju(&#123;message:e,originalMethod:t,isPanic:r,callArguments:n&#125;)&#123;return&#123;functionName:`prisma.$&#123;t&#125;()`,message:e,isPanic:r??!1,callArguments:n&#125;&#125;function Uu(&#123;callsite:e,message:t,originalMethod:r,isPanic:n,callArguments:i&#125;,o)&#123;let s=ju(&#123;message:t,originalMethod:r,isPanic:n,callArguments:i&#125;);if(!e||typeof window&lt;&quot;u&quot;||process.env.NODE_ENV===&quot;production&quot;)return s;let a=e.getLocation();if(!a||!a.lineNumber||!a.columnNumber)return s;let l=Math.max(1,a.lineNumber-3),u=Xt.read(a.fileName)?.slice(l,a.lineNumber),c=u?.lineAt(a.lineNumber);if(u&amp;&amp;c)&#123;let p=Qu(c),d=Bu(c);if(!d)return s;s.functionName=`$&#123;d.code&#125;)`,s.location=a,n||(u=u.mapLineAt(a.lineNumber,h=&gt;h.slice(0,d.openingBraceIndex))),u=o.highlightSource(u);let f=String(u.lastLineNumber).length;if(s.contextLines=u.mapLines((h,x)=&gt;o.gray(String(x).padStart(f))+&quot; &quot;+h).mapLines(h=&gt;o.dim(h)).prependSymbol | ... truncated </span><br><span class="line"> 7 | `)&#125;function Hu(e)&#123;let t=[e.fileName];return e.lineNumber&amp;&amp;t.push(String(e.lineNumber)),e.columnNumber&amp;&amp;t.push(String(e.columnNumber)),t.join(&quot;:&quot;)&#125;function er(e)&#123;let t=e.showColors?Vu:qu,r;return r=Uu(e,t),Ju(r,t)&#125;var so=U(cn());function to(e,t,r)&#123;let n=ro(e),i=Gu(n),o=Wu(i);o?tr(o,t,r):t.addErrorMessage(()=&gt;&quot;Unknown error&quot;)&#125;function ro(e)&#123;return e.errors.flatMap(t=&gt;t.kind===&quot;Union&quot;?ro(t):[t])&#125;function Gu(e)&#123;let t=new Map,r=[];for(let n of e)&#123;if(n.kind!==&quot;InvalidArgumentType&quot;)&#123;r.push(n);continue&#125;let i=`$&#123;n.selectionPath.join(&quot;.&quot;)&#125;:$&#123;n.argumentPath.join(&quot;.&quot;)&#125;`,o=t.get(i);o?t.set(i,&#123;...n,argument:&#123;...n.argument,typeNames:zu(o.argument.typeNames,n.argument.typeNames)&#125;&#125;):t.set(i,n)&#125;return r.push(...t.values()),r&#125;function zu(e,t)&#123;return[...new Set(e.concat(t))]&#125;function Wu(e)&#123;return ln(e,(t,r)=&gt;&#123;let n=Xi(t),i=Xi(r);return n!==i?n-i:eo(t)-eo(r)&#125;)&#125;function Xi(e)&#123;let t=0;return Array.isArray(e.selectionPath)&amp;&amp;(t+=e.selectionPath.length),Array.isArray(e.argumentPath)&amp;&amp;(t+=e.argumentPath.length),t&#125;function eo(e)&#123;switch( | ... truncated </span><br><span class="line"> 8 | `)&#125;getCurrentLineLength()&#123;return this.currentLine.length&#125;indentedCurrentLine()&#123;let t=this.currentLine.padStart(this.currentLine.length+2*this.currentIndent);return this.marginSymbol?this.marginSymbol+t.slice(1):t&#125;&#125;;no();var rr=class&#123;constructor(t)&#123;this.value=t&#125;write(t)&#123;t.write(this.value)&#125;markAsError()&#123;this.value.markAsError()&#125;&#125;;var nr=e=&gt;e,ir=&#123;bold:nr,red:nr,green:nr,dim:nr,enabled:!1&#125;,oo=&#123;bold:G,red:be,green:st,dim:it,enabled:!0&#125;,Le=&#123;write(e)&#123;e.writeLine(&quot;,&quot;)&#125;&#125;;var Y=class&#123;constructor(t)&#123;this.contents=t&#125;isUnderlined=!1;color=t=&gt;t;underline()&#123;return this.isUnderlined=!0,this&#125;setColor(t)&#123;return this.color=t,this&#125;write(t)&#123;let r=t.getCurrentLineLength();t.write(this.color(this.contents)),this.isUnderlined&amp;&amp;t.afterNextNewline(()=&gt;&#123;t.write(&quot; &quot;.repeat(r)).writeLine(this.color(&quot;~&quot;.repeat(this.contents.length)))&#125;)&#125;&#125;;var pe=class&#123;hasError=!1;markAsError()&#123;return this.hasError=!0,this&#125;&#125;;var $e=class extends pe&#123;items=[];addItem(t)&#123;return this.items.push(new rr(t)),this&#125;getField(t)&#123;return this.items[t]&#125;getPrintWidth()&#123;r | ... truncated </span><br><span class="line"> 9 | Note that $&#123;s.bold(&quot;include&quot;)&#125; statements only accept relation fields.`,a&#125;)&#125;function Yu(e,t,r)&#123;let n=t.arguments.getDeepSubSelectionValue(e.selectionPath)?.asObject();if(n)&#123;let i=n.getField(&quot;omit&quot;)?.value.asObject();if(i)&#123;Xu(e,t,i);return&#125;if(n.hasField(&quot;select&quot;))&#123;ec(e,t);return&#125;&#125;if(r?.[ce(e.outputType.name)])&#123;tc(e,t);return&#125;t.addErrorMessage(()=&gt;`Unknown field at &quot;$&#123;e.selectionPath.join(&quot;.&quot;)&#125; selection&quot;`)&#125;function Xu(e,t,r)&#123;r.removeAllFields();for(let n of e.outputType.fields)r.addSuggestion(new q(n.name,&quot;false&quot;));t.addErrorMessage(n=&gt;`The $&#123;n.red(&quot;omit&quot;)&#125; statement includes every field of the model $&#123;n.bold(e.outputType.name)&#125;. At least one field must be included in the result`)&#125;function ec(e,t)&#123;let r=e.outputType,n=t.arguments.getDeepSelectionParent(e.selectionPath)?.value,i=n?.isEmpty()??!1;n&amp;&amp;(n.removeAllFields(),uo(n,r)),t.addErrorMessage(o=&gt;i?`The $&#123;o.red(&quot;`select`&quot;)&#125; statement for type $&#123;o.bold(r.name)&#125; must not be empty. $&#123;ht(o)&#125;`:`The $&#123;o.red(&quot;`select`&quot;)&#125; statement for type $&#123;o.bold(r.name)&#125; needs $&#123; | ... truncated </span><br><span class="line">10 | `)&#125;&#125;;function Ue(e)&#123;return new dn(go(e))&#125;function go(e)&#123;let t=new Ve;for(let[r,n]of Object.entries(e))&#123;let i=new sr(r,yo(n));t.addField(i)&#125;return t&#125;function yo(e)&#123;if(typeof e==&quot;string&quot;)return new k(JSON.stringify(e));if(typeof e==&quot;number&quot;||typeof e==&quot;boolean&quot;)return new k(String(e));if(typeof e==&quot;bigint&quot;)return new k(`$&#123;e&#125;n`);if(e===null)return new k(&quot;null&quot;);if(e===void 0)return new k(&quot;undefined&quot;);if(Fe(e))return new k(`new Prisma.Decimal(&quot;$&#123;e.toFixed()&#125;&quot;)`);if(e instanceof Uint8Array)return Buffer.isBuffer(e)?new k(`Buffer.alloc($&#123;e.byteLength&#125;)`):new k(`new Uint8Array($&#123;e.byteLength&#125;)`);if(e instanceof Date)&#123;let t=Zt(e)?e.toISOString():&quot;Invalid Date&quot;;return new k(`new Date(&quot;$&#123;t&#125;&quot;)`)&#125;return e instanceof fo.ObjectEnumValue?new k(`Prisma.$&#123;e._getName()&#125;`):je(e)?new k(`prisma.$&#123;ce(e.modelName)&#125;.$fields.$&#123;e.name&#125;`):Array.isArray(e)?hc(e):typeof e==&quot;object&quot;?go(e):new k(Object.prototype.toString.call(e))&#125;function hc(e)&#123;let t=new $e;for(let r of e)t.addItem(yo(r));return t&#125;function ar(e,t)&#123;let r=t===&quot;pretty&quot;?oo:ir, | ... truncated </span><br><span class="line">11 | `);return t.reduce(function(r,n)&#123;var i=Dc(n)||Mc(n)||$c(n)||Uc(n)||qc(n);return i&amp;&amp;r.push(i),r&#125;,[])&#125;var Oc=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|rsc|&lt;anonymous&gt;|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,Nc=/\((\S*)(?::(\d+))(?::(\d+))\)/;function Dc(e)&#123;var t=Oc.exec(e);if(!t)return null;var r=t[2]&amp;&amp;t[2].indexOf(&quot;native&quot;)===0,n=t[2]&amp;&amp;t[2].indexOf(&quot;eval&quot;)===0,i=Nc.exec(t[2]);return n&amp;&amp;i!=null&amp;&amp;(t[2]=i[1],t[3]=i[2],t[4]=i[3]),&#123;file:r?null:t[2],methodName:t[1]||Tt,arguments:r?[t[2]]:[],lineNumber:t[3]?+t[3]:null,column:t[4]?+t[4]:null&#125;&#125;var Fc=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|rsc|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;function Mc(e)&#123;var t=Fc.exec(e);return t?&#123;file:t[2],methodName:t[1]||Tt,arguments:[],lineNumber:+t[3],column:t[4]?+t[4]:null&#125;:null&#125;var _c=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|rsc|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,Lc=/(\S+) line (\d+)(?: &gt; eval line \d+)* &gt; | ... truncated </span><br><span class="line"></span><br><span class="line">TypeError: undefined is not an object (evaluating &#x27;t.graph&#x27;)</span><br><span class="line"> clientVersion: &quot;7.3.0&quot;,</span><br><span class="line"></span><br><span class="line">      at new ii (YOUR_WORKSPACE_DIR\node_modules\@prisma\client\runtime\client.js:11:56375)</span><br><span class="line">      at Fa (YOUR_WORKSPACE_DIR\node_modules\@prisma\client\runtime\client.js:11:56244)</span><br><span class="line">      at deserialize (YOUR_WORKSPACE_DIR\node_modules\@prisma\client\runtime\client.js:11:57817)</span><br><span class="line">      at new jt (YOUR_WORKSPACE_DIR\node_modules\@prisma\client\runtime\client.js:57:17465)</span><br><span class="line">      at ml (YOUR_WORKSPACE_DIR\node_modules\@prisma\client\runtime\client.js:58:6195)</span><br><span class="line">      at new t (YOUR_WORKSPACE_DIR\node_modules\@prisma\client\runtime\client.js:75:71)</span><br><span class="line">      at YOUR_WORKSPACE_DIR\package\server\prisma\client.ts:28:23</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;prsima-monorepo-下多版本冲突&quot;&gt;&lt;a href=&quot;#prsima-monorepo-下多版本冲突&quot; class=&quot;headerlink&quot; title=&quot;prsima monorepo 下多版本冲突&quot;&gt;&lt;/a&gt;prsima monorepo 下多版本</summary>
      
    
    
    
    <category term="Language" scheme="https://blog.rezedge.com/categories/Language/"/>
    
    <category term="Javascript" scheme="https://blog.rezedge.com/categories/Language/Javascript/"/>
    
    <category term="Library" scheme="https://blog.rezedge.com/categories/Language/Javascript/Library/"/>
    
    <category term="Prisma" scheme="https://blog.rezedge.com/categories/Language/Javascript/Library/Prisma/"/>
    
    
  </entry>
  
  <entry>
    <title>README</title>
    <link href="https://blog.rezedge.com/posts/31a40024/"/>
    <id>https://blog.rezedge.com/posts/31a40024/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.163Z</updated>
    
    
    
    
    <category term="AI" scheme="https://blog.rezedge.com/categories/AI/"/>
    
    
  </entry>
  
  <entry>
    <title>主题设计Prompt参考</title>
    <link href="https://blog.rezedge.com/posts/de233666/"/>
    <id>https://blog.rezedge.com/posts/de233666/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.163Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://www.designprompts.dev/">https://www.designprompts.dev/</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://www.designprompts.dev/&quot;&gt;https://www.designprompts.dev/&lt;/a&gt;&lt;/p&gt;
</summary>
      
    
    
    
    <category term="AI" scheme="https://blog.rezedge.com/categories/AI/"/>
    
    <category term="design" scheme="https://blog.rezedge.com/categories/AI/design/"/>
    
    
  </entry>
  
  <entry>
    <title>为什么 AI 生成的页面总是紫色？以及如何“去 AI 味”</title>
    <link href="https://blog.rezedge.com/posts/8e5928e7/"/>
    <id>https://blog.rezedge.com/posts/8e5928e7/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.163Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>generate by chatGPT</p></blockquote><h1 id="为什么-AI-生成的页面总是紫色？以及如何“去-AI-味”"><a href="#为什么-AI-生成的页面总是紫色？以及如何“去-AI-味”" class="headerlink" title="为什么 AI 生成的页面总是紫色？以及如何“去 AI 味”"></a>为什么 AI 生成的页面总是紫色？以及如何“去 AI 味”</h1><p>最近刷到一个有趣的梗：Tailwind 创始人调侃地为当年把 <code>bg-indigo-500</code> 设成默认按钮色道歉——因为现在几乎所有 AI 生成的 UI 都是那种“熟悉的紫色”。你是不是也有同样的感觉？一眼 AI，大片紫、渐变卡片、圆角阴影三件套。</p><p>这不是错觉，这是模式收敛。</p><p>当你用类似这样的提示词：</p><blockquote><p>站在产品经理和设计师的角度，使用 HTML 设计一个番茄工作法 iOS 应用原型图……</p></blockquote><p>AI 会优先选择它训练数据中“最常见、最安全、最不出错”的组合：Tailwind + 紫色主色 + 柔和渐变 + 大圆角 + 轻阴影。因为这是当前主流开源组件库和 SaaS 产品的审美均值。</p><p>如果你不指定风格，它就会回到“统计平均值”。这就是紫色泛滥的根本原因。</p><hr><h2 id="一、为什么-AI-会收敛到紫色？"><a href="#一、为什么-AI-会收敛到紫色？" class="headerlink" title="一、为什么 AI 会收敛到紫色？"></a>一、为什么 AI 会收敛到紫色？</h2><p>原因可以拆成三个层面。</p><p>第一，训练数据分布。<br>Tailwind、Shadcn、Radix、各类 SaaS 模板大量使用 Indigo &#x2F; Violet 系主色。模型学习到的“现代 UI”≈“紫色卡片 + 柔和渐变”。</p><p>第二，风险最小化。<br>紫色既不像红色那么激进，也不像绿色那样有语义歧义（成功&#x2F;错误），是一个“中性偏科技感”的安全选择。</p><p>第三，提示词太宽泛。<br>“现代化”“精美”“完整”“可直接实现”这些词没有具体约束，模型只能调用默认范式。</p><p>本质不是 AI 审美差，而是你没有给它风格边界。</p><hr><h2 id="二、如何让-AI-不再生成“紫色默认模板”"><a href="#二、如何让-AI-不再生成“紫色默认模板”" class="headerlink" title="二、如何让 AI 不再生成“紫色默认模板”"></a>二、如何让 AI 不再生成“紫色默认模板”</h2><p>核心思路：<strong>把抽象词换成可执行设计约束</strong>。</p><p>不要说“现代化”，要说：</p><ul><li>主色：#0F172A 深灰蓝</li><li>辅助色：#22C55E 番茄计时状态绿色</li><li>强调色：#F97316 橙色</li><li>禁止使用紫色系</li></ul><p>不要说“iOS 风格”，要说：</p><ul><li>使用 iOS 17 Human Interface Guidelines 风格</li><li>采用大标题 + 分组卡片</li><li>模糊背景 + 半透明材质</li><li>使用 SF Pro 字体（或等价替代）</li></ul><p>不要说“精美完整”，要说：</p><ul><li><p>必须包含以下状态：</p><ul><li>未开始</li><li>计时中</li><li>暂停</li><li>结束统计页</li></ul></li><li><p>明确列出组件结构</p></li></ul><p>示例改写提示词：</p><blockquote><p>使用原生 HTML + CSS（不依赖 Tailwind CDN），设计一个番茄工作法 iOS 风格应用原型。<br>主色为 #22C55E，禁止使用紫色系。<br>采用玻璃拟态（glassmorphism）设计，圆角 16px，阴影为柔和扩散阴影。<br>字体使用本地 Inter 或 SF Pro 替代。<br>页面需包含：计时首页、计时中状态、暂停弹窗、统计页。<br>所有组件需可直接供 Vue 3 项目拆分实现。</p></blockquote><p>当你给出明确的视觉约束，AI 的输出会明显提升。</p><hr><h2 id="三、进阶玩法：定义“设计技能（Skill）”"><a href="#三、进阶玩法：定义“设计技能（Skill）”" class="headerlink" title="三、进阶玩法：定义“设计技能（Skill）”"></a>三、进阶玩法：定义“设计技能（Skill）”</h2><p>与其每次重写提示词，不如抽象成一套“设计规范模板”。</p><p>你可以建立一个本地 prompt 模板，例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Design System:</span><br><span class="line">- Style: Minimal + iOS native</span><br><span class="line">- Radius: 12px</span><br><span class="line">- Spacing scale: 4px system</span><br><span class="line">- Typography: 16px base, 1.5 line-height</span><br><span class="line">- Primary color: #0EA5E9</span><br><span class="line">- No purple</span><br><span class="line">- No Tailwind CDN</span><br><span class="line">- Use semantic class naming</span><br></pre></td></tr></table></figure><p>以后所有 UI 生成都附带这段规范。</p><p>这本质上是“定义 Agent Skill”，而不是每次临时对话。</p><hr><h2 id="四、如何“二开”AI-生成的项目"><a href="#四、如何“二开”AI-生成的项目" class="headerlink" title="四、如何“二开”AI 生成的项目"></a>四、如何“二开”AI 生成的项目</h2><p>如果已经生成了一个“紫色 Tailwind 模板”，怎么改？</p><p>建议按下面步骤做：</p><h3 id="1-去框架化（可选）"><a href="#1-去框架化（可选）" class="headerlink" title="1. 去框架化（可选）"></a>1. 去框架化（可选）</h3><p>如果你希望长期维护：</p><ul><li>去掉 CDN</li><li>把 Tailwind 样式提取为变量</li><li>或重写为 SCSS &#x2F; CSS Modules</li></ul><h3 id="2-抽离-Design-Token"><a href="#2-抽离-Design-Token" class="headerlink" title="2. 抽离 Design Token"></a>2. 抽离 Design Token</h3><p>建立：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-pseudo">:root</span> &#123;</span><br><span class="line">  <span class="attr">--color-primary</span>: <span class="number">#22C55E</span>;</span><br><span class="line">  <span class="attr">--color-bg</span>: <span class="number">#F8FAFC</span>;</span><br><span class="line">  <span class="attr">--radius-base</span>: <span class="number">12px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>替换所有硬编码的 <code>bg-indigo-500</code>。</p><h3 id="3-组件化重构（Vue）"><a href="#3-组件化重构（Vue）" class="headerlink" title="3. 组件化重构（Vue）"></a>3. 组件化重构（Vue）</h3><p>拆分结构：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/components</span><br><span class="line">  TimerDisplay.vue</span><br><span class="line">  ControlButtons.vue</span><br><span class="line">  StatsCard.vue</span><br><span class="line">  PauseDialog.vue</span><br></pre></td></tr></table></figure><p>把原始 HTML 拆成 Vue 组件。</p><h3 id="4-建立状态机"><a href="#4-建立状态机" class="headerlink" title="4. 建立状态机"></a>4. 建立状态机</h3><p>番茄钟不是静态页面，它是状态驱动：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">idle -&gt; running -&gt; paused -&gt; finished</span><br></pre></td></tr></table></figure><p>用 Vue <code>ref</code> 或 <code>pinia</code> 建立状态流，而不是靠 DOM 切换。</p><hr><h2 id="五、真正去-AI-味的方法"><a href="#五、真正去-AI-味的方法" class="headerlink" title="五、真正去 AI 味的方法"></a>五、真正去 AI 味的方法</h2><p>“去 AI 味”不是换颜色，而是增加“选择”。</p><p>AI 模板最大的问题是：</p><ul><li>所有按钮一样</li><li>所有卡片一样</li><li>所有阴影一样</li></ul><p>真实设计不会这么均匀。</p><p>你可以：</p><ul><li>给主 CTA 更强对比</li><li>给统计页用不同布局结构</li><li>刻意打破 8px 统一圆角</li><li>控制留白，而不是平均分布</li></ul><p>设计的灵魂在于“节奏差异”，而不是整齐。</p><hr><h2 id="六、总结"><a href="#六、总结" class="headerlink" title="六、总结"></a>六、总结</h2><p>AI 生成紫色页面不是 bug，而是统计平均。</p><p>当提示词过于抽象时，模型会回到默认模板。<br>想要真正定制化 UI，你必须给出：</p><ul><li>明确色彩体系</li><li>明确设计风格</li><li>明确状态结构</li><li>明确技术栈限制</li></ul><p>从“让 AI 设计”转变为“让 AI 按规范实现设计”。</p><p>这样生成的页面，才会真正变成你的作品，而不是一眼 AI。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;generate by chatGPT&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;为什么-AI-生成的页面总是紫色？以及如何“去-AI-味”&quot;&gt;&lt;a href=&quot;#为什么-AI-生成的页面总是紫色？以及如何“去-AI-味”&quot; class=</summary>
      
    
    
    
    <category term="AI" scheme="https://blog.rezedge.com/categories/AI/"/>
    
    <category term="design" scheme="https://blog.rezedge.com/categories/AI/design/"/>
    
    
  </entry>
  
  <entry>
    <title>reprint-解决神舟 T8 Pro E64 无法开启安全启动的问题 - Moe Blog</title>
    <link href="https://blog.rezedge.com/posts/bf7f45c9/"/>
    <id>https://blog.rezedge.com/posts/bf7f45c9/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.166Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>原文地址 <a href="https://blog.1loli.link/archives/105/">blog.1loli.link</a></p></blockquote><h3 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h3><p>我在神舟 T8 Pro E64 (616QY) 笔记本上尝试开启安全启动 (Secure Boot) 时，BIOS 提示当前处于 “Setup Mode”，需要切换到”User Mode” 才能成功开启。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/1378833192.png"><br>经过大量尝试和查阅资料，发现此型号笔记本由广达代工，其 BIOS 隐藏了大量高级选项，包括关键的密钥管理 (Key Management) 设置页面，导致无法通过常规方法解决。</p><p>本文记录了解决此问题的完整过程。</p><h3 id="教程"><a href="#教程" class="headerlink" title="教程"></a>教程</h3><p>核心思路是通过修改 BIOS，将隐藏的 “Key Management” 菜单显示出来，然后手动注册安全启动所需的密钥文件。</p><h4 id="第一步：提取并修改-BIOS"><a href="#第一步：提取并修改-BIOS" class="headerlink" title="第一步：提取并修改 BIOS"></a>第一步：提取并修改 BIOS</h4><ol><li><p><strong>提取 BIOS 文件</strong></p><ul><li>对于 Intel 芯片组的主板，可以使用官方 CSME System Tools 包中的 Flash Programming Tool (FPT) 来提取和刷入 BIOS。</li><li><strong>注意</strong>：刷入前可能需要先禁用 BIOS 的写保护功能（如果 BIOS 支持该功能）。</li></ul></li><li><p><strong>编辑 BIOS 文件</strong></p><ul><li>使用 <a href="https://github.com/BoringBoredom/UEFI-Editor">UEFI-Editor</a> 工具打开提取出的 BIOS 文件。</li><li>根据该工具的教程，在 BIOS 设置中找到安全启动 (Secure Boot) 相关的菜单。</li><li>定位到被隐藏的 “Key Management” 项目（通常会被标记为 Suppressed），解除其隐藏状态。</li><li>保存修改后的 BIOS 文件。</li></ul></li><li><p><strong>刷入修改后的 BIOS</strong></p><ul><li>使用 Flash Programming Tool (FPT) 将修改后的 BIOS 文件刷回主板。</li></ul></li></ol><h4 id="第二步：准备安全启动密钥文件"><a href="#第二步：准备安全启动密钥文件" class="headerlink" title="第二步：准备安全启动密钥文件"></a>第二步：准备安全启动密钥文件</h4><ol><li><p><strong>下载密钥文件</strong></p><ul><li>访问微软在 GitHub 上的官方仓库：<a href="https://github.com/microsoft/secureboot_objects/releases">secureboot_objects</a>。</li><li>下载最新版本的 <code>dbx</code>, <code>db</code>, <code>KEK</code>, <code>PK</code> 文件。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/1503472119.jpg"></li></ul></li><li><p><strong>准备存储介质</strong></p><ul><li>将下载的所有密钥文件解压，并存放至一个 FAT32 格式的 U 盘根目录。</li></ul></li></ol><h4 id="第三步：手动导入密钥并配置启动项"><a href="#第三步：手动导入密钥并配置启动项" class="headerlink" title="第三步：手动导入密钥并配置启动项"></a>第三步：手动导入密钥并配置启动项</h4><ol><li><p><strong>进入 BIOS 设置</strong></p><ul><li>重启电脑，进入 BIOS 设置界面。此时，你应该可以在安全启动菜单下看到之前被隐藏的 “Key Management” 选项。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/2465528013.png"></li></ul></li><li><p><strong>检查密钥状态</strong></p><ul><li>进入 “Key Management” 页面，检查 <code>PK</code>, <code>KEK</code>, <code>db</code>, <code>dbx</code> 的状态。在我的情况中，这些项目初始大小均为 0KB，且尝试恢复出厂默认密钥 (Restore Default PK) 会提示失败。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/3617543902.png"></li></ul></li><li><p><strong>手动导入密钥</strong></p><ul><li>依次选择 <code>PK</code>, <code>KEK</code>, <code>db</code>, <code>dbx</code> 选项，并从之前准备好的 U 盘中手动导入对应的文件。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/4247723101.png"></li></ul></li><li><p><strong>注册 Windows 启动文件</strong></p><ul><li><p>在 “Key Management” 页面中，找到并选择 “Enroll Efi Image” 选项。</p></li><li><p>浏览到你的 Windows 启动分区 (ESP 分区)。</p></li><li><p>选择 Windows 的启动文件，路径通常为 <code>/EFI/Microsoft/Boot/bootmgfw.efi</code>，并确认导入。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/288453274.jpg"></p><h4 id="第四步：开启并验证安全启动"><a href="#第四步：开启并验证安全启动" class="headerlink" title="第四步：开启并验证安全启动"></a>第四步：开启并验证安全启动</h4></li></ul></li><li><p><strong>开启安全启动</strong></p><ul><li>完成上述所有操作后，返回上一级菜单，尝试开启安全启动 (Secure Boot)。此时应该可以被正常设置为 “Enabled”。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/559349980.jpg"></li></ul></li><li><p><strong>保存并退出</strong></p><ul><li>按 <code>F10</code> 保存更改并重启电脑。</li></ul></li><li><p><strong>验证结果</strong></p><ul><li>进入 Windows 系统后，打开 “Windows 安全中心” 或运行 <code>msinfo32</code> (系统信息)，可以查看到安全启动状态是否已成功开启。</li></ul></li></ol><p><strong>注意</strong>：如果在启动过程中遇到红色的提示框，显示 “Verification failed” 或类似的验证失败信息，这通常意味着启动文件验证不通过。你需要重新执行第三步的第 4 点，确保导入了正确的 <code>bootmgfw.efi</code> 文件。<br><img src="https://blog.1loli.link/usr/uploads/2025/07/59466183.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;原文地址 &lt;a href=&quot;https://blog.1loli.link/archives/105/&quot;&gt;blog.1loli.link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; cla</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="System" scheme="https://blog.rezedge.com/categories/Environment/System/"/>
    
    
  </entry>
  
  <entry>
    <title>如何手动修改BIOS以升级微码</title>
    <link href="https://blog.rezedge.com/posts/15e7d1d4/"/>
    <id>https://blog.rezedge.com/posts/15e7d1d4/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.167Z</updated>
    
    <content type="html"><![CDATA[<h1 id="如何手动修改BIOS以升级微码"><a href="#如何手动修改BIOS以升级微码" class="headerlink" title="如何手动修改BIOS以升级微码"></a>如何手动修改BIOS以升级微码</h1><p>众所周知，机械革命不是一个好的电脑厂商。</p><p>所以虽然Intel 14900 系列一直有着问题，但是想要让他们去更新bios那是想都不要想的。</p><p>所以基本上得要自己想办法去更新微码。</p><p>二六年二月二十三日朋友告诉吾辈，微码是可以自己手动更新的，感恩。</p><h2 id="需要用到的-Tool"><a href="#需要用到的-Tool" class="headerlink" title="需要用到的 Tool"></a>需要用到的 Tool</h2><h3 id="Flash-Programming-Tool-FPT"><a href="#Flash-Programming-Tool-FPT" class="headerlink" title="Flash Programming Tool (FPT)"></a>Flash Programming Tool (FPT)</h3><p>对于Intel芯片组的主板，FPT 作为 CSME System Tools 包中的一部分，用来提取和刷入 BIOS。<br><strong>注意</strong>：刷入前可能需要先禁用 BIOS 的写保护功能（如果 BIOS 支持该功能）。</p><h3 id="MMTool"><a href="#MMTool" class="headerlink" title="MMTool"></a>MMTool</h3><p>American Megatrends Inc. 公司 Aptio 工具套件的一部分，所以自然是没有直接下载方案的</p><h4 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h4><h3 id="UEFI-Editor"><a href="#UEFI-Editor" class="headerlink" title="UEFI-Editor"></a>UEFI-Editor</h3><p>GitHub: <a href="https://github.com/BoringBoredom/UEFI-Editor">https://github.com/BoringBoredom/UEFI-Editor</a></p><h3 id=""><a href="#" class="headerlink" title=""></a></h3>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;如何手动修改BIOS以升级微码&quot;&gt;&lt;a href=&quot;#如何手动修改BIOS以升级微码&quot; class=&quot;headerlink&quot; title=&quot;如何手动修改BIOS以升级微码&quot;&gt;&lt;/a&gt;如何手动修改BIOS以升级微码&lt;/h1&gt;&lt;p&gt;众所周知，机械革命不是一个好的电脑厂</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="System" scheme="https://blog.rezedge.com/categories/Environment/System/"/>
    
    
  </entry>
  
  <entry>
    <title>安装</title>
    <link href="https://blog.rezedge.com/posts/11dcd65c/"/>
    <id>https://blog.rezedge.com/posts/11dcd65c/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.165Z</updated>
    
    <content type="html"><![CDATA[<p>你这个问题问得非常专业 👍——如果你已经在认真考虑依赖管理，那确实说明你不是只想“跑起来”，而是想把环境结构做干净、可控、可复现。</p><p>结论先说：<br><strong>是的，用 <code>uv</code> 会比传统 <code>pip + venv</code> 更好。</strong><br>尤其是在你这种 Windows + GPU + 需要长期维护模型环境的场景下。</p><p>下面我给你一个完整、工程级别的 <code>uv</code> 安装方案，而不是简单替换几条命令。</p><hr><h1 id="一、为什么用-uv-更好？"><a href="#一、为什么用-uv-更好？" class="headerlink" title="一、为什么用 uv 更好？"></a>一、为什么用 uv 更好？</h1><p><code>uv</code>（Astral 出品）本质是一个高性能的 Python 包管理器 + 虚拟环境工具，优势在于：</p><ul><li>🚀 速度远快于 pip</li><li>🔒 更可靠的依赖解析</li><li>📦 更好的 lock 管理</li><li>🧼 虚拟环境结构更干净</li><li>🧠 不污染全局 Python</li></ul><p>在 AI 项目（尤其是 PyTorch + CUDA 这种复杂依赖）里，环境污染是灾难。<br><code>uv</code> 可以显著降低这种风险。</p><hr><h1 id="二、使用-uv-安装-ComfyUI（Windows-原生方案）"><a href="#二、使用-uv-安装-ComfyUI（Windows-原生方案）" class="headerlink" title="二、使用 uv 安装 ComfyUI（Windows 原生方案）"></a>二、使用 uv 安装 ComfyUI（Windows 原生方案）</h1><h2 id="Step-1：安装-uv"><a href="#Step-1：安装-uv" class="headerlink" title="Step 1：安装 uv"></a>Step 1：安装 uv</h2><p>在 PowerShell 里执行：</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">powershell <span class="literal">-ExecutionPolicy</span> ByPass <span class="literal">-c</span> <span class="string">&quot;irm https://astral.sh/uv/install.ps1 | iex&quot;</span></span><br></pre></td></tr></table></figure><p>然后确认：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv --version</span><br></pre></td></tr></table></figure><hr><h2 id="Step-2：克隆-ComfyUI"><a href="#Step-2：克隆-ComfyUI" class="headerlink" title="Step 2：克隆 ComfyUI"></a>Step 2：克隆 ComfyUI</h2><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git clone https://github.com/comfyanonymous/ComfyUI.git C:\ComfyUI</span><br><span class="line"><span class="built_in">cd</span> C:\ComfyUI</span><br></pre></td></tr></table></figure><hr><h2 id="Step-3：用-uv-创建虚拟环境"><a href="#Step-3：用-uv-创建虚拟环境" class="headerlink" title="Step 3：用 uv 创建虚拟环境"></a>Step 3：用 uv 创建虚拟环境</h2><h3 id="推荐方式（指定-Python-3-10）"><a href="#推荐方式（指定-Python-3-10）" class="headerlink" title="推荐方式（指定 Python 3.10）"></a>推荐方式（指定 Python 3.10）</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv venv <span class="literal">--python</span> <span class="number">3.10</span></span><br></pre></td></tr></table></figure><p>这会在当前目录创建：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.venv/</span><br></pre></td></tr></table></figure><p>然后激活：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.venv\Scripts\activate</span><br></pre></td></tr></table></figure><hr><h2 id="Step-4：使用-uv-安装依赖（替代-pip）"><a href="#Step-4：使用-uv-安装依赖（替代-pip）" class="headerlink" title="Step 4：使用 uv 安装依赖（替代 pip）"></a>Step 4：使用 uv 安装依赖（替代 pip）</h2><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv pip install <span class="literal">-r</span> requirements.txt</span><br></pre></td></tr></table></figure><p>⚠️ 这里 uv 会调用它自己的 resolver，比 pip 更稳定。</p><hr><h1 id="三、关于-PyTorch-CUDA（重点）"><a href="#三、关于-PyTorch-CUDA（重点）" class="headerlink" title="三、关于 PyTorch + CUDA（重点）"></a>三、关于 PyTorch + CUDA（重点）</h1><p>ComfyUI 本质是依赖 PyTorch 的。</p><p>通常你需要：</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv pip install torch torchvision <span class="literal">--index-url</span> https://download.pytorch.org/whl/cu121</span><br></pre></td></tr></table></figure><p>⚠️ 这里的 <code>cu121</code> 要根据你的 CUDA 版本决定。</p><p>检查方式：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nvidia-smi</span><br></pre></td></tr></table></figure><p>如果是 RTX 40 系列，一般推荐 CUDA 12.x。</p><hr><h1 id="四、启动-ComfyUI"><a href="#四、启动-ComfyUI" class="headerlink" title="四、启动 ComfyUI"></a>四、启动 ComfyUI</h1><p>有两种方式：</p><h3 id="方式一（推荐）"><a href="#方式一（推荐）" class="headerlink" title="方式一（推荐）"></a>方式一（推荐）</h3><p>直接用 uv 运行：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv run python main.py</span><br></pre></td></tr></table></figure><h3 id="方式二"><a href="#方式二" class="headerlink" title="方式二"></a>方式二</h3><p>激活环境后：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python main.py</span><br></pre></td></tr></table></figure><p>浏览器打开：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://127.0.0.1:8188</span><br></pre></td></tr></table></figure><hr><h1 id="五、如果你想做“工程级”管理（进阶）"><a href="#五、如果你想做“工程级”管理（进阶）" class="headerlink" title="五、如果你想做“工程级”管理（进阶）"></a>五、如果你想做“工程级”管理（进阶）</h1><p>你可以进一步改成：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">uv init</span><br><span class="line">uv add -r requirements.txt</span><br><span class="line">uv lock</span><br></pre></td></tr></table></figure><p>这样会生成：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">uv.lock</span><br><span class="line">pyproject.toml</span><br></pre></td></tr></table></figure><p>以后环境是完全可复现的。</p><p>这对于长期维护 Stable Diffusion 节点非常重要。</p><hr><h1 id="六、推荐的最佳实践结构"><a href="#六、推荐的最佳实践结构" class="headerlink" title="六、推荐的最佳实践结构"></a>六、推荐的最佳实践结构</h1><p>我个人建议你这样组织：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">C:\AI\</span><br><span class="line">   ├── ComfyUI\</span><br><span class="line">   │     ├── .venv\</span><br><span class="line">   │     ├── models\</span><br><span class="line">   │     └── custom_nodes\</span><br><span class="line">   └── other_sd_project\</span><br></pre></td></tr></table></figure><p>每个项目独立 venv。</p><p>不要共享 Python。</p><p>不要全局 pip install。</p><hr><h1 id="七、什么时候不需要-uv？"><a href="#七、什么时候不需要-uv？" class="headerlink" title="七、什么时候不需要 uv？"></a>七、什么时候不需要 uv？</h1><p>如果：</p><ul><li>你只是临时跑一跑</li><li>用官方 portable 版本</li><li>不打算长期维护</li></ul><p>那 uv 不是必须。</p><p>但如果你：</p><ul><li>想深度调优</li><li>会装大量 custom nodes</li><li>可能换 torch 版本</li><li>可能升级 CUDA</li></ul><p>那 uv 会极大提升稳定性。</p><hr><h1 id="八、额外建议（非常关键）"><a href="#八、额外建议（非常关键）" class="headerlink" title="八、额外建议（非常关键）"></a>八、额外建议（非常关键）</h1><ol><li>永远不要用系统 Python</li><li>不要用 Anaconda（AI 环境冲突率高）</li><li>关闭 Windows Defender 对模型目录的实时扫描（会严重影响速度）</li><li>GPU 驱动要用 Studio Driver</li></ol><hr><p>如果你愿意，我可以帮你做一个：</p><ul><li>RTX 4080 &#x2F; CUDA 12.x 最优 torch 组合建议</li><li>ComfyUI 性能优化参数</li><li>VRAM 省显存启动方案</li></ul><p>你是想走“稳定生产环境”，还是“实验性环境”？<br>我可以给你两个完全不同的配置策略。</p><p>很好，这个报错信息其实非常清晰，我们逐层拆解。</p><hr><h1 id="一句话结论"><a href="#一句话结论" class="headerlink" title="一句话结论"></a>一句话结论</h1><p>你现在安装的是：</p><blockquote><p><strong>CPU 版本的 PyTorch</strong></p></blockquote><p>而不是 CUDA 版本。</p><p>所以 ComfyUI 在初始化 GPU 时直接炸掉：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">AssertionError: Torch not compiled with CUDA enabled</span><br></pre></td></tr></table></figure><hr><h1 id="证据在哪里？"><a href="#证据在哪里？" class="headerlink" title="证据在哪里？"></a>证据在哪里？</h1><p>关键日志：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Found comfy_kitchen backend cuda:</span><br><span class="line">&#123;&#x27;available&#x27;: False,</span><br><span class="line"> &#x27;disabled&#x27;: True,</span><br><span class="line"> &#x27;unavailable_reason&#x27;: &#x27;CUDA not available on this system&#x27;&#125;</span><br></pre></td></tr></table></figure><p>以及：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Torch not compiled with CUDA enabled</span><br></pre></td></tr></table></figure><p>这不是驱动问题。</p><p>这不是 CUDA 13.1 问题。</p><p>这 100% 是：</p><blockquote><p>你当前 venv 里装的是 CPU torch</p></blockquote><hr><h1 id="为什么会发生？"><a href="#为什么会发生？" class="headerlink" title="为什么会发生？"></a>为什么会发生？</h1><p>因为你之前执行了：</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv pip install <span class="literal">-r</span> requirements.txt</span><br></pre></td></tr></table></figure><p>而 requirements.txt 里通常只写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">torch</span><br></pre></td></tr></table></figure><p>默认行为是：</p><blockquote><p>pip 安装 CPU 版 torch</p></blockquote><p>除非你明确指定 CUDA index-url。</p><hr><h1 id="正确修复步骤（非常重要）"><a href="#正确修复步骤（非常重要）" class="headerlink" title="正确修复步骤（非常重要）"></a>正确修复步骤（非常重要）</h1><p>在 ComfyUI 目录：</p><h3 id="1️⃣-激活你的虚拟环境"><a href="#1️⃣-激活你的虚拟环境" class="headerlink" title="1️⃣ 激活你的虚拟环境"></a>1️⃣ 激活你的虚拟环境</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.venv\Scripts\activate</span><br></pre></td></tr></table></figure><h3 id="2️⃣-彻底卸载当前-torch"><a href="#2️⃣-彻底卸载当前-torch" class="headerlink" title="2️⃣ 彻底卸载当前 torch"></a>2️⃣ 彻底卸载当前 torch</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv pip uninstall torch torchvision torchaudio <span class="literal">-y</span></span><br></pre></td></tr></table></figure><p>确保完全移除。</p><hr><h3 id="3️⃣-安装-CUDA-12-1-版本（推荐）"><a href="#3️⃣-安装-CUDA-12-1-版本（推荐）" class="headerlink" title="3️⃣ 安装 CUDA 12.1 版本（推荐）"></a>3️⃣ 安装 CUDA 12.1 版本（推荐）</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv pip install torch torchvision <span class="literal">--index-url</span> https://download.pytorch.org/whl/cu121</span><br></pre></td></tr></table></figure><p>⚠️ 必须指定 index-url。</p><hr><h3 id="4️⃣-验证"><a href="#4️⃣-验证" class="headerlink" title="4️⃣ 验证"></a>4️⃣ 验证</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python <span class="literal">-c</span> <span class="string">&quot;import torch; print(torch.cuda.is_available()); print(torch.version.cuda)&quot;</span></span><br></pre></td></tr></table></figure><p>你应该看到：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">True</span><br><span class="line">12.1</span><br></pre></td></tr></table></figure><hr><h1 id="然后再运行"><a href="#然后再运行" class="headerlink" title="然后再运行"></a>然后再运行</h1><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv run python main.py</span><br></pre></td></tr></table></figure><hr><h1 id="为什么不是-CUDA-13-1？"><a href="#为什么不是-CUDA-13-1？" class="headerlink" title="为什么不是 CUDA 13.1？"></a>为什么不是 CUDA 13.1？</h1><p>因为：</p><ul><li>驱动支持 CUDA 13.1</li><li>PyTorch 目前稳定构建是 cu121</li><li>驱动向下兼容</li></ul><p>完全没问题。</p><hr><h1 id="再解释一下日志里的-triton"><a href="#再解释一下日志里的-triton" class="headerlink" title="再解释一下日志里的 triton"></a>再解释一下日志里的 triton</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Found comfy_kitchen backend triton:</span><br><span class="line">ImportError: No module named &#x27;triton&#x27;</span><br></pre></td></tr></table></figure><p>这个不是致命问题。</p><ul><li>Triton 是优化后端</li><li>可选</li><li>不影响 GPU 是否可用</li></ul><p>真正的问题只有：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Torch not compiled with CUDA enabled</span><br></pre></td></tr></table></figure><hr><h1 id="你现在环境的真实状态"><a href="#你现在环境的真实状态" class="headerlink" title="你现在环境的真实状态"></a>你现在环境的真实状态</h1><table><thead><tr><th>项目</th><th>状态</th></tr></thead><tbody><tr><td>驱动</td><td>正常</td></tr><tr><td>GPU</td><td>可用</td></tr><tr><td>CUDA runtime</td><td>支持 13.1</td></tr><tr><td>PyTorch</td><td>CPU 版本 ❌</td></tr><tr><td>ComfyUI</td><td>正常</td></tr></tbody></table><hr><h1 id="你犯的经典错误"><a href="#你犯的经典错误" class="headerlink" title="你犯的经典错误"></a>你犯的经典错误</h1><p><strong>先装 requirements，再装 torch</strong></p><p>正确顺序是：</p><ol><li>先装 GPU torch</li><li>再装 requirements</li></ol><p>否则 requirements 会装 CPU 版本覆盖。</p><hr><h1 id="如果你想更干净一点（推荐）"><a href="#如果你想更干净一点（推荐）" class="headerlink" title="如果你想更干净一点（推荐）"></a>如果你想更干净一点（推荐）</h1><p>直接删除 <code>.venv</code>：</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rmdir</span> /s /q .venv</span><br></pre></td></tr></table></figure><p>然后：</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">uv venv <span class="literal">--python</span> <span class="number">3.10</span></span><br><span class="line">.venv\Scripts\activate</span><br><span class="line"></span><br><span class="line">uv pip install torch torchvision <span class="literal">--index-url</span> https://download.pytorch.org/whl/cu121</span><br><span class="line">uv pip install <span class="literal">-r</span> requirements.txt</span><br></pre></td></tr></table></figure><p>这是最干净的做法。</p><hr><p>如果你愿意，我可以帮你做一个：</p><ul><li>RTX 40 系列稳定配置</li><li>ComfyUI 高显存优化参数</li><li>SDXL &#x2F; Flux 最佳启动参数</li><li>省显存运行策略</li></ul><p>你显卡型号是？显存多少？<br>我们可以直接调到最优解。</p><p>很好，你这张 <strong>RTX 4080 12GB</strong> 其实是一个“刚好卡在临界点”的配置——<br>既可以跑 SDXL，但必须精细控制显存策略，否则就会出现 OOM 或频繁清理显存导致卡顿。</p><p>我给你一个系统级的优化方案，不是零散参数，而是完整结构思路。</p><hr><h1 id="一、先确认你的目标类型"><a href="#一、先确认你的目标类型" class="headerlink" title="一、先确认你的目标类型"></a>一、先确认你的目标类型</h1><p>12GB 显存下的优先级建议：</p><ul><li>🟢 SD1.5 → 完全无压力</li><li>🟡 SDXL → 可跑，但需要控制</li><li>🔴 Flux &#x2F; 大型 LoRA 叠加 → 必须优化</li></ul><p>如果你是长期使用 ComfyUI 做生产工作，建议做下面这几层优化。</p><hr><h1 id="二、ComfyUI-启动层优化"><a href="#二、ComfyUI-启动层优化" class="headerlink" title="二、ComfyUI 启动层优化"></a>二、ComfyUI 启动层优化</h1><h2 id="推荐启动参数（4080-12GB-稳定版）"><a href="#推荐启动参数（4080-12GB-稳定版）" class="headerlink" title="推荐启动参数（4080 12GB 稳定版）"></a>推荐启动参数（4080 12GB 稳定版）</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python main.py --force-fp16 --use-pytorch-cross-attention --disable-smart-memory</span><br></pre></td></tr></table></figure><h3 id="参数解释"><a href="#参数解释" class="headerlink" title="参数解释"></a>参数解释</h3><ul><li><p><code>--force-fp16</code><br>强制半精度，直接节省 40~50% 显存</p></li><li><p><code>--use-pytorch-cross-attention</code><br>让 attention 走 torch 原生 kernel（对 40 系列更稳定）</p></li><li><p><code>--disable-smart-memory</code><br>禁止 ComfyUI 频繁卸载模型（12GB 下反而更稳定）</p></li></ul><hr><h1 id="三、PyTorch-层优化"><a href="#三、PyTorch-层优化" class="headerlink" title="三、PyTorch 层优化"></a>三、PyTorch 层优化</h1><h2 id="1️⃣-开启-TF32（非常重要）"><a href="#1️⃣-开启-TF32（非常重要）" class="headerlink" title="1️⃣ 开启 TF32（非常重要）"></a>1️⃣ 开启 TF32（非常重要）</h2><p>在 main.py 顶部加：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">torch.backends.cuda.matmul.allow_tf32 = <span class="literal">True</span></span><br><span class="line">torch.backends.cudnn.allow_tf32 = <span class="literal">True</span></span><br></pre></td></tr></table></figure><p>这对 RTX 40 系列有明显提升。</p><hr><h2 id="2️⃣-开启-cudnn-benchmark"><a href="#2️⃣-开启-cudnn-benchmark" class="headerlink" title="2️⃣ 开启 cudnn benchmark"></a>2️⃣ 开启 cudnn benchmark</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">torch.backends.cudnn.benchmark = <span class="literal">True</span></span><br></pre></td></tr></table></figure><p>前提是你分辨率固定（例如 1024×1024）。</p><hr><h1 id="四、模型加载策略优化"><a href="#四、模型加载策略优化" class="headerlink" title="四、模型加载策略优化"></a>四、模型加载策略优化</h1><h2 id="1️⃣-不要同时加载多个-checkpoint"><a href="#1️⃣-不要同时加载多个-checkpoint" class="headerlink" title="1️⃣ 不要同时加载多个 checkpoint"></a>1️⃣ 不要同时加载多个 checkpoint</h2><p>12GB 下：</p><ul><li>一次只加载一个大模型</li><li>LoRA 不超过 2~3 个</li></ul><hr><h2 id="2️⃣-使用-8-bit-或-4-bit-LoRA"><a href="#2️⃣-使用-8-bit-或-4-bit-LoRA" class="headerlink" title="2️⃣ 使用 8-bit 或 4-bit LoRA"></a>2️⃣ 使用 8-bit 或 4-bit LoRA</h2><p>如果你使用大量 LoRA：</p><ul><li>转成 8bit</li><li>或用 nvfp4（ComfyUI 新 backend 已支持）</li></ul><p>可以节省 1~2GB。</p><hr><h1 id="五、分辨率控制建议"><a href="#五、分辨率控制建议" class="headerlink" title="五、分辨率控制建议"></a>五、分辨率控制建议</h1><table><thead><tr><th>模型</th><th>建议最大分辨率</th></tr></thead><tbody><tr><td>SD1.5</td><td>1024×1024</td></tr><tr><td>SDXL</td><td>1024×1024</td></tr><tr><td>SDXL + ControlNet</td><td>832×832</td></tr></tbody></table><p>不要一开始就 1344×1344。</p><hr><h1 id="六、Windows-系统层优化"><a href="#六、Windows-系统层优化" class="headerlink" title="六、Windows 系统层优化"></a>六、Windows 系统层优化</h1><h2 id="1️⃣-关闭-Defender-对模型目录扫描"><a href="#1️⃣-关闭-Defender-对模型目录扫描" class="headerlink" title="1️⃣ 关闭 Defender 对模型目录扫描"></a>1️⃣ 关闭 Defender 对模型目录扫描</h2><p>把：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">D:\AI Models\</span><br></pre></td></tr></table></figure><p>加入排除列表。</p><p>会明显减少 IO 卡顿。</p><hr><h2 id="2️⃣-设置电源模式为“最佳性能”"><a href="#2️⃣-设置电源模式为“最佳性能”" class="headerlink" title="2️⃣ 设置电源模式为“最佳性能”"></a>2️⃣ 设置电源模式为“最佳性能”</h2><p>控制面板 → 电源选项。</p><hr><h2 id="3️⃣-NVIDIA-控制面板"><a href="#3️⃣-NVIDIA-控制面板" class="headerlink" title="3️⃣ NVIDIA 控制面板"></a>3️⃣ NVIDIA 控制面板</h2><ul><li>电源管理模式 → Prefer Maximum Performance</li><li>低延迟模式 → Off</li></ul><hr><h1 id="七、内存和缓存优化"><a href="#七、内存和缓存优化" class="headerlink" title="七、内存和缓存优化"></a>七、内存和缓存优化</h1><h2 id="1️⃣-增加-Pagefile（很重要）"><a href="#1️⃣-增加-Pagefile（很重要）" class="headerlink" title="1️⃣ 增加 Pagefile（很重要）"></a>1️⃣ 增加 Pagefile（很重要）</h2><p>12GB GPU + 16GB RAM 时建议：</p><p>虚拟内存设置为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">最小 32768 MB</span><br><span class="line">最大 65536 MB</span><br></pre></td></tr></table></figure><p>避免 SDXL 爆内存崩溃。</p><hr><h1 id="八、性能预期（给你一个心理模型）"><a href="#八、性能预期（给你一个心理模型）" class="headerlink" title="八、性能预期（给你一个心理模型）"></a>八、性能预期（给你一个心理模型）</h1><p>RTX 4080 12GB + SDXL：</p><table><thead><tr><th>分辨率</th><th>步数</th><th>预估时间</th></tr></thead><tbody><tr><td>1024</td><td>20</td><td>6~8 秒</td></tr><tr><td>1024</td><td>30</td><td>9~12 秒</td></tr></tbody></table><p>如果明显慢于这个，多半是：</p><ul><li>没开 fp16</li><li>torch 没走 CUDA</li><li>被 Defender 拖慢</li></ul><hr><h1 id="九、是否要安装-Triton？"><a href="#九、是否要安装-Triton？" class="headerlink" title="九、是否要安装 Triton？"></a>九、是否要安装 Triton？</h1><p>你日志显示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ImportError: No module named &#x27;triton&#x27;</span><br></pre></td></tr></table></figure><p>是否值得装？</p><p>结论：</p><ul><li>对 40 系列提升有限</li><li>容易增加依赖冲突</li><li>不建议现在装</li></ul><p>等环境稳定再考虑。</p><hr><h1 id="十、终极稳定方案（推荐结构）"><a href="#十、终极稳定方案（推荐结构）" class="headerlink" title="十、终极稳定方案（推荐结构）"></a>十、终极稳定方案（推荐结构）</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">D:\AI\</span><br><span class="line">   ├── ComfyUI\</span><br><span class="line">   │     ├── .venv</span><br><span class="line">   │     ├── models</span><br><span class="line">   │     ├── output</span><br><span class="line">   │     └── custom_nodes</span><br></pre></td></tr></table></figure><ul><li>每个 AI 项目一个独立 venv</li><li>不共享 torch</li><li>不全局安装 CUDA Toolkit</li></ul><hr><h1 id="十一、如果你想进一步压榨性能"><a href="#十一、如果你想进一步压榨性能" class="headerlink" title="十一、如果你想进一步压榨性能"></a>十一、如果你想进一步压榨性能</h1><p>可以：</p><ul><li>使用 xFormers（节省 10~15% 显存）</li><li>使用 Flash Attention 2（需要编译）</li><li>使用 nvfp4 quantization</li></ul><p>但这些属于“进阶实验优化”，不是稳定优先方案。</p><hr><h1 id="总结给你一句话"><a href="#总结给你一句话" class="headerlink" title="总结给你一句话"></a>总结给你一句话</h1><p>你的 RTX 4080 12GB 是一个“必须精细管理显存”的卡。</p><p>优化关键只有三件事：</p><ol><li>强制 FP16</li><li>控制模型数量</li><li>关闭 Windows IO 干扰</li></ol><p>做到这三点，ComfyUI 会非常稳定。</p><hr><p>如果你告诉我：</p><ul><li>你主要跑 SDXL 还是 1.5？</li><li>会不会用 ControlNet？</li><li>会不会叠多个 LoRA？</li></ul><p>我可以给你一个完全针对你使用模式的最优组合。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;你这个问题问得非常专业 👍——如果你已经在认真考虑依赖管理，那确实说明你不是只想“跑起来”，而是想把环境结构做干净、可控、可复现。&lt;/p&gt;
&lt;p&gt;结论先说：&lt;br&gt;&lt;strong&gt;是的，用 &lt;code&gt;uv&lt;/code&gt; 会比传统 &lt;code&gt;pip + venv&lt;/co</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="APP" scheme="https://blog.rezedge.com/categories/Environment/APP/"/>
    
    <category term="ComfyUI" scheme="https://blog.rezedge.com/categories/Environment/APP/ComfyUI/"/>
    
    
  </entry>
  
  <entry>
    <title>Solidworks 2024 开启 RealView</title>
    <link href="https://blog.rezedge.com/posts/c938871/"/>
    <id>https://blog.rezedge.com/posts/c938871/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.165Z</updated>
    
    <content type="html"><![CDATA[<p>将注册表定位到：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HKEY_CURRENT_USER\SOFTWARE\SolidWorks\AllowList\Current</span><br></pre></td></tr></table></figure><p>在右侧窗口找到 Renderer 项，双击并复制其”Value”（例如：NVIDIA GeForce RTX 4080 Laptop GPU&#x2F;PCIe&#x2F;SSE2）</p><p>定位 Gl2Shaders：导航至：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HKEY_CURRENT_USER\SOFTWARE\SolidWorks\AllowList\Gl2Shaders</span><br></pre></td></tr></table></figure><p>根据显卡品牌（NVIDIA 选 NV40，AMD 选 R420，Intel 选 Other），在对应文件夹下新建项（key），重命名为刚才复制的名称。</p><p>在新文件夹内新建 DWORD (32位) 值，命名为 Workarounds，数值建议填入 30408 或 31408 (十六进制)(Hexadecimal)</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;将注册表定位到：&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="APP" scheme="https://blog.rezedge.com/categories/Environment/APP/"/>
    
    <category term="Solidworks" scheme="https://blog.rezedge.com/categories/Environment/APP/Solidworks/"/>
    
    
  </entry>
  
  <entry>
    <title>React 动画库</title>
    <link href="https://blog.rezedge.com/posts/7462525e/"/>
    <id>https://blog.rezedge.com/posts/7462525e/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.172Z</updated>
    
    <content type="html"><![CDATA[<h1 id="React-动画库调研"><a href="#React-动画库调研" class="headerlink" title="React 动画库调研"></a>React 动画库调研</h1><p>在 2026 年的 React 生态系统中，Motion（原 Framer Motion）依然是声明式动画的事实标准。然而，根据不同的项目需求，如物理特性、复杂时间轴、包体积或自动布局动画，以下是几个主要的同类竞争产品调研。</p><h2 id="React-Spring"><a href="#React-Spring" class="headerlink" title="React Spring"></a>React Spring</h2><p>React Spring 是一个基于弹簧物理（Physics-based）原理的动画库，它不再依赖固定的持续时间，而是通过模拟质量、张力和阻力来创建自然的运动效果。</p><ul><li>核心优势：动画效果极其流畅且符合直觉，能很好地处理中断和交互。</li><li>适用场景：需要高度自然感、有机交互的 UI，或者涉及复杂物理反馈的场景。</li><li>关键特性：支持 Hooks API（如 useSpring, useTransition），兼容 SSR 环境。</li></ul><h2 id="GSAP-GreenSock-Animation-Platform"><a href="#GSAP-GreenSock-Animation-Platform" class="headerlink" title="GSAP (GreenSock Animation Platform)"></a>GSAP (GreenSock Animation Platform)</h2><p>GSAP 是网页动画领域的工业级标准。虽然它不是专门为 React 设计的，但其强大的插件生态（如 ScrollTrigger）使其在复杂动画开发中不可替代。</p><ul><li>核心优势：极高的高性能和跨浏览器兼容性。其时间轴（Timeline）控制能力远超其他声明式库。</li><li>适用场景：复杂的营销页面、滚动驱动的叙事动画、涉及数百个元素同步运动的场景。</li><li>关键特性：ScrollTrigger 插件可以轻松实现复杂的滚动联动效果。</li></ul><h2 id="AutoAnimate"><a href="#AutoAnimate" class="headerlink" title="AutoAnimate"></a>AutoAnimate</h2><p>由 FormKit 团队开发的 AutoAnimate 走的是零配置路线，它通过一行代码就能为列表和布局变动添加平滑过渡。</p><ul><li>核心优势：极低的学习成本，不需要编写具体的动画帧或过渡逻辑。</li><li>适用场景：快速提升后台管理系统、动态列表或网格布局的视觉质感。</li><li>关键特性：通过单个 Hook 或指令即可自动识别 DOM 变化并应用动画。</li></ul><h2 id="React-Transition-Group"><a href="#React-Transition-Group" class="headerlink" title="React Transition Group"></a>React Transition Group</h2><p>这是 React 官方推荐过的底层库，它本身不提供动画逻辑，而是管理组件进入和离开 DOM 的状态。</p><ul><li>核心优势：体积小巧，完全控制生命周期，可配合原生 CSS 或任何 JavaScript 动画引擎使用。</li><li>适用场景：基础的模态框显隐、简单的淡入淡出，以及对包体积有极致要求的项目。</li><li>关键特性：CSSTransition 和 TransitionGroup 组件。</li></ul><h2 id="性能与特性对比表"><a href="#性能与特性对比表" class="headerlink" title="性能与特性对比表"></a>性能与特性对比表</h2><table><thead><tr><th>库名称</th><th>动画类型</th><th>学习曲线</th><th>包体积 (Gzipped)</th><th>推荐用途</th></tr></thead><tbody><tr><td>Motion</td><td>声明式&#x2F;手势</td><td>中等</td><td>~30KB</td><td>通用 UI、交互原型</td></tr><tr><td>React Spring</td><td>物理模拟</td><td>较高</td><td>~15KB</td><td>自然感交互、高性能 UI</td></tr><tr><td>GSAP</td><td>时间轴&#x2F;命令式</td><td>较高</td><td>~25KB+</td><td>复杂叙事、高性能 Canvas</td></tr><tr><td>AutoAnimate</td><td>自动布局</td><td>极低</td><td>~2KB</td><td>列表排序、快速优化</td></tr><tr><td>RTG</td><td>状态切换</td><td>中等</td><td>~2KB</td><td>基础显隐过渡</td></tr></tbody></table><h2 id="选择建议"><a href="#选择建议" class="headerlink" title="选择建议"></a>选择建议</h2><ol><li>如果追求与 React 的深度集成、极致的声明式体验和丰富的手势支持，Motion 仍是首选。</li><li>如果项目侧重于物理驱动的响应式动效，React Spring 在表现力上更具优势。</li><li>面对需要精密编排、长序列动画或大规模 DOM 节点的情况，GSAP 的性能和调试工具更为可靠。</li><li>仅需为列表增加简单的添加&#x2F;删除动画，AutoAnimate 是投入产出比最高的方案。</li></ol><p>我可以为您对比其中某两个库的具体代码实现，或者根据您的项目规模推荐最适合的配置方案，您希望我深入介绍哪一个？</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;React-动画库调研&quot;&gt;&lt;a href=&quot;#React-动画库调研&quot; class=&quot;headerlink&quot; title=&quot;React 动画库调研&quot;&gt;&lt;/a&gt;React 动画库调研&lt;/h1&gt;&lt;p&gt;在 2026 年的 React 生态系统中，Motion（原 Fra</summary>
      
    
    
    
    <category term="Language" scheme="https://blog.rezedge.com/categories/Language/"/>
    
    <category term="Javascript" scheme="https://blog.rezedge.com/categories/Language/Javascript/"/>
    
    <category term="React" scheme="https://blog.rezedge.com/categories/Language/Javascript/React/"/>
    
    
  </entry>
  
  <entry>
    <title>monorepo中跨包导入问题</title>
    <link href="https://blog.rezedge.com/posts/1a1a74e9/"/>
    <id>https://blog.rezedge.com/posts/1a1a74e9/</id>
    <published>2026-02-23T17:16:19.000Z</published>
    <updated>2026-08-17T06:09:03.172Z</updated>
    
    <content type="html"><![CDATA[<p>Error is gone. Here’s the full explanation of everything at play:</p><hr><h2 id="Summary-TypeScript-package-json-exports-in-monorepo"><a href="#Summary-TypeScript-package-json-exports-in-monorepo" class="headerlink" title="Summary: TypeScript + package.json exports in monorepo"></a>Summary: TypeScript + <code>package.json</code> exports in monorepo</h2><h3 id="Why-the-error-occurred"><a href="#Why-the-error-occurred" class="headerlink" title="Why the error occurred"></a>Why the error occurred</h3><p>Your <code>tsconfig.base.json</code> has <code>composite: true</code>, which implies <strong>all source files must be under <code>rootDir</code></strong> (defaults to the tsconfig’s directory). When TypeScript resolves <code>@package/ui/Navigation</code> via the <code>exports</code> field → <code>./src/Navigation/index.ts</code>, that file lives in <code>package/ui/</code>, which is outside <code>package/app/</code>‘s <code>rootDir</code>. Hence the error.</p><p>Additionally, <code>include: [&quot;../ui/**/*.ts&quot;]</code> was directly pulling ui source into app’s program — a double violation.</p><h3 id="How-TypeScript-resolves-package-json-exports"><a href="#How-TypeScript-resolves-package-json-exports" class="headerlink" title="How TypeScript resolves package.json exports"></a>How TypeScript resolves <code>package.json</code> exports</h3><p>With <code>moduleResolution: &quot;Bundler&quot;</code> (your base config), TypeScript <strong>fully supports</strong> the <code>exports</code> field:</p><ol><li><code>import &#123;RouterLink&#125; from &#39;@package/ui/Navigation&#39;</code></li><li>TS finds <code>@package/ui</code> → reads <code>package.json</code></li><li>Matches <code>exports[&quot;./Navigation&quot;]</code> → uses <code>types</code> condition → <code>./src/Navigation/index.ts</code></li><li>Resolution succeeds</li></ol><p>The issue was never about <code>exports</code> compatibility — it was about <code>composite</code>‘s <code>rootDir</code> enforcement.</p><h3 id="What-was-changed"><a href="#What-was-changed" class="headerlink" title="What was changed"></a>What was changed</h3><p><strong><code>package/app/tsconfig.json</code>:</strong></p><ul><li>Overrode <code>composite: false</code>, <code>declaration: false</code>, <code>declarationMap: false</code>, <code>emitDeclarationOnly: false</code> — app is a leaf Vite application, not a library, so it doesn’t need these</li><li>Removed <code>&quot;../ui/**/*.ts&quot;, &quot;../ui/**/*.tsx&quot;</code> from <code>include</code> — app should only compile its own source; cross-package types come through <code>exports</code> resolution</li><li>Removed <code>outDir</code> since app doesn’t emit anything (Vite handles bundling)</li></ul><p><strong>Root <code>tsconfig.json</code>:</strong></p><ul><li>Removed <code>app</code> from <code>references</code> — without <code>composite</code>, it can’t participate in <code>tsc -b</code></li></ul><h3 id="The-pattern-for-extensionless-cross-package-imports"><a href="#The-pattern-for-extensionless-cross-package-imports" class="headerlink" title="The pattern for extensionless cross-package imports"></a>The pattern for extensionless cross-package imports</h3><p>Your current <code>package/ui/package.json</code> exports setup is correct for this:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&quot;./*&quot;: &#123;</span><br><span class="line">  &quot;types&quot;: &quot;./src/*&quot;,</span><br><span class="line">  &quot;import&quot;: &quot;./src/*&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot;./Navigation&quot;: &#123;</span><br><span class="line">  &quot;types&quot;: &quot;./src/Navigation/index.ts&quot;,</span><br><span class="line">  &quot;import&quot;: &quot;./src/Navigation/index.ts&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><strong>Wildcard <code>./*</code></strong> — handles extensionless file imports like <code>@package/ui/SomeFile</code></li><li><strong>Explicit <code>./Navigation</code></strong> — needed for directory-based exports (where the actual file is <code>index.ts</code> inside a folder), because the wildcard won’t automatically append <code>/index.ts</code></li></ul><p>The rule: <strong>for any directory with an <code>index.ts</code>, add an explicit <code>exports</code> entry</strong>. Wildcards only work for direct file-to-file mapping.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Error is gone. Here’s the full explanation of everything at play:&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;Summary-TypeScript-package-json-exports-in-monorepo&quot;&gt;&lt;</summary>
      
    
    
    
    <category term="Language" scheme="https://blog.rezedge.com/categories/Language/"/>
    
    <category term="Javascript" scheme="https://blog.rezedge.com/categories/Language/Javascript/"/>
    
    <category term="Typescript" scheme="https://blog.rezedge.com/categories/Language/Javascript/Typescript/"/>
    
    
  </entry>
  
  <entry>
    <title>Git 追踪文件大小写</title>
    <link href="https://blog.rezedge.com/posts/7491252b/"/>
    <id>https://blog.rezedge.com/posts/7491252b/</id>
    <published>2026-02-14T19:39:24.000Z</published>
    <updated>2026-08-17T06:09:03.165Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Git-追踪目录大小写问题小记"><a href="#Git-追踪目录大小写问题小记" class="headerlink" title="Git 追踪目录大小写问题小记"></a>Git 追踪目录大小写问题小记</h1><p>有，而且这是一个<strong>典型 Windows + Git + 大小写重命名</strong>的工程问题。你这个 monorepo 规模下，确实值得用“工程级解法”一次性清干净。</p><p>我给你按<strong>安全程度从低风险到高风险</strong>分层讲清楚。</p><hr><h1 id="✅-方案一（推荐）：强制-Git-重新识别当前大小写状态"><a href="#✅-方案一（推荐）：强制-Git-重新识别当前大小写状态" class="headerlink" title="✅ 方案一（推荐）：强制 Git 重新识别当前大小写状态"></a>✅ 方案一（推荐）：强制 Git 重新识别当前大小写状态</h1><p>这个是最干净、最可控的方法。</p><hr><h2 id="第一步：关闭-ignorecase"><a href="#第一步：关闭-ignorecase" class="headerlink" title="第一步：关闭 ignorecase"></a>第一步：关闭 ignorecase</h2><p>Windows 默认：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config core.ignorecase</span><br><span class="line"><span class="comment"># 大概率是 true</span></span><br></pre></td></tr></table></figure><p>改为：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config core.ignorecase <span class="literal">false</span></span><br></pre></td></tr></table></figure><p>这一步非常关键。</p><hr><h2 id="第二步：强制-Git-重新扫描-index"><a href="#第二步：强制-Git-重新扫描-index" class="headerlink" title="第二步：强制 Git 重新扫描 index"></a>第二步：强制 Git 重新扫描 index</h2><p>让 Git 重新对比磁盘文件和 index：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">rm</span> -r --cached .</span><br><span class="line">git add .</span><br></pre></td></tr></table></figure><p>然后：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br></pre></td></tr></table></figure><p>如果大小写有差异，你会看到 rename 或 delete&#x2F;add。</p><p>最后：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&quot;chore: normalize file casing&quot;</span></span><br></pre></td></tr></table></figure><hr><h3 id="为什么这招有效？"><a href="#为什么这招有效？" class="headerlink" title="为什么这招有效？"></a>为什么这招有效？</h3><p>因为：</p><ul><li><code>--cached</code> 只清 index，不删物理文件</li><li>再 <code>git add .</code> 会根据当前磁盘真实大小写重新建 index</li><li>Git 被强制重新建立大小写映射</li></ul><p>这是最安全方案。</p><hr><h1 id="✅-方案二：强制大小写重命名（更精确）"><a href="#✅-方案二：强制大小写重命名（更精确）" class="headerlink" title="✅ 方案二：强制大小写重命名（更精确）"></a>✅ 方案二：强制大小写重命名（更精确）</h1><p>如果你只想修一个目录，比如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">component/navigation</span><br></pre></td></tr></table></figure><p>想统一成：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">component/Navigation</span><br></pre></td></tr></table></figure><p>做法：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">mv</span> component/navigation component/__tmp__</span><br><span class="line">git <span class="built_in">mv</span> component/__tmp__ component/Navigation</span><br><span class="line">git commit -m <span class="string">&quot;fix: normalize Navigation directory casing&quot;</span></span><br></pre></td></tr></table></figure><hr><h1 id="✅-方案三：暴力重建-index（偏工程化）"><a href="#✅-方案三：暴力重建-index（偏工程化）" class="headerlink" title="✅ 方案三：暴力重建 index（偏工程化）"></a>✅ 方案三：暴力重建 index（偏工程化）</h1><p>如果你怀疑整个仓库 casing 混乱，可以：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -f .git/index</span><br><span class="line">git reset</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git read-tree --reset -u HEAD</span><br></pre></td></tr></table></figure><p>这个会完全重建 index。</p><p>⚠️ 只建议在工作区 clean 时使用。</p><hr><h1 id="🚨-千万不要做的事"><a href="#🚨-千万不要做的事" class="headerlink" title="🚨 千万不要做的事"></a>🚨 千万不要做的事</h1><p>不要：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">删除文件 → 手动重建</span><br></pre></td></tr></table></figure><p>不要：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">直接 rename 文件夹大小写（Windows 会忽略）</span><br></pre></td></tr></table></figure><p>因为 NTFS 默认大小写不敏感，直接改大小写 Git 不一定感知。</p><hr><h1 id="🧠-为什么会发生？"><a href="#🧠-为什么会发生？" class="headerlink" title="🧠 为什么会发生？"></a>🧠 为什么会发生？</h1><p>你的项目：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Library.Book/package/app/src/component</span><br></pre></td></tr></table></figure><p>如果你：</p><ul><li>曾在 Linux&#x2F;WSL 操作</li><li>或从 Mac clone</li><li>或 IDE 自动修正大小写</li><li>或做过 <code>git mv</code> 但 ignorecase&#x3D;true</li></ul><p>都会导致：</p><p>Git index 认为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Navigation</span><br></pre></td></tr></table></figure><p>但磁盘是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">navigation</span><br></pre></td></tr></table></figure><p>TypeScript 再结合 path alias 就会触发 TS1149。</p><hr><h1 id="🛡-工程级预防方案（强烈建议）"><a href="#🛡-工程级预防方案（强烈建议）" class="headerlink" title="🛡 工程级预防方案（强烈建议）"></a>🛡 工程级预防方案（强烈建议）</h1><h3 id="1️⃣-tsconfig-打开"><a href="#1️⃣-tsconfig-打开" class="headerlink" title="1️⃣ tsconfig 打开"></a>1️⃣ tsconfig 打开</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;forceConsistentCasingInFileNames&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br></pre></td></tr></table></figure><hr><h3 id="2️⃣-团队-Git-强制大小写敏感"><a href="#2️⃣-团队-Git-强制大小写敏感" class="headerlink" title="2️⃣ 团队 Git 强制大小写敏感"></a>2️⃣ 团队 Git 强制大小写敏感</h3><p>在仓库级别执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config core.ignorecase <span class="literal">false</span></span><br></pre></td></tr></table></figure><p>甚至可以写进：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.git/config</span><br></pre></td></tr></table></figure><hr><h3 id="3️⃣-ESLint-规则"><a href="#3️⃣-ESLint-规则" class="headerlink" title="3️⃣ ESLint 规则"></a>3️⃣ ESLint 规则</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span>/no-unresolved</span><br></pre></td></tr></table></figure><p>并开启 caseSensitive 选项。</p><hr><h1 id="🎯-给你最稳的一套操作顺序"><a href="#🎯-给你最稳的一套操作顺序" class="headerlink" title="🎯 给你最稳的一套操作顺序"></a>🎯 给你最稳的一套操作顺序</h1><p>如果我是你，现在这样做：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git config core.ignorecase <span class="literal">false</span></span><br><span class="line">git <span class="built_in">rm</span> -r --cached .</span><br><span class="line">git add .</span><br><span class="line">git commit -m <span class="string">&quot;chore: rebuild git index to normalize casing&quot;</span></span><br></pre></td></tr></table></figure><p>然后：</p><ul><li>重启 TS server</li><li>重启 IDE</li><li>再跑一遍 typecheck</li></ul><p>基本 99% 解决。</p><hr><h1 id="💬-说一句实话"><a href="#💬-说一句实话" class="headerlink" title="💬 说一句实话"></a>💬 说一句实话</h1><p>你这个 monorepo 规模（Library.Book）已经到了：</p><blockquote><p>“路径规范必须制度化”的阶段。</p></blockquote><p>否则以后 CI 上 Linux 一跑，直接炸。</p><hr><p>如果你愿意，我可以给你：</p><ul><li>一套跨平台命名规范</li><li>一套 React + TS + Bun monorepo 的 casing 规范模板</li><li>一套 pre-commit 自动检测大小写冲突脚本</li></ul><p>这类问题属于工程成熟度问题，而不是单纯 bug。</p><p>你现在踩到的是正常进阶门槛。</p><h2 id="为什么-Git-默认不追踪大小写变更？"><a href="#为什么-Git-默认不追踪大小写变更？" class="headerlink" title="为什么 Git 默认不追踪大小写变更？"></a>为什么 Git 默认不追踪大小写变更？</h2><ul><li>Git 默认大小写敏感，但会根据文件系统类型决定是否追踪大小写变化。</li><li><strong>Linux</strong>：默认大小写敏感（EXT4）。</li><li><strong>macOS&#x2F;Windows</strong>：默认大小写不敏感（HFS+ &#x2F; NTFS）。</li></ul><h2 id="如何让-Git-追踪大小写变化？"><a href="#如何让-Git-追踪大小写变化？" class="headerlink" title="如何让 Git 追踪大小写变化？"></a>如何让 Git 追踪大小写变化？</h2><ul><li><p>执行以下命令强制 Git 不忽略大小写：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config core.ignorecase <span class="literal">false</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="如何解决已有的大小写更改未被识别？"><a href="#如何解决已有的大小写更改未被识别？" class="headerlink" title="如何解决已有的大小写更改未被识别？"></a>如何解决已有的大小写更改未被识别？</h2><ul><li><p>使用中间临时名来实现大小写变更：</p><ol><li><p>重命名为临时名：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">mv</span> foo temp_name</span><br></pre></td></tr></table></figure></li><li><p>重命名为目标名：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">mv</span> temp_name Foo</span><br></pre></td></tr></table></figure></li><li><p>提交更改：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&quot;fix: rename foo → Foo (大小写更正)&quot;</span></span><br></pre></td></tr></table></figure></li></ol></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ul><li><p><strong>跨系统协作时：</strong></p><ul><li>确保所有开发者统一 Git 设置：<code>git config core.ignorecase false</code></li><li>规范文件命名，避免随意更改大小写（例如，统一小写或使用下划线）。、</li></ul></li><li><p><strong>检查当前设置：</strong></p><ul><li>使用 <code>git config core.ignorecase</code> 查看当前的配置，确保其为 <code>false</code>。</li></ul></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Git-追踪目录大小写问题小记&quot;&gt;&lt;a href=&quot;#Git-追踪目录大小写问题小记&quot; class=&quot;headerlink&quot; title=&quot;Git 追踪目录大小写问题小记&quot;&gt;&lt;/a&gt;Git 追踪目录大小写问题小记&lt;/h1&gt;&lt;p&gt;有，而且这是一个&lt;strong&gt;典型</summary>
      
    
    
    
    <category term="Environment" scheme="https://blog.rezedge.com/categories/Environment/"/>
    
    <category term="Git" scheme="https://blog.rezedge.com/categories/Environment/Git/"/>
    
    
  </entry>
  
  <entry>
    <title>React Compiler 踩坑</title>
    <link href="https://blog.rezedge.com/posts/a0a5fdef/"/>
    <id>https://blog.rezedge.com/posts/a0a5fdef/</id>
    <published>2026-02-13T10:48:29.000Z</published>
    <updated>2026-08-17T06:09:03.172Z</updated>
    
    <content type="html"><![CDATA[<p>先说问题，再放简介</p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><h3 id="Few-Hooks-error"><a href="#Few-Hooks-error" class="headerlink" title="Few Hooks error"></a>Few Hooks error</h3><p>因为 <code>babel-plugin-react-compiler</code> 会优化 Hooks，但是只会优化以<code>use</code>开头的<code>useXXX</code>函数，理论上未使用use开头的函数是会跳过？</p><p>然而实际上这可能触发非常严重的问题，会导致完全无法调试的Few Hooks error。</p><p>推荐调试的时候先禁用插件，然后确定问题是不是由于<code>babel-plugin-react-compiler</code>导致的。</p><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><blockquote><p>Generate by AI </p></blockquote><p><code>babel-plugin-react-compiler</code> 本质上是 React Compiler 的 Babel 接入层：它把你的函数组件与自定义 Hook（以及部分相关函数）在“构建期”改写成带有自动缓存与细粒度失效的代码，让你在不大量手写 <code>useMemo</code> &#x2F; <code>useCallback</code> &#x2F; <code>React.memo</code> 的前提下，尽量把“更新时真正需要重算&#x2F;重渲染的部分”压到最小，同时还会基于同一套核心逻辑去验证你是否违反了 React 的基本规则（纯渲染、Hooks 规则等）。这套方向在官方设计目标里写得很直白：希望应用默认就快、启动时间不要倒退、并且尽量“移除概念而不是引入概念”（减少对手动 memo 的依赖）。(<a href="https://raw.githubusercontent.com/facebook/react/main/compiler/docs/DESIGN_GOALS.md" title="raw.githubusercontent.com">GitHub</a>)</p><p>从产物形态上看，这个 Babel 插件干的事并不神秘：它会在编译后的输出里插入一个“memo cache”数组，并以一个哨兵值 <code>Symbol.for(&quot;react.memo_cache_sentinel&quot;)</code> 来判断缓存是否已填充，然后复用上一次渲染计算出来的 JSX 或中间值。官方安装文档给了一个最小例子：编译后会出现 <code>import &#123; c as _c &#125; from &quot;react/compiler-runtime&quot;;</code>，随后用 <code>_c(n)</code> 初始化缓存槽位并在命中时直接取回。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>) 这也是你判断“插件是否真的在跑”的最硬证据之一（另一个是 DevTools 里出现 “Memo ✨” 标记）。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>)</p><p>再往里一层，React 团队公开的编译器架构描述解释了“为什么它能做到更细粒度”：Babel 插件先决定哪些函数要编译（取决于选项与局部指令），随后把 Babel AST lowering 成编译器自己的高层中间表示 HIR（保留高层语义、并以控制流图组织），再进入 SSA 形式、跑一系列校验（检测条件式 Hook、无条件 setState 等）、做基础优化（DCE、常量传播）、做保守类型推断，然后推断并构造所谓“reactive scopes”（把会一起创建&#x2F;变更、以及相关指令聚成组），最后 codegen 回 Babel AST 替换原函数。(<a href="https://raw.githubusercontent.com/facebook/react/main/compiler/docs/DESIGN_GOALS.md" title="raw.githubusercontent.com">GitHub</a>) 这段描述里有两个对使用者非常关键的含义：第一，它强依赖“遵守 React 规则”来保证变换安全；第二，它明确把“完全零冗余重算”列为非目标，因为额外追踪与代码膨胀可能反噬启动性能。(<a href="https://raw.githubusercontent.com/facebook/react/main/compiler/docs/DESIGN_GOALS.md" title="raw.githubusercontent.com">GitHub</a>) 也因此你会看到它不支持类组件、也不会承诺支持 100% JS 语法角落（例如 <code>eval()</code> 等）。(<a href="https://raw.githubusercontent.com/facebook/react/main/compiler/docs/DESIGN_GOALS.md" title="raw.githubusercontent.com">GitHub</a>)</p><p>落到 <code>babel-plugin-react-compiler</code> 的实操层面，有三件事决定你能否顺利落地。第一是插件顺序：官方明确要求它必须在 Babel 插件流水线里最先运行，因为它需要尽可能“原始”的源码信息做分析，后置变换会破坏这些信息。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>) 第二是接入方式：React 官方文档直接给了 Babel 与 Vite 的推荐配置（Vite 既可以走 <code>@vitejs/plugin-react</code> 的 <code>babel.plugins</code>，也可以用 <code>vite-plugin-babel</code> 单独挂载）。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>) 第三是版本目标：React 19 默认就能工作；如果你在 React 17&#x2F;18 上用编译产物，则需要安装 <code>react-compiler-runtime</code> 并在配置里设置 <code>target: &#39;17&#39; | &#39;18&#39;</code>，否则运行期会缺少相应 runtime。(<a href="https://react.dev/reference/react-compiler/configuration" title="Configuration – React">React</a>)</p><p>下面给你一个“工程里最常见、也最不容易踩坑”的 Babel 配置骨架，你只需要把它合并进现有配置即可（注意它要放在插件数组最前）：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// babel.config.js</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    [<span class="string">&#x27;babel-plugin-react-compiler&#x27;</span>, &#123;</span><br><span class="line">      <span class="comment">// 生产建议：遇到问题的组件跳过优化，不要直接炸构建</span></span><br><span class="line">      <span class="attr">panicThreshold</span>: <span class="string">&#x27;none&#x27;</span>,</span><br><span class="line">      <span class="comment">// React 19 默认即可；React 17/18 需要显式 target + 安装 react-compiler-runtime</span></span><br><span class="line">      <span class="comment">// target: &#x27;18&#x27;,</span></span><br><span class="line">    &#125;],</span><br><span class="line">    <span class="comment">// ...other plugins</span></span><br><span class="line">  ],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>这里出现的 <code>panicThreshold</code> 来自官方配置参考，它决定“编译遇到错误时是失败构建还是跳过问题组件”；文档里把 <code>panicThreshold: &#39;none&#39;</code> 标为推荐的生产配置（跳过出问题的组件，继续优化其他部分）。(<a href="https://react.dev/reference/react-compiler/configuration" title="Configuration – React">React</a>) 同一份配置参考还给了调试与灰度手段：你可以用 <code>logger.logEvent(filename, event)</code> 捕获编译成功&#x2F;失败等事件，用于定位到底哪些文件被编译、哪里被跳过。(<a href="https://react.dev/reference/react-compiler/configuration" title="Configuration – React">React</a>) 如果你需要做 A&#x2F;B 或渐进灰度，<code>gating</code> 允许你指定一个 feature-flag 模块与导出函数名，让编译产物在运行期根据开关选择是否走优化路径。(<a href="https://react.dev/reference/react-compiler/gating" title="gating – React">React</a>)</p><p>另一个经常被忽略、但会直接影响“为什么我感觉没生效”的开关，是 <code>compilationMode</code>。默认是 <code>&#39;infer&#39;</code>：编译器靠启发式识别组件与 Hook（比如 PascalCase 组件名、<code>use</code> 前缀 Hook、并且确实创建 JSX 或调用 Hook），你不需要写任何额外标注；如果你想极其稳妥地逐步接入，可以改为 <code>&#39;annotation&#39;</code>，此时只有显式写了 <code>&quot;use memo&quot;</code> 指令的函数才会被编译；而 <code>&quot;use no memo&quot;</code> 则永远是强制跳过。(<a href="https://react.dev/reference/react-compiler/compilationMode" title="compilationMode – React">React</a>) 这套机制的价值在于：当你接入初期遇到少数库&#x2F;组件不兼容或行为异常时，你可以先用 <code>&quot;use no memo&quot;</code> 把它们隔离出来，让整体构建与大部分页面继续享受优化，然后再用 lint&#x2F;日志去逐个消化。官方安装页把这点写得非常明确：<code>&quot;use no memo&quot;</code> 是临时逃生舱。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>)</p><p>关于“手写 memo 还要不要存在”，官方立场其实很一致：目标是让绝大多数场景下你不需要再为了性能去写 <code>useMemo/useCallback/React.memo</code>，但它并不追求把所有重算都消到零，也不会为了极限最优引入高额追踪成本或显著膨胀代码体积。(<a href="https://raw.githubusercontent.com/facebook/react/main/compiler/docs/DESIGN_GOALS.md" title="raw.githubusercontent.com">GitHub</a>) 这意味着你的工程实践会变成“默认不写，只有在行为语义需要（比如你就是要一个稳定引用参与外部系统协议）或某些特殊性能剖析结论明确时再写”，而不是过去那种“先写一堆 memo 再说”。</p><p>最后说一下配套的“保证你不会盲用”的部分：官方推荐同时启用 ESLint 的相关规则，用来提示哪些组件&#x2F;Hook 因为违反 Rules of React 而无法被优化。更重要的是，文档强调这是安全的：当 ESLint 报错时，编译器会跳过该组件&#x2F;Hook 的优化，但不会影响其它代码的优化，你可以按自己的节奏逐步修。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>) 接入完成后，最直接的验收方法就是打开 React DevTools，看看组件名旁边是否出现 “Memo ✨” 标记；或者直接在构建输出里搜 <code>react/compiler-runtime</code> 与 <code>react.memo_cache_sentinel</code>。(<a href="https://react.dev/learn/react-compiler/installation" title="Installation – React">React</a>)</p><p>如果你愿意把你当前的构建栈（Vite&#x2F;Next&#x2F;Rspack 等）、React 版本（17&#x2F;18&#x2F;19）、以及是否存在“必须保留稳定引用语义”的场景（例如订阅系统、第三方表单库、可视化库）贴出来，我可以按你的工程形态给一份更贴合的推荐配置（<code>compilationMode/target/panicThreshold/logger/gating</code> 该怎么组合、以及最小化风险的渐进接入路径）。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;先说问题，再放简介&lt;/p&gt;
&lt;h2 id=&quot;问题&quot;&gt;&lt;a href=&quot;#问题&quot; class=&quot;headerlink&quot; title=&quot;问题&quot;&gt;&lt;/a&gt;问题&lt;/h2&gt;&lt;h3 id=&quot;Few-Hooks-error&quot;&gt;&lt;a href=&quot;#Few-Hooks-error&quot; clas</summary>
      
    
    
    
    <category term="Language" scheme="https://blog.rezedge.com/categories/Language/"/>
    
    <category term="Javascript" scheme="https://blog.rezedge.com/categories/Language/Javascript/"/>
    
    <category term="React" scheme="https://blog.rezedge.com/categories/Language/Javascript/React/"/>
    
    
  </entry>
  
</feed>
