vault backup: 2026-07-01 23:09:21
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
---
|
||||
tags: [macos, dev-env, onboarding]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# macOS 开发环境配置指南
|
||||
|
||||
## 概述
|
||||
|
||||
面向 Mac 的通用开发环境搭建步骤,覆盖七牛云暑期实习开营前的工具链要求:Git / SSH、Node.js(nvm + pnpm)、TypeScript、Go(GOPROXY)、AI Coding Agent 和 GitHub CLI。按顺序执行即可,每条末尾附验证命令。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- macOS 12 Monterey 或更高版本
|
||||
- 系统自带 **Terminal**,推荐使用 **iTerm2**
|
||||
|
||||
```bash
|
||||
brew install iterm2
|
||||
```
|
||||
|
||||
## 一、Homebrew
|
||||
|
||||
详见 [[mac-dev-env-setup/homebrew-intro]](安装步骤与常见命令在此简述,进阶用法见独立文档)。
|
||||
|
||||
Homebrew 是 macOS 最重要的包管理器,后续所有工具都通过它安装。
|
||||
|
||||
```bash
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
```
|
||||
|
||||
首次安装后把 brew 加入 PATH(ARM Mac / Intel Mac 不同,按终端输出的提示操作):
|
||||
|
||||
```bash
|
||||
# ARM Mac(M1/M2/M3/M4)
|
||||
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
|
||||
# Intel Mac
|
||||
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
brew --version
|
||||
```
|
||||
|
||||
### 常用 brew 命令速查
|
||||
|
||||
| 用途 | 命令 |
|
||||
|------|------|
|
||||
| 搜索 | `brew search <name>` |
|
||||
| 安装 | `brew install <name>` |
|
||||
| 卸载 | `brew uninstall <name>` |
|
||||
| 升级所有已装包 | `brew upgrade` |
|
||||
| 清理缓存 | `brew cleanup` |
|
||||
| 列出可升级包 | `brew outdated` |
|
||||
|
||||
## 二、Git & SSH
|
||||
|
||||
详见 [[mac-dev-env-setup/git-ssh-config]](双账号密钥路由、~/.ssh/config 配置机制、连接排障)。
|
||||
|
||||
```bash
|
||||
brew install git
|
||||
git --version # 验证
|
||||
```
|
||||
|
||||
### SSH Key 生成速查
|
||||
|
||||
```bash
|
||||
# GitHub
|
||||
ssh-keygen -t ed25519 -C "hezhaohui0807@163.com" -f ~/.ssh/id_ed25519_github
|
||||
|
||||
# Gitea
|
||||
ssh-keygen -t ed25519 -C "hezhaohui0807@163.com" -f ~/.ssh/id_ed25519_gitea
|
||||
```
|
||||
|
||||
公钥分别粘贴到对应平台的 SSH Keys 设置页。详细 Host 别名配置见子文档。
|
||||
|
||||
### Git 基础配置
|
||||
|
||||
```bash
|
||||
git config --global user.name "hezhaohui"
|
||||
git config --global user.email "hezhaohui0807@163.com"
|
||||
git config --global core.autocrlf input
|
||||
git config --global init.defaultBranch main
|
||||
```
|
||||
|
||||
## 三、Node.js + pnpm
|
||||
|
||||
详见 [[mac-dev-env-setup/node-nvm-pnpm]](nvm 版本管理机制、Corepack 零开销调度器、pnpm 硬链接存储模型)。
|
||||
|
||||
### nvm 速查
|
||||
|
||||
```bash
|
||||
brew install nvm
|
||||
mkdir -p ~/nvm
|
||||
```
|
||||
|
||||
在 `~/.zshrc` 中追加(完整脚本见子文档):
|
||||
|
||||
```bash
|
||||
export NVM_DIR="$HOME/nvm"
|
||||
[ -s "$(brew --prefix)/opt/nvm/nvm.sh" ] && . "$(brew --prefix)/opt/nvm/nvm.sh"
|
||||
EOF
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
### pnpm
|
||||
|
||||
```bash
|
||||
corepack enable
|
||||
corepack prepare pnpm@latest --activate
|
||||
```
|
||||
|
||||
详见子文档了解 Corepack 机制、pnpm workspace 与 store 管理。
|
||||
|
||||
### VS Code(推荐)
|
||||
|
||||
```bash
|
||||
brew install --cask visual-studio-code
|
||||
```
|
||||
|
||||
然后在 VS Code 中打开扩展面板,搜索并安装以下插件:
|
||||
- ESLint
|
||||
- Prettier
|
||||
- TypeScript Debugger
|
||||
|
||||
## 四、TypeScript
|
||||
|
||||
```bash
|
||||
npm install -g typescript
|
||||
```
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
tsc -v # 如 v5.6.3
|
||||
```
|
||||
|
||||
## 五、Go
|
||||
|
||||
详见 [[mac-dev-env-setup/go-module-proxy]](GOPROXY 代理链原理、GOSUMDB 校验机制、Go Workspace / vendor 模式)。
|
||||
|
||||
```bash
|
||||
brew install go
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
```
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
go version # 如 go1.23.x
|
||||
go env GOPROXY # 应输出:https://goproxy.cn,direct
|
||||
```
|
||||
|
||||
### VS Code Go 插件
|
||||
|
||||
VS Code 扩展面板搜索安装 **Go**(by Gore-Multi),安装后会弹出提示是否安装 Go 工具链子组件,点 **Install All** 即可。
|
||||
|
||||
## 六、Python(按需)
|
||||
|
||||
如果所在组使用 Python 栈,提前装好:
|
||||
|
||||
```bash
|
||||
brew install python@3.12
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m venv ~/venvs/default
|
||||
source ~/venvs/default/bin/activate
|
||||
```
|
||||
|
||||
### uv(可选,更快的 Python 包管理器)
|
||||
|
||||
```bash
|
||||
brew install uv
|
||||
```
|
||||
|
||||
## 七、Java(按需)
|
||||
|
||||
```bash
|
||||
brew install --cask temurin
|
||||
# 或
|
||||
brew install openjdk@17
|
||||
```
|
||||
|
||||
在 `~/.zshrc` 中加入 JAVA_HOME:
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
|
||||
```
|
||||
|
||||
## 八、GitHub CLI
|
||||
|
||||
详见 [[mac-dev-env-setup/gh-cli-commands]](PR / Issue / Fork 常用命令与完整工作流)。
|
||||
|
||||
```bash
|
||||
brew install gh
|
||||
gh auth login # 按提示登录 GitHub 账号
|
||||
gh --version # 验证
|
||||
```
|
||||
|
||||
### 日常高频命令速查
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
| Clone 仓库 | `gh repo clone owner/repo` |
|
||||
| Fork + 克隆 | `gh repo fork owner/repo` |
|
||||
| Checkout PR | `gh pr checkout 12` |
|
||||
| 创建 PR | `gh pr create --title "feat: xxx" --body "desc"` |
|
||||
| 列出 Issues | `gh issue list --label bug` |
|
||||
| 查看自己的 PR/Issue | `gh pr status` / `gh issue status` |
|
||||
| 终端查看详情 | `gh pr view 42` / `gh issue view 42` |
|
||||
|
||||
> [!tip] gh + Claude Code 协作
|
||||
> 先用 `gh issue list` 拉出任务,再让 Claude Code 在当前分支实现,比在浏览器切来切去高效得多。见 [[mac-dev-env-setup/ai-coding-agent]]。
|
||||
|
||||
## 九、AI Coding Agent — Claude Code
|
||||
|
||||
详见 [[mac-dev-env-setup/ai-coding-agent]](Prompting 四原则、CLAUDE.md 上下文注入、与 gh CLI 组合工作流)。
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm install -g @anthropic-ai/claude-code
|
||||
```
|
||||
|
||||
### 首次运行
|
||||
|
||||
```bash
|
||||
claude
|
||||
```
|
||||
|
||||
按提示登录 Anthropic 账号并配置 API Key。
|
||||
|
||||
> [!info] 让 Claude Code 调用 GitHub CLI
|
||||
> Claude Code 可以原生理解仓库上下文,配合 `gh` 使用效果更好:先 `gh issue list` 查看任务,再让 Claude Code 直接在当前分支实现。
|
||||
|
||||
## 十、VS Code 常用插件汇总
|
||||
|
||||
| 插件名 | 用途 |
|
||||
|--------|------|
|
||||
| Go | Go 语言支持 |
|
||||
| ESLint | JS/TS 代码检查 |
|
||||
| Prettier | 代码格式化 |
|
||||
| GitLens | Git 增强 |
|
||||
| Error Lens | 行内错误提示 |
|
||||
| Thunder Client | API 调试(替代 Postman) |
|
||||
| Todo Tree | 自动收集 TODO/FIXME |
|
||||
| Remote - SSH | SSH 远程开发 |
|
||||
| Docker | Dockerfile / compose 支持 |
|
||||
|
||||
一键批量安装(保存为 `extensions.txt` 后运行 `code --install-extension $(cat extensions.txt)`):
|
||||
|
||||
```text
|
||||
golang.go
|
||||
dbaeumer.vscode-eslint
|
||||
esbenp.prettier-vscode
|
||||
eamodio.gitlens
|
||||
bierner.markdown-preview-github-styles
|
||||
mutantdino.resourcemonitor
|
||||
```
|
||||
|
||||
## 关联笔记
|
||||
- [[weekly/00-week-zero-prep-guide]] — 开营前预习指南(总览)
|
||||
- [[mac-dev-env-setup/homebrew-intro]] — Homebrew 深度指南
|
||||
- [[mac-dev-env-setup/git-ssh-config]] — Git & SSH 双账号路由与排障
|
||||
- [[mac-dev-env-setup/node-nvm-pnpm]] — nvm / Corepack / pnpm 工作原理
|
||||
- [[mac-dev-env-setup/go-module-proxy]] — Go Module 代理链与校验机制
|
||||
- [[mac-dev-env-setup/gh-cli-commands]] — GitHub CLI 常用命令与工作流
|
||||
- [[mac-dev-env-setup/ai-coding-agent]] — AI 编码提示词策略与安全边界
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
tags: [ai, claude-code, dev-env]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# AI Coding Agent 用法指南
|
||||
|
||||
## 概述
|
||||
|
||||
在实训环境中使用 AI 辅助开发的规范化方法:Claude Code 作为首选 Coding Agent,配合 GitHub CLI 等工具形成闭环工作流。重点在于 **提示词工程、权限边界、上下文组织** 三要素。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### Prompting 四原则
|
||||
|
||||
无论使用何种 AI 编码工具,以下原则通用:
|
||||
|
||||
| 原则 | 要点 | 反面示例 |
|
||||
|------|------|---------|
|
||||
| **具体** | 精确到文件名、行号、函数名 | "帮我优化一下登录页面" |
|
||||
| **限定范围** | 明确说"只改什么",不说"改什么" | 无范围约束 → 过度改动 |
|
||||
| **可验证** | 给出预期结果或验收标准 | "让它能跑就行" |
|
||||
| **分步** | 复杂任务拆成小步骤逐步确认 | 一次性描述整个重构 |
|
||||
|
||||
### Claude Code 上下文注入机制
|
||||
|
||||
Claude Code 在启动后会自动收集以下上下文:
|
||||
|
||||
```
|
||||
当前工作目录结构
|
||||
├── CLAUDE.md ← 知识库/项目规范(固定注入)
|
||||
├── .claude/settings.local.json ← 权限配置(可选)
|
||||
├── .gitignore
|
||||
├── src/ ← 当前打开/选中的文件
|
||||
└── ...
|
||||
```
|
||||
|
||||
| 注入方式 | 说明 |
|
||||
|---------|------|
|
||||
| **CLAUDE.md** | 项目级指令,Claude Code 启动时自动加载到 system prompt |
|
||||
| **当前文件** | 你正在查看/编辑的文件自动加入 context |
|
||||
| **选中文本** | 在编辑器选中后用 `@` 引用或直接在对话中使用 |
|
||||
| **文件附件** | 用 `@file` 语法显式追加任意文件到上下文窗口 |
|
||||
|
||||
### CLAUDE.md 模板结构
|
||||
|
||||
```markdown
|
||||
# Project Context
|
||||
|
||||
## 技术栈
|
||||
- Go 1.23 + Gin, Node.js 20 + React 19
|
||||
|
||||
## 代码规范
|
||||
- 错误处理必须 wrapping(fmt.Errorf("failed to X: %w", err))
|
||||
- API handler 命名:HandlerSuffix(CreateUserHandler)
|
||||
|
||||
## 工作流约定
|
||||
- PR 标题格式:type(scope): description(feat(auth): add login endpoint)
|
||||
- 每个 commit 必须是 squash-friendly 的小粒度
|
||||
```
|
||||
|
||||
## 代码示例
|
||||
|
||||
### 典型任务工作流
|
||||
|
||||
#### 场景 1:实现一个 API 接口
|
||||
|
||||
```
|
||||
在 internal/handler/user.go 中增加 GetUserByID handler,
|
||||
只改这一个文件,不要动其他代码。
|
||||
要求:参数绑定使用 gin 的 query binding,错误码使用 pkg/errno 包定义的常量。
|
||||
```
|
||||
|
||||
#### 场景 2:审查已有改动
|
||||
|
||||
```
|
||||
审查刚才的改动(src/auth/middleware.ts),有没有潜在 bug 或性能问题。
|
||||
重点关注:token 过期处理、中间件执行顺序、内存泄漏风险。
|
||||
```
|
||||
|
||||
#### 场景 3:围绕 Issue 工作
|
||||
|
||||
```
|
||||
查看 #42 issue 的描述,创建一个修复分支 fix-42-rate-limit,
|
||||
实现限流逻辑后提交并创建 PR。PR 描述中包含复现步骤和修复说明。
|
||||
```
|
||||
|
||||
### 与 GitHub CLI 组合使用
|
||||
|
||||
```bash
|
||||
# Step 1:查看任务清单
|
||||
gh issue list --state=open --label="internship"
|
||||
|
||||
# Step 2:让 Claude Code 直接在这个上下文中工作
|
||||
# (在 Claude Code 中直接输入上述命令的输出或使用 @)
|
||||
|
||||
# Step 3:完成后再切回来发 PR
|
||||
gh pr create --title "feat(limit): add rate limiter for signup API" \
|
||||
--body "@@projects/rate-limiter-design.md"
|
||||
```
|
||||
|
||||
## 常见陷阱与最佳实践
|
||||
|
||||
### 1. 上下文窗口溢出
|
||||
|
||||
Claude Code 的上下文窗口有限,当项目很大时不要一次性追加太多文件:
|
||||
|
||||
```
|
||||
# ❌ 不好:把整个 src/ 文件夹丢进去
|
||||
@src/*.go
|
||||
|
||||
# ✅ 好:只追加当前文件和相关接口定义
|
||||
@internal/handler/user.go
|
||||
@pkg/errno/code.go
|
||||
```
|
||||
|
||||
需要跨文件理解时,先用 Grep 定位关键词再精准追加。
|
||||
|
||||
### 2. AI 生成代码不直接提交
|
||||
|
||||
AI 生成的代码可能存在 **隐蔽的逻辑错误或安全隐患**,务必经过人工审查:
|
||||
|
||||
```
|
||||
审查流程:
|
||||
1. 让 Claude Code 生成代码 → diff 输出
|
||||
2. 人工阅读 diff,逐行检查
|
||||
3. 如有问题,用自然语言指出("这里少了 nil check")→ 让其修正
|
||||
4. 确认无误后再手动 staged + commit
|
||||
```
|
||||
|
||||
> [!warning] 绝对不要做的事
|
||||
> - 不要信任 AI 生成的数据库 migration SQL 不经 review 就执行
|
||||
> - 不要 trust AI 生成的敏感信息(AK/SK、token)直接 commit
|
||||
> - 不要在 prod 环境让 AI 直接操作
|
||||
|
||||
### 3. Prompt 太长反而降低质量
|
||||
|
||||
一个超过 500 字的 prompt 通常意味着意图不够聚焦。遵循 **STAR 原则**:
|
||||
|
||||
| 元素 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| **S**ituation | 当前背景 | "我在写一个用户注册的 API handler" |
|
||||
| **T**ask | 你要做什么 | "需要加上邮箱验证码校验" |
|
||||
| **A**ction | 具体要求 | "用 Redis SETEX 做 1 分钟有效期,key 前缀 `code:email:`" |
|
||||
| **R**esult | 期望输出 | "返回 Go struct 并在注释中标明 error code" |
|
||||
|
||||
### 4. 利用会话历史进行迭代
|
||||
|
||||
不要试图一次性完美。采用增量反馈循环:
|
||||
|
||||
```
|
||||
第一轮:实现功能 → AI 出代码 → 我 review
|
||||
第二轮:"这个实现有个问题,XX 没处理" → AI 修正
|
||||
第三轮:"再加个单元测试" → AI 补测试
|
||||
第四轮:"把错误处理改为 errors.Is 兼容风格" → AI 微调
|
||||
```
|
||||
|
||||
每轮控制在 2-3 次交互内,超出就停下来自己总结。
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [[mac-dev-env-setup/homebrew-intro]] — Claude Code 安装前置(npm/nvm 环境)
|
||||
- [[CLAUDE.md]] — 本笔记库的 CLAUDE.md 本身就是一个实战范例
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
tags: [github, cli, dev-env]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# GitHub CLI (gh) 命令速查
|
||||
|
||||
## 概述
|
||||
|
||||
`gh` 是 GitHub 官方 CLI,在终端完成 PR、Issue、Fork、Clone 等操作,比浏览器更流畅。它与 Git + Claude Code 组合可以形成完整的高效开发工作流。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install gh
|
||||
|
||||
# 验证
|
||||
gh --version
|
||||
gh auth login # 首次运行,按提示登录 GitHub 账号
|
||||
```
|
||||
|
||||
## Pull Request 操作
|
||||
|
||||
### 查看与筛选
|
||||
|
||||
```bash
|
||||
gh pr list # 当前仓库的 open PR(最近 30 条)
|
||||
gh pr list --state closed # 已关闭的 PR
|
||||
gh pr list --assignee your-user # 分配给自己的 PR
|
||||
|
||||
gh pr status # 自己相关的 PR:当前分支 / 创建过 / 需要你 review
|
||||
```
|
||||
|
||||
### Checkout 到本地
|
||||
|
||||
```bash
|
||||
gh pr checkout 12 # 通过 PR 编号 checkout(自动处理 fork)
|
||||
gh pr checkout patch-2 # 通过分支名 checkout
|
||||
gh pr view 12 # 终端内查看 PR 详情
|
||||
gh pr view 12 --web # 浏览器打开 PR
|
||||
```
|
||||
|
||||
### 创建 PR
|
||||
|
||||
```bash
|
||||
gh pr create # 交互式创建
|
||||
gh pr create --title "feat: add xxx" --body "description"
|
||||
gh pr create --web # 浏览器打开创建页
|
||||
```
|
||||
|
||||
## Issue 操作
|
||||
|
||||
```bash
|
||||
gh issue list # 列出 open issues
|
||||
gh issue list --label bug # 按标签过滤
|
||||
gh issue list --assignee user # 按负责人过滤
|
||||
|
||||
gh issue status # 与你相关的 issues(分配/提及/自己开的)
|
||||
|
||||
gh issue view 42 # 终端查看 issue 详情
|
||||
gh issue view 42 --web # 浏览器打开
|
||||
|
||||
gh issue create # 交互式创建
|
||||
gh issue create --label bug --title "fix: xxx"
|
||||
```
|
||||
|
||||
## Repository 操作
|
||||
|
||||
### Clone
|
||||
|
||||
```bash
|
||||
gh repo clone owner/repo # OWNER/REPO 语法
|
||||
gh repo clone https://github.com/owner/repo # URL 语法
|
||||
```
|
||||
|
||||
### Fork
|
||||
|
||||
```bash
|
||||
# 在已有仓库目录中
|
||||
gh repo fork # 自动 fork + 询问是否添加 remote
|
||||
|
||||
# 跳过 remote 提示
|
||||
gh repo fork --remote=false
|
||||
|
||||
# Fork 后跳过克隆
|
||||
gh repo fork owner/repo --clone=false
|
||||
|
||||
# Fork 时直接克隆
|
||||
gh repo fork owner/repo # 会自动问是否 clone
|
||||
```
|
||||
|
||||
### View
|
||||
|
||||
```bash
|
||||
gh repo view owner/repo # 终端查看仓库信息 + README
|
||||
gh repo view owner/repo --web # 浏览器打开
|
||||
gh repo view # 当前所在仓库
|
||||
```
|
||||
|
||||
## 常见工作流示例
|
||||
|
||||
### Fork → 开发 → 提 PR
|
||||
|
||||
```bash
|
||||
gh repo fork owner/repo # 1. Fork
|
||||
cd repo # 进入目录
|
||||
git checkout -b feature/new-ui # 2. 创建功能分支
|
||||
# ... 编码 ...
|
||||
git commit -m "feat: new ui"
|
||||
git push origin feature/new-ui # 3. 推送
|
||||
gh pr create --title "feat: new UI components" \
|
||||
--body "Closes #42" # 4. 创建 PR
|
||||
```
|
||||
|
||||
### Review 别人提交的 PR
|
||||
|
||||
```bash
|
||||
gh pr checkout 8896 # 1. Checkout 别人的 PR
|
||||
git pull origin patch-2 # 确保最新
|
||||
# ... 审查代码 ...
|
||||
```
|
||||
|
||||
### Claude Code + gh 协作
|
||||
|
||||
```bash
|
||||
gh issue list # 1. 查看任务列表
|
||||
gh issue view 42 # 查看具体需求
|
||||
claude # 2. AI 助手直接在当前分支实现
|
||||
```
|
||||
|
||||
## 参考链接
|
||||
|
||||
- GitHub 官方文档: <https://cli.github.com/>
|
||||
- [[mac-dev-env-setup]] — macOS 开发环境配置总指南
|
||||
- [[mac-dev-env-setup/ai-coding-agent]] — AI Coding Agent 安全边界与提示策略
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
tags: [git, ssh, dev-env]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# Git & SSH 配置
|
||||
|
||||
## 概述
|
||||
|
||||
Git 本地配置、SSH Key 管理与多账户/多主机路由,确保 GitHub 与私有 Gitea 实例能同时免密协作。核心在于 `~/.ssh/config` 文件将不同主机映射到独立的私钥。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### Git 全局配置项速览
|
||||
|
||||
```bash
|
||||
git config --global user.name "hezhaohui"
|
||||
git config --global user.email "hezhaohui0807@163.com"
|
||||
git config --global core.autocrlf input # 写时转 LF,避免 Windows CRLF 混入仓库
|
||||
git config --global init.defaultBranch main # 初始化用 main(不再过时默认的 master)
|
||||
git config --global init.forcedCloneProtocol https # git clone 默认走 HTTPS(可选)
|
||||
```
|
||||
|
||||
> [!info] 查看 / 删除配置
|
||||
> - `git config --global --list` — 列出所有全局设置
|
||||
> - `git config --global --unset user.name` — 删除某项
|
||||
> - `git config --edit --global` — 直接编辑 `~/.gitconfig`
|
||||
|
||||
### SSH Key 为什么需要独立密钥对
|
||||
|
||||
同一个 GitHub / Gitea 账号如果共用一个 SSH Key 是可以的,但 **按服务分 key** 有以下好处:
|
||||
|
||||
| 优势 | 说明 |
|
||||
|------|------|
|
||||
| 隔离风险 | Gitea 服务器如果泄露某个部署密钥(deploy key),不会牵连你的 GitHub 主身份 |
|
||||
| 审计清晰 | 服务端日志中 `Host A uses id_ed25519_github` vs `id_ed25519_gitea`,一眼区分来源 |
|
||||
| 灵活轮换 | 替换 Gitea 密钥不影响 GitHub 已授权的 session |
|
||||
|
||||
### ~/.ssh/config 路由机制
|
||||
|
||||
SSH 客户端在发起连接时会顺序读取 `~/.ssh/config`,**第一个匹配规则生效**。关键指令:
|
||||
|
||||
| 指令 | 作用 |
|
||||
|------|------|
|
||||
| `Host` | 别名(不是真实主机名),匹配 `.git@remote-url` 中的 hostname 部分 |
|
||||
| `HostName` | 真实 DNS 名或 IP |
|
||||
| `Port` | SSH 端口(默认 22) |
|
||||
| `User` | SSH 认证用户名 |
|
||||
| `IdentityFile` | 使用的私钥路径 |
|
||||
| `IdentitiesOnly yes` | 强制只使用指定 key,不尝试系统其他 key |
|
||||
|
||||
示例完整配置:
|
||||
|
||||
```ssh-config
|
||||
Host github.com
|
||||
HostName github.com
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519_github
|
||||
IdentitiesOnly yes
|
||||
|
||||
Host gitea-self
|
||||
HostName 47.121.181.112
|
||||
Port 3000
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519_gitea
|
||||
IdentitiesOnly yes
|
||||
```
|
||||
|
||||
连接测试验证:
|
||||
|
||||
```bash
|
||||
ssh -T git@github.com # Hi hezhaohui! You've successfully authenticated...
|
||||
ssh -T git@gitea-self # logged in as hezhaohui
|
||||
```
|
||||
|
||||
> [!tip] verbose 调试
|
||||
> 遇到 "Permission denied" 时加 `-v` 打印详细握手日志:
|
||||
> ```bash
|
||||
> ssh -Tv git@github.com 2>&1 | grep "Offering"
|
||||
> # 看客户端主动发送了哪个 key、服务端拒绝了哪一个
|
||||
> ```
|
||||
|
||||
## 常见陷阱与最佳实践
|
||||
|
||||
### 1. SSH Config Host 别名必须与实际 URL 一致
|
||||
|
||||
```bash
|
||||
# ❌ 错误:.git 远端仍指向原始地址
|
||||
git remote add origin git@47.121.181.112:3000/user/repo.git
|
||||
|
||||
# ✅ 正确:使用 alias,让 config 中的 Host 匹配
|
||||
git remote add origin git@gitea-self:3000/user/repo.git
|
||||
```
|
||||
|
||||
Git 克隆时的远程 URL 格式为 `git@[Host]:path`,`Host` 必须和 `~/.ssh/config` 里的 `Host` 完全一致才会命中对应的 IdentityFile 规则。
|
||||
|
||||
### 2. Git 的 HTTP 代理干扰 SSH
|
||||
|
||||
如果你设置了 `http.proxy` 或 `https.proxy`,某些工具链可能影响 `ssh` 命令的网络行为。对于 SSH 专用代理(如 proxychains),要排除内网地址:
|
||||
|
||||
```bash
|
||||
# .gitconfig 中排除 Gitea 内网段
|
||||
[url "ssh://git@gitea-self:3000/"]
|
||||
insteadOf = ssh://git@47.121.181.112:3000/
|
||||
```
|
||||
|
||||
### 3. 私钥权限过松导致被拒绝
|
||||
|
||||
```bash
|
||||
chmod 600 ~/.ssh/id_ed25519_gitea
|
||||
chmod 600 ~/.ssh/config # SSH client 也要求 config 不能开放可读
|
||||
```
|
||||
|
||||
OpenSSH 如果检测到私钥文件对其他用户可读写,会直接忽略它——这是最常见的新手踩坑。
|
||||
|
||||
### 4. Ed25519 vs RSA:优先用 Ed25519
|
||||
|
||||
| 算法 | 公钥长度 | 私钥长度 | 安全性 | 速度 |
|
||||
|------|---------|---------|--------|------|
|
||||
| **Ed25519** ✅ | 68 bytes | 68 bytes | 高 | 快 |
|
||||
| RSA 4096 | 968 bytes | ~3 KB | 中高 | 慢 |
|
||||
|
||||
Ed25519 不受 Heartbleed 类漏洞影响,且密钥更小、签名更快。除非服务端明确限制(极老设备),否则一律用 ed25519。
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [[mac-dev-env-setup/homebrew-intro]] — Homebrew 包管理器安装 Git
|
||||
- [[mac-dev-env-setup/node-nvm-pnpm]] — Node.js 环境搭建(后续依赖)
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
tags: [go, module, proxy, dev-env]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# Go Module 代理与依赖管理
|
||||
|
||||
## 概述
|
||||
|
||||
Go Modules 是 Go 自 v1.11 引入的官方依赖管理方案,GOPROXY 环境变量决定了模块下载的来源。国内用户通过配置代理加速拉取,本文深入 Module 体系与代理机制。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### GOPROXY 的工作原理
|
||||
|
||||
```
|
||||
go get ./...
|
||||
│
|
||||
▼
|
||||
GOPROXY 列表依次查询 → 命中第一个返回
|
||||
│ (类似 DNS 回退链)
|
||||
▼
|
||||
缓存到 ~/go/pkg/mod/cache/
|
||||
│
|
||||
▼
|
||||
写入 go.sum(校验哈希)
|
||||
```
|
||||
|
||||
```bash
|
||||
# 默认值(中国大陆不可达)
|
||||
go env GOFLAGS # 应设为空或不设
|
||||
|
||||
# 推荐:阿里 + goproxy.io 备用
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
|
||||
# 也可以指定多个(逗号分隔,从左到右优先级递减)
|
||||
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,https://goproxy.io,direct
|
||||
```
|
||||
|
||||
为什么需要 `direct` 作为兜底?当模块是私有仓库、不在任何公开代理上时,`direct` 告诉 Go 直接通过 VCS(git/svn/hg)从源码仓库拉取。
|
||||
|
||||
### GOSUMDB 校验链
|
||||
|
||||
每个 `go.mod` 旁边都会有一个 `go.sum`,它记录了所有直接和间接依赖的 **模块版本 + 哈希**:
|
||||
|
||||
```bash
|
||||
# 当前 GOSUMDB 设置
|
||||
go env GOSUMDB # sum.golang.org(Google 托管的全球信任根)
|
||||
|
||||
# 离线模式(跳过哈希校验,开发阶段方便但不建议用于 CI)
|
||||
go env -w GONOSUMCHECK=* # 跳过校验
|
||||
go env -w GONOSUMDB=* # 不向 sumdb 请求
|
||||
go env -w GOSUM=off # 完全关闭 sum 检查
|
||||
```
|
||||
|
||||
> [!warning] GONOSUMCHECK vs GONOSUMDB vs GOSUM=off
|
||||
> | 变量 | 效果 | 适用场景 |
|
||||
> |------|------|---------|
|
||||
> | `GONOSUMCHECK=*` | 跳过对 `go.sum` 比对,但仍查询 GOSUMDB | 不推荐使用 |
|
||||
> | `GONOSUMDB=*` | 不向 sum.golang.org 查询,但仍做 local checksum | 自建镜像时使用 |
|
||||
> | `GOSUM=off` | 完全禁用 hash 校验 | 仅限纯本地实验项目 |
|
||||
|
||||
生产环境务必保留 `GOSUMDB=sum.golang.org`,否则无法防御依赖供应链攻击(比如有人往公共 repo 推送恶意版本)。
|
||||
|
||||
### Go Workspace(Go 1.18+)
|
||||
|
||||
当你在本地同时修改多个内部模块时,Go Workspace 可以绕过 GOPROXY,用本地路径解析替代网络下载:
|
||||
|
||||
```bash
|
||||
# 初始化 workspace
|
||||
go work init ./cmd/server ./internal/lib
|
||||
|
||||
# 添加已有模块
|
||||
go work use ./pkg/utils
|
||||
|
||||
# 生成的 go.work 文件
|
||||
cat go.work
|
||||
# go 1.22
|
||||
#
|
||||
# use (
|
||||
# ./cmd/server
|
||||
# ./internal/lib
|
||||
# ./pkg/utils
|
||||
# )
|
||||
```
|
||||
|
||||
Workspace 模式下,`go build` / `go test` 会优先使用 `use` 列表中本地路径对应的模块版本,而非 `GOPROXY` 下载的缓存版本。这在做 monorepo 或多模块协同开发时非常有用。
|
||||
|
||||
### vendor 模式:离线构建
|
||||
|
||||
```bash
|
||||
# 将所有依赖下载到本地 vendor/ 目录
|
||||
go mod vendor
|
||||
|
||||
# 用 vendor 目录构建(完全离线)
|
||||
go build -mod=vendor ./...
|
||||
```
|
||||
|
||||
`vendor/` 会被纳入代码仓库并提交,这样新成员 clone 后即使没有网络也能编译。对比:
|
||||
|
||||
| 方式 | 是否需要网络 | 是否提交 | 适用场景 |
|
||||
|------|-------------|---------|---------|
|
||||
| **Module cache** | 首次需要 | 否(本地磁盘) | 日常开发 |
|
||||
| **vendor/** | 不需要 | 是 | CI/CD、内网隔离 |
|
||||
| **Go Workspace** | 不需要 | 是(go.work) | 多模块本地协同 |
|
||||
|
||||
## 代码示例
|
||||
|
||||
### 批量检查过期依赖
|
||||
|
||||
```bash
|
||||
# 使用 depaware 第三方工具可视化依赖关系并发现重复模块
|
||||
go install github.com/tailscale/depaware@latest
|
||||
depaware --print ./...
|
||||
```
|
||||
|
||||
### 清理未使用的依赖
|
||||
|
||||
```bash
|
||||
# 移除 go.mod 中不再需要的 require 条目
|
||||
go mod tidy
|
||||
|
||||
# 清理本地 module cache 中无人引用的旧版本
|
||||
go clean -modcache # ⚠️ 谨慎使用:会删掉整个 ~/go/pkg/mod/cache
|
||||
```
|
||||
|
||||
`go mod tidy` 的核心逻辑:扫描 `*.go` 文件的 import 路径 → 去 `go.mod` 中查找对应 require → 未被导入且无 build tag 使用的条目会被自动删除,新增的导入会自动添加。
|
||||
|
||||
## 常见陷阱与最佳实践
|
||||
|
||||
### 1. GOPROXY 配错导致 "bad response"
|
||||
|
||||
当代理地址不可达时,Go 会报 403/404/502。排查步骤:
|
||||
|
||||
```bash
|
||||
# 第一步:手动 curl 测试代理健康度
|
||||
curl -i https://goproxy.cn/github.com/aws/aws-sdk-go/@v/v1.45.0.zipinfo
|
||||
|
||||
# 期望:HTTP 200 + 响应体包含 {"Path":"github.com/aws/aws-sdk-go", ...}
|
||||
# 失败:检查代理 URL 是否正确、是否有防火墙拦截
|
||||
```
|
||||
|
||||
阿里云的 `https://mirrors.aliyun.com/goproxy/` 在某些地区更稳定,可切换测试。
|
||||
|
||||
### 2. go.sum 丢失或不同步
|
||||
|
||||
`go.sum` 不应手动编辑。如果不小心修改了导致冲突:
|
||||
|
||||
```bash
|
||||
# 重建 go.sum(基于 go.mod + 当前可用 GOPROXY 重新拉取)
|
||||
rm go.sum
|
||||
go mod download
|
||||
go mod verify # 确认每个依赖的哈希都匹配
|
||||
```
|
||||
|
||||
### 3. 私有仓库需要结合 GOPRIVATE
|
||||
|
||||
```bash
|
||||
# 跳过代理和 sumdb 校验,走 VCS 直接拉取
|
||||
go env -w GOPRIVATE=git.internal.company.com/*
|
||||
```
|
||||
|
||||
> [!tip] GOPRIVATE 与 GOPROXY 的关系
|
||||
> `GOPRIVATE` 模块不走 GOPROXY,也触发 GONOSUMCHECK/GONOSUMDB。如果你只想屏蔽特定域名而不全部关闭校验,可以:
|
||||
> ```bash
|
||||
> go env -w GOPRIVATE=git.internal.company.com
|
||||
> # GOPROXY 仍然走 goproxy.cn,只有匹配的域名例外
|
||||
> ```
|
||||
|
||||
### 4. Module 语义化版本陷阱
|
||||
|
||||
Go Modules 使用 [Semantic Import Versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning):如果一个模块 v2+ 发生了 breaking change,它的 import path 应带上 `/v2` 后缀:
|
||||
|
||||
```
|
||||
# v1.x → import "example.com/foo"
|
||||
# v2.x → import "example.com/foo/v2"
|
||||
```
|
||||
|
||||
很多开源库(如 `gin-gonic/gin`)忽略了这一约定,直接用 `v2.x` 但没有在 import path 上加 `/v2`。这时需要在 `go.mod` 里显式声明:
|
||||
|
||||
```go
|
||||
require github.com/example/broken-module v2.3.4 // indirect
|
||||
// 或用 replace 纠正
|
||||
replace github.com/example/broken-module v2.3.4 => github.com/example/broken-module v2.3.4
|
||||
```
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [[mac-dev-env-setup/homebrew-intro]] — 通过 Homebrew 安装 Go
|
||||
- [[mac-dev-env-setup/git-ssh-config]] — 私有仓库需先配置 SSH Key
|
||||
@@ -0,0 +1,221 @@
|
||||
---
|
||||
tags: [homebrew, macos, package-manager]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# Homebrew — macOS 包管理器
|
||||
|
||||
## 概述
|
||||
|
||||
Homebrew(简称 brew)是 macOS 上最流行的开源包管理工具,弥补了 macOS 缺乏官方包管理器的空白。它通过命令行安装、更新和卸载 Unix 工具和桌面应用,是 Mac 开发环境搭建的第一步。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
/opt/homebrew/ # ARM Mac 安装根目录(M1/M2/M3/M4)
|
||||
├── bin/ # 可执行文件(brew 本身在此)
|
||||
├── Cellar/ # 已安装包的实际存放位置(版本化目录)
|
||||
├── Cask/ # GUI 应用(--cask)的安装元数据
|
||||
├── etc/ # 配置文件
|
||||
├── include/ # C/C++ 头文件
|
||||
├── lib/ # 动态链接库
|
||||
├── opt/ # 当前活跃版本的 symlink 目标
|
||||
├── share/ # 共享资源(man pages, completions 等)
|
||||
└── var/ # 运行时数据
|
||||
|
||||
/usr/local/ # Intel Mac 安装根目录
|
||||
```
|
||||
|
||||
> [!info] Cellar vs Opt
|
||||
> `Cellar/<formula>/<version>` 存储每个版本的实际文件;`opt/<formula>` 是一个 symlink,始终指向当前最新版本。这就是 `brew upgrade` 后不需要重新配置 PATH 的原因。
|
||||
|
||||
### Formula vs Cask
|
||||
|
||||
| 类型 | 用途 | 示例 | 安装路径 |
|
||||
|------|------|------|----------|
|
||||
| **Formula** | CLI 工具和库 | `git`, `go`, `python@3.12` | `/opt/homebrew/Cellar/...` |
|
||||
| **Cask** | GUI 桌面应用 | `visual-studio-code`, `iterm2` | `/Applications/` |
|
||||
|
||||
```bash
|
||||
# Formula 安装
|
||||
brew install git
|
||||
|
||||
# Cask 安装(注意 --cask 或直接用 install,brew v4+ 自动识别)
|
||||
brew install --cask visual-studio-code
|
||||
```
|
||||
|
||||
### Tap —— 第三方仓库
|
||||
|
||||
默认只包含 Homebrew 官方的 core tap(formula + cask)。社区维护的第三方仓库称为 **tap**。
|
||||
|
||||
```bash
|
||||
# 查看已添加的 taps
|
||||
brew taps
|
||||
|
||||
# 添加社区 tap
|
||||
brew tap homebrew/cask-fonts # 字体 cask
|
||||
brew tap darwinports # 假设的第三方 tap
|
||||
|
||||
# 从 tap 安装
|
||||
brew install darwinports/my-tool
|
||||
```
|
||||
|
||||
> [!tip] 常见社区 tap
|
||||
> - `homebrew/cask-fonts` — 大量字体应用
|
||||
> - `homebrew/core` 和 `homebrew/cask` 默认已添加
|
||||
> - 添加前用 `brew search <name>` 确认是否在官方源中,避免不必要的 tap
|
||||
|
||||
## 代码示例
|
||||
|
||||
### 安装与初始化
|
||||
|
||||
```bash
|
||||
# 一键安装脚本
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
|
||||
# ARM Mac:将 brew 加入 shell profile
|
||||
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
|
||||
# Intel Mac
|
||||
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
`brew shellenv` 会输出需要注入到 shell 中的环境变量(PATH、MANPATH、CGO_CFLAGS 等),`eval` 将其应用到当前环境。
|
||||
|
||||
### 常用工作流
|
||||
|
||||
```bash
|
||||
# 搜索包(formula + cask)
|
||||
brew search neovim
|
||||
|
||||
# 查看详情(版本、依赖、安装数)
|
||||
brew info neovim
|
||||
|
||||
# 安装
|
||||
brew install neovim
|
||||
|
||||
# 指定版本(需先用 brew versions 或查 formula history)
|
||||
brew install neovim@0.9
|
||||
|
||||
# 升级
|
||||
brew upgrade # 升级所有可升级的包
|
||||
brew upgrade neovim # 只升级某个包
|
||||
|
||||
# 清理磁盘空间
|
||||
brew cleanup # 删除旧版本缓存
|
||||
brew cleanup --prune # 同时清理孤立 symlink
|
||||
|
||||
# 诊断
|
||||
brew doctor # 检查环境问题
|
||||
brew config # 查看当前配置信息
|
||||
```
|
||||
|
||||
### 管理依赖
|
||||
|
||||
```bash
|
||||
# 查看某包的依赖树
|
||||
brew deps --tree git
|
||||
|
||||
# 查看哪些包依赖某包(反向查询)
|
||||
brew depends --tag python@3.12
|
||||
|
||||
# 列出已安装的包
|
||||
brew list
|
||||
|
||||
# 列出可卸载的孤立依赖(无人引用)
|
||||
brew autoremove
|
||||
```
|
||||
|
||||
> [!warning] autoremove 不会删除你显式安装的包
|
||||
> 只有那些因满足其他包的依赖而被自动安装、且当前不再被任何包需要的依赖才会被移除。
|
||||
|
||||
### 源码编译自定义参数
|
||||
|
||||
```bash
|
||||
# 查看可用选项
|
||||
brew options curl
|
||||
|
||||
# 安装时启用特定 flag
|
||||
brew install curl --with-openssl
|
||||
|
||||
# 或者编辑 formula 后再安装(bottle 会被跳过)
|
||||
brew edit curl # 打开本地 formula 副本
|
||||
brew install curl
|
||||
```
|
||||
|
||||
`brew edit <formula>` 会在本地创建一个公式副本,适合临时修改编译参数,但升级时会提示冲突。
|
||||
|
||||
## 常见陷阱与最佳实践
|
||||
|
||||
### 1. PATH 优先级问题
|
||||
|
||||
macOS 系统自带的工具(如 `/usr/bin/python3`)可能比 brew 安装的更早出现在 PATH 中。确保 brew 路径在 `/usr/local/bin` 或 `/opt/homebrew/bin` 之前:
|
||||
|
||||
```bash
|
||||
echo $PATH
|
||||
# 期望顺序:/opt/homebrew/bin:...(在 /usr/bin 之前)
|
||||
```
|
||||
|
||||
> [!tip] 验证方法
|
||||
> 运行 `which git` 应输出 `/opt/homebrew/bin/git`(ARM)或 `/usr/local/bin/git`(Intel),而非 `/usr/bin/git`。
|
||||
|
||||
### 2. Permission Denied 不要用 sudo
|
||||
|
||||
```bash
|
||||
# ❌ 错误做法
|
||||
sudo brew install git # 会破坏 ownership,导致后续操作全部报错
|
||||
|
||||
# ✅ 正确做法
|
||||
chown -R $(whoami) $(brew --prefix)/* # 修复权限后重试
|
||||
```
|
||||
|
||||
brew 设计的初衷就是用户级别使用,使用 `sudo` 会改变 `/opt/homebrew` 下文件的 owner,引发连锁问题。如果误用了 `sudo brew`,用上面的命令修复即可。
|
||||
|
||||
### 3. 大版本升级后的迁移
|
||||
|
||||
```bash
|
||||
# Homebrew v4 (2023+) 要求先运行迁移命令
|
||||
brew update
|
||||
brew doctor # 检查是否需要迁移
|
||||
brew bump-formula-pr --arch ... # 通常无需手动干预
|
||||
```
|
||||
|
||||
### 4. 离线环境 / 国内网络优化
|
||||
|
||||
中国大陆用户安装和下载可能较慢,可以通过设置镜像源加速:
|
||||
|
||||
```bash
|
||||
# Git 仓库镜像(可选,通常无需设置,brew 官方源在国内访问正常)
|
||||
# 替换为清华大学镜像
|
||||
git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
|
||||
|
||||
# pip / npm 等有专门的镜像配置方式,这里不展开
|
||||
```
|
||||
|
||||
### 5. Bottle vs Build from Source
|
||||
|
||||
brew 默认优先下载预编译的 **bottle**(二进制包),速度远快于从源码编译。某些特殊架构或定制需求时才需要从源码构建:
|
||||
|
||||
```bash
|
||||
# 强制从源码编译(跳过 bottle)
|
||||
brew install --build-from-source curl
|
||||
```
|
||||
|
||||
### 6. 公式维护约定
|
||||
|
||||
brew formula 采用 "one version at a time" 策略——`brew install git` 只装最新稳定版,不保留历史版本。如果需要多版本共存(类似 nvm for Node),推荐:
|
||||
|
||||
- Go → 用 `gvm` 或通过 golang.org/dl 官网安装
|
||||
- Python → `pyenv` 配合 `brew install pyenv`
|
||||
- Node.js → `nvm`(已在本环境的 Node 章节覆盖)
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [Homebrew 官方文档](https://docs.brew.sh)
|
||||
- [[projects/mac-dev-env-setup]] — macOS 开发环境总指南
|
||||
- [[technical/go]] — Go 语言环境配置
|
||||
- [[technical/nodejs]] — Node.js 与 pnpm 配置
|
||||
@@ -0,0 +1,208 @@
|
||||
---
|
||||
tags: [nodejs, nvm, pnpm, dev-env]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# Node.js + nvm + pnpm 详解
|
||||
|
||||
## 概述
|
||||
|
||||
Node.js 开发环境中版本管理和包管理的核心链路:nvm 控制运行时版本、Corepack 提供标准化的包管理器入口、pnpm 以高效磁盘模型取代传统的 flat install。三者配合形成完整的 JS/TS 工程基础。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### nvm 版本管理机制
|
||||
|
||||
nvm(Node Version Manager)的核心设计是通过 shell 函数劫持 `node` / `npm` / `npx` 命令:
|
||||
|
||||
```bash
|
||||
# nvm 工作原理示意
|
||||
which node
|
||||
# → $(nvm_alias)/versions/node/*/bin/node ← 实际是符号链接
|
||||
# ↑ 由 nvm 动态切换
|
||||
```
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
|------|------|------|
|
||||
| 安装 LTS | `nvm install --lts` | 自动检测最新 Long Term Support 版本 |
|
||||
| 切换版本 | `nvm use <version>` | 修改 `.nvmrc` 或版本号 |
|
||||
| 查看已装 | `nvm ls` | 列出版本树 |
|
||||
| 设置默认 | `nvm alias default 20` | 每次打开终端自动激活 |
|
||||
| 全局包复用 | `--reinstall-packages-from=<version>` | 切换时迁移全局包 |
|
||||
|
||||
```bash
|
||||
# 在项目根目录创建 .nvmrc
|
||||
echo "20" > .nvmrc
|
||||
|
||||
# nvm use 不加版本号时自动读 .nvmrc
|
||||
cd my-project && nvm use
|
||||
# → Found '/path/to/my-project/.nvmrc' with version <20>
|
||||
# → Now using Node.js v20.18.0
|
||||
```
|
||||
|
||||
> [!tip] nvm 与 corepack 的交互
|
||||
> `corepack prepare pnpm@latest --activate` 安装的是 `corepack` 自己,nvm 切换 Node 版本后,corepack 依然存在——因为它是随 Node.js bundled 的(Node ≥ 16.13)。这意味着 **不需要** 在切换 Node 版本后重新安装 corepack。
|
||||
|
||||
### Corepack 的作用
|
||||
|
||||
Corepack 是 Node.js 官方提供的零开销包管理器调度器,从 Node v16.13 起内置:
|
||||
|
||||
```bash
|
||||
# Corepack 支持的包管理器
|
||||
corepack enable # 注册 pnpm / yarn / npm 的 shim 入口
|
||||
corepack prepare pnpm@latest --activate # 锁定 pnpm 版本
|
||||
|
||||
# 查看 corepack 管理的版本
|
||||
corepack --version
|
||||
corepack --enable
|
||||
```
|
||||
|
||||
核心思想:**让团队统一使用包管理器版本,而非各自在全局安装不同版本的 npm/yarn/pnpm。**
|
||||
|
||||
```bash
|
||||
# 项目中可指定 pnpm 版本
|
||||
echo "pnpm@8.15.0" > .npmrc # Corepack 读取
|
||||
|
||||
# 或直接通过 package.json
|
||||
# (package.json 中添加 "packageManager": "pnpm@8.15.0")
|
||||
```
|
||||
|
||||
CI 跑 `corepack enable` 即可自动下载指定版本,无需额外安装步骤。
|
||||
|
||||
### pnpm 的存储模型
|
||||
|
||||
pnpm 最核心的创新在于 **硬链接 + 内容寻址存储**,解决了 npm/yarn 的两个经典问题:
|
||||
|
||||
1. **磁盘浪费**:npm 在每个 node_modules 下复制依赖副本
|
||||
2. **隐形依赖**:flat tree 结构中子包能意外访问父包的依赖
|
||||
|
||||
```
|
||||
传统 npm 安装(flat tree,symlink 树)
|
||||
project-A/node_modules/
|
||||
├── lodash/ ← symlink -> project-A/node_modules/lodash
|
||||
├── express/ ← symlink -> project-A/node_modules/express
|
||||
│ └── node_modules/
|
||||
│ └── qs/ ← 可能被 project-B 重复安装
|
||||
|
||||
pnpm 安装(strict 模式)
|
||||
pnpm-store/
|
||||
├── .stores/v8/
|
||||
│ └── abc123/ ← 内容哈希索引,全局唯一
|
||||
│ ├── lodash.tgz
|
||||
│ └── express.tgz
|
||||
project-A/node_modules/
|
||||
├── lodash/ ← hard link (硬链接) → .stores/v8/abc123/lodash.tgz
|
||||
├── express/ ← hard link → .stores/v8/abc123/express.tgz
|
||||
└── .pnpm/
|
||||
└── express@4.x/ ← nested symlink 满足 express 自身的 require('qs')
|
||||
```
|
||||
|
||||
**硬链接的优势**:同样的文件在磁盘上只存一份,`node_modules` 中的硬链接不占用额外空间;而 symlink 在 Windows 上需要管理员权限才能创建。
|
||||
|
||||
> [!warning] Windows 上的 pnpm
|
||||
> Windows 10+ 支持硬链接,但默认可能需要开启"开发者模式"。如果遇到 permission denied,以管理员身份运行终端,或在系统设置中启用开发者模式。
|
||||
|
||||
### pnpm workspace(Monorepo 支持)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-monorepo",
|
||||
"private": true,
|
||||
"workspaces": ["packages/*"]
|
||||
}
|
||||
```
|
||||
|
||||
workspace 模式下,同仓库内的包互相引用时直接使用硬链接,无需 publish:
|
||||
|
||||
```bash
|
||||
cd packages/shared && pnpm add ../libs/core
|
||||
# 等价于在 shared 的 package.json 中写了 "core": "link:../libs/core"
|
||||
```
|
||||
|
||||
## 代码示例
|
||||
|
||||
### 项目级 .npmrc 推荐配置
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
auto-install-peers=true
|
||||
side-effects-cache=true # 缓存 noSideEffects=true 的包,加快安装
|
||||
shamefully-hoist=false # 禁止非 hoist 提升到顶层
|
||||
strict-peer-dependencies=true # peerDependency 缺失时报错而非警告
|
||||
```
|
||||
|
||||
### 快速诊断 node_modules 大小
|
||||
|
||||
```bash
|
||||
# macOS/Linux
|
||||
du -sh node_modules/
|
||||
|
||||
# 找出最大的前 10 个包
|
||||
pnpm why --recursive | head -20
|
||||
```
|
||||
|
||||
## 常见陷阱与最佳实践
|
||||
|
||||
### 1. nvm 与 Node.js 全局 CLI 丢失
|
||||
|
||||
切换 Node 版本后,之前在全局安装的 CLI 工具(如 `typescript`、`eslint`)不再可用,因为每个 Node 版本有独立的全局目录:
|
||||
|
||||
```bash
|
||||
# 切换时保留全局包(仅同大版本间安全)
|
||||
nvm use 20 --reinstall-packages-from=18
|
||||
|
||||
# 或者通用做法:CLI 工具放在工作区 root 的 devDependencies 中
|
||||
pnpm add -D typescript eslint
|
||||
npx tsc --version # 始终能用
|
||||
```
|
||||
|
||||
> [!tip] 黄金法则:CLI 工具不进 global,进 devDependencies
|
||||
> 所有团队工具的版本应该锁在 `package.json` 中,通过 `npx <tool>` 调用。这是避免"我的能跑你不行"问题的最根本策略。
|
||||
|
||||
### 2. Corepack 版本冲突
|
||||
|
||||
如果你的团队中有成员安装了独立的全局 pnpm,会与 Corepack 冲突:
|
||||
|
||||
```bash
|
||||
# 检查当前 pnpm 来源
|
||||
which pnpm
|
||||
# → 应该是:$(corepack_dir)/pnpm → .corepack/pnpm → 目标二进制
|
||||
|
||||
# 卸载独立安装的全局 pnpm
|
||||
npm uninstall -g pnpm
|
||||
|
||||
# 重新用 corepack 激活
|
||||
corepack enable
|
||||
corepack prepare pnpm@latest --activate
|
||||
```
|
||||
|
||||
### 3. pnpm store 膨胀
|
||||
|
||||
pnpm 的内容寻址存储在反复安装/删除不同版本后会产生碎片:
|
||||
|
||||
```bash
|
||||
# 清理未被任何 package.json 引用过的 store 条目
|
||||
pnpm store prune
|
||||
|
||||
# 定期检查 store 大小
|
||||
du -sh $(pnpm store path)
|
||||
```
|
||||
|
||||
建议每月执行一次 `pnpm store prune`,通常能释放数 GB 空间。
|
||||
|
||||
### 4. pnpm 与 Native Addon
|
||||
|
||||
带有 C++ 原生编译绑定的包(如 `sharp`、`bcrypt`)在 pnpm 环境下有时会因为找不到头文件路径而编译失败:
|
||||
|
||||
```bash
|
||||
# 临时关闭 strict-deps 解决 header 路径问题
|
||||
pnpm install --strict-peer-dependencies=false
|
||||
|
||||
# 长期方案:在 package.json 中声明正确的 dependencies 层级
|
||||
```
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [[mac-dev-env-setup/homebrew-intro]] — 通过 Homebrew 安装 nvm
|
||||
- [[mac-dev-env-setup/git-ssh-config]] — SSH 配置(用于 git clone private repos)
|
||||
- [[mac-dev-env-setup/go-module-proxy]] — Go 生态的依赖管理对比参考
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
tags: [onboarding, week-zero]
|
||||
create time: 2026-07-01 00:00
|
||||
---
|
||||
|
||||
# 第零周 · 开营前预习指南
|
||||
|
||||
## 概述
|
||||
|
||||
七牛云暑期实习 MS0(开营前)准备清单,涵盖账号与协作基础、开发环境、AI Coding Agent 三大模块,确保开营第一天即可直接上手项目,而非从零摸索工具。
|
||||
|
||||
## 一、账号与协作基础
|
||||
|
||||
### GitHub 账号
|
||||
- 注册 GitHub 账号,提交 ID 并填写表单:<https://wj.qq.com/s2/27190567/04b8/>
|
||||
- 收到邀约通知后,加入实训营 GitHub 组织
|
||||
- 配置 SSH key,确保本地能免密 push
|
||||
- ~~验收✅~~ 完成状态待定
|
||||
|
||||
> [!info] 备注
|
||||
> Git 操作、commit 规范、PR、Fork 同步等协作流程开营后在真实项目中实践,不作开营前强制要求。
|
||||
|
||||
## 二、开发环境
|
||||
|
||||
配置时机:入职当天发放办公电脑,届时安装;希望提前熟悉也可先在个人电脑上试装。详细步骤见 [[technical/mac-dev-env-setup]](含 Homebrew → Git → Node/Go/AI Agent 完整指南)。
|
||||
|
||||
### Node.js
|
||||
- 用 nvm 管理版本,安装一个 LTS 版本
|
||||
- 包管理器用 pnpm
|
||||
- 验证:`node -v`、`pnpm -v` 正常输出
|
||||
|
||||
### TypeScript
|
||||
- 安装 TypeScript
|
||||
- 验证:`tsc -v` 正常输出
|
||||
|
||||
### Go
|
||||
- 安装 Go,配置 GOPROXY 国内代理加速依赖拉取([goproxy.cn](https://goproxy.cn/))
|
||||
- 验证:`go version`、`go env GOPROXY` 正常
|
||||
|
||||
### 其他
|
||||
- 代码编辑器(推荐 VS Code)及常用插件
|
||||
- 终端与 Git
|
||||
|
||||
## 三、AI Coding Agent
|
||||
|
||||
实训允许并鼓励使用 AI 辅助开发,但 AI 服务于工程流程,不绕开设计、Review 和测试。
|
||||
|
||||
### 基本用法
|
||||
- 安装并跑通一个 Coding Agent(如 Claude Code、Codex 等)
|
||||
- 熟悉:基于明确任务下发指令、限定改动范围、阅读并检查生成结果
|
||||
- 配置 GitHub CLI,使 Agent 能围绕 Issue / PR 工作(查看 Issue、创建分支、提交 PR、补充 PR 描述)
|
||||
|
||||
## 四、打卡清单
|
||||
|
||||
逐项确认完成情况:
|
||||
|
||||
- [ ] GitHub 账号已注册并加入组织,SSH key 配置完成(✅ 表单已提交,待邀约)
|
||||
- [ ] Node(nvm + pnpm)配置完成并验证
|
||||
- [ ] Go(GOPROXY)配置完成并验证
|
||||
- [ ] 跑通至少一个 Coding Agent,配置好 GitHub CLI
|
||||
|
||||
## 关联笔记
|
||||
- [[technical/mac-dev-env-setup]] — macOS 开发环境详细配置指南
|
||||
Reference in New Issue
Block a user