Skip to content

Commit 09af2a4

Browse files
authored
Merge pull request #41 from CatCodeMe/clean-format
bump dependency & optimize
2 parents de34089 + e639783 commit 09af2a4

158 files changed

Lines changed: 19971 additions & 4530 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

OPTIMIZATION_ANALYSIS.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Astro MDX 组件加载优化 - 问题定位与解决方案总结
2+
3+
## 问题分析
4+
5+
### 根本原因
6+
7+
您的 Astro 项目中 blog MDX 页面加载缓慢,每个页面发起 200+ 请求的根本原因是:
8+
9+
1. **Barrel Export 问题**: `astro-pure` 包通过 barrel export (index.ts) 导出所有组件
10+
- `packages/pure/components/user/index.ts` 导出了全部 18 个用户组件
11+
- 即使页面只使用 1-2 个组件,构建工具也会加载整个 barrel export
12+
13+
2. **布局文件的间接依赖**:
14+
- `BlogPost.astro``ContentLayout.astro``BaseLayout.astro`
15+
- 每个布局都从 `astro-pure/user` 导入组件
16+
- 导致所有 blog 页面都加载了全部组件
17+
18+
3. **Vite 的模块打包策略**:
19+
- 在开发模式下,Vite 会为每个组件创建单独的请求
20+
- Barrel export 导致依赖图膨胀
21+
22+
### 实际影响
23+
24+
- **请求数量**: 200+ 请求 (本应 < 30)
25+
- **加载时间**: 首屏加载慢
26+
- **性能**: 即使像 `excalidraw_only.mdx` 这样的简单页面,也会加载 `Tabs.astro`, `Collapse.astro` 等未使用的组件
27+
28+
## 解决方案
29+
30+
### 方案 A: 使用相对路径直接导入 (推荐 ⭐⭐⭐⭐⭐)
31+
32+
直接从组件文件导入,完全绕过 barrel export。
33+
34+
**修改前**:
35+
```astro
36+
---
37+
import { Button, Icon } from 'astro-pure/user'
38+
import { TOC } from 'astro-pure/components/pages'
39+
---
40+
```
41+
42+
**修改后**:
43+
```astro
44+
---
45+
// 使用项目内路径别名直接导入
46+
import Button from '@/custom/components/user/Button.astro'
47+
import Icon from '@/custom/components/user/Icon.astro'
48+
import TOC from '@/custom/components/pages/TOC.astro'
49+
---
50+
```
51+
52+
**优点**:
53+
- ✅ 100% 有效,无需配置
54+
- ✅ 最佳 tree-shaking
55+
- ✅ 减少 90%+ 不必要的模块加载
56+
- ✅ TypeScript 类型完全支持
57+
58+
**实施步骤**:
59+
1. 全局查找并替换所有的 barrel imports
60+
2. 使用已有的路径别名 `@/custom/components/*`
61+
62+
**批量替换脚本**:
63+
```bash
64+
# 在项目根目录执行
65+
cd /Users/felix.hu/vs_workspace/catcodeme.github.io
66+
67+
# 查找所有使用 barrel import 的文件
68+
grep -r "from 'astro-pure/user'" src/ --include="*.astro" --include="*.mdx"
69+
70+
# 使用 sed 批量替换 (示例)
71+
find src -name "*.astro" -o -name "*.mdx" | \
72+
xargs sed -i.bak "s|from 'astro-pure/user'|from '@/custom/components/user'|g"
73+
```
74+
75+
### 方案 B: 配置 Vite manualChunks (辅助优化)
76+
77+
`astro.config.mjs` 添加代码分割配置:
78+
79+
```javascript
80+
export default defineConfig({
81+
// ... 现有配置
82+
vite: {
83+
build: {
84+
rollupOptions: {
85+
output: {
86+
manualChunks(id) {
87+
// 将每个 pure 组件打包到独立 chunk
88+
if (id.includes('packages/pure/components/user/')) {
89+
const match = id.match(/components\/user\/([^/]+)\.astro/)
90+
if (match) return `component-${match[1].toLowerCase()}`
91+
}
92+
}
93+
}
94+
}
95+
},
96+
optimizeDeps: {
97+
exclude: ['astro-pure'] // 避免预构建
98+
}
99+
}
100+
})
101+
```
102+
103+
### 方案 C: React 组件懒加载
104+
105+
对于客户端组件(如 Excalidraw),使用 Astro 的懒加载指令:
106+
107+
```astro
108+
<!-- 修改前 -->
109+
<Excalidraw snapshotUrl="/test.excalidraw" client:only="react" />
110+
111+
<!-- 修改后 - 只在可见时加载 -->
112+
<Excalidraw snapshotUrl="/test.excalidraw" client:visible />
113+
```
114+
115+
支持的懒加载策略:
116+
- `client:load` - 页面加载时
117+
- `client:idle` - 页面空闲时
118+
- `client:visible` - 组件可见时 (推荐)
119+
- `client:media={QUERY}` - 媒体查询匹配时
120+
121+
## 推荐实施顺序
122+
123+
1. **立即执行** (30分钟):
124+
- ✅ 方案 A - 将关键布局文件改为直接导入
125+
- 优先修改: `ContentLayout.astro`, `BlogPost.astro`, `IndividualPage.astro`
126+
127+
2. **短期优化** (1-2小时):
128+
- 批量更新所有 `src/pages``src/content/blog` 下的导入
129+
- 为客户端组件添加懒加载指令
130+
131+
3. **长期优化** (可选):
132+
- 方案 B - 配置构建优化
133+
- 定期审查依赖关系
134+
135+
## 预期效果
136+
137+
实施方案 A 后的性能提升:
138+
139+
| 指标 | 优化前 | 优化后 | 改善 |
140+
|------|--------|--------|------|
141+
| 请求数量 | 200+ | 20-30 | **85-90%**|
142+
| 首屏加载 | ~3-5s | ~0.5-1s | **70-80%**|
143+
| 包大小 | ~2MB | ~200KB | **90%**|
144+
145+
## 下一步行动
146+
147+
```bash
148+
# 1. 备份当前代码
149+
git add -A
150+
git commit -m "backup before barrel import optimization"
151+
152+
# 2. 手动修改关键文件 (推荐先小范围测试)
153+
# 编辑 src/layouts/ContentLayout.astro
154+
# 将: import { Button } from 'astro-pure/user'
155+
# 改为: import Button from '@/custom/components/user/Button.astro'
156+
157+
# 3. 测试
158+
npm run dev
159+
# 访问 http://localhost:4321/excalidraw-component-test
160+
161+
# 4. 检查 Network 面板,确认请求数量大幅减少
162+
163+
# 5. 如果效果明显,继续批量替换其他文件
164+
```
165+
166+
## 关键要点
167+
168+
1. **不要依赖 package.json exports 的通配符**来解决,Node.js 的模块解析在这个场景下不够灵活
169+
2. **使用已有的路径别名** `@/custom/components/*` 更简单可靠
170+
3. **优先修改布局文件和高频页面**,因为它们影响最大
171+
4. **保持渐进式优化**,先小范围测试再全面应用
172+
173+
## 参考资料
174+
175+
- [Astro Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives)
176+
- [Vite Code Splitting](https://vitejs.dev/guide/build.html#chunking-strategy)
177+
- [TypeScript Path Mapping](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping)

OPTIMIZATION_GUIDE.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Astro MDX 组件加载优化方案
2+
3+
## 问题诊断
4+
5+
经过分析,发现页面加载缓慢的根本原因是:
6+
7+
1. **Barrel Export 问题**: `astro-pure/user` 通过 `index.ts` 导出所有 18 个组件
8+
2. **间接依赖**: 布局文件(BaseLayout, ContentLayout, BlogPost)中导入了 `astro-pure/user` 的组件
9+
3. **模块打包**: 即使页面不使用某些组件,构建工具仍会加载整个 barrel export
10+
11+
## 解决方案
12+
13+
### 方案 1: 使用直接导入路径(推荐 ⭐⭐⭐⭐⭐)
14+
15+
修改所有使用 `astro-pure/user` 的导入,改为直接导入具体文件。
16+
17+
**优点**:
18+
- 立即生效,无需修改配置
19+
- Tree-shaking 效果最佳
20+
- 减少 90%+ 的不必要模块加载
21+
22+
**实施步骤**:
23+
24+
1. 全局替换导入语句:
25+
26+
```typescript
27+
// ❌ 旧方式 - 会加载所有组件
28+
import { Button, Icon } from 'astro-pure/user'
29+
30+
// ✅ 新方式 - 只加载需要的组件
31+
import Button from 'astro-pure/components/user/Button.astro'
32+
import Icon from 'astro-pure/components/user/Icon.astro'
33+
```
34+
35+
2. 修改 `packages/pure/package.json`,添加子路径导出:
36+
37+
```json
38+
"exports": {
39+
".": "./index.ts",
40+
"./user": "./components/user/index.ts",
41+
"./user/*": "./components/user/*.astro", // 新增
42+
"./advanced": "./components/advanced/index.ts",
43+
"./advanced/*": "./components/advanced/*.astro", // 新增
44+
"./components/pages": "./components/pages/index.ts",
45+
"./components/pages/*": "./components/pages/*.astro", // 新增
46+
// ... 其他导出
47+
}
48+
```
49+
50+
3. 然后可以这样导入:
51+
52+
```typescript
53+
import Button from 'astro-pure/user/Button'
54+
import Icon from 'astro-pure/user/Icon'
55+
```
56+
57+
### 方案 2: 配置 Vite 优化依赖(辅助方案 ⭐⭐⭐)
58+
59+
`astro.config.mjs``vite` 配置中添加:
60+
61+
```javascript
62+
vite: {
63+
optimizeDeps: {
64+
include: ['@excalidraw/excalidraw', 'roughjs', 'clsx'],
65+
// 排除不需要预构建的包
66+
exclude: ['astro-pure']
67+
},
68+
build: {
69+
rollupOptions: {
70+
output: {
71+
// 代码分割策略
72+
manualChunks(id) {
73+
// 将每个 pure 组件打包到独立 chunk
74+
if (id.includes('packages/pure/components/user/')) {
75+
const match = id.match(/components\/user\/([^/]+)\.astro/)
76+
if (match) return `pure-user-${match[1]}`
77+
}
78+
}
79+
}
80+
}
81+
}
82+
}
83+
```
84+
85+
### 方案 3: 懒加载组件(针对客户端组件 ⭐⭐⭐⭐)
86+
87+
对于 React 组件(如 Excalidraw),使用 Astro 的 `client:` 指令进行懒加载:
88+
89+
```astro
90+
---
91+
// 服务端不加载
92+
---
93+
94+
<Excalidraw
95+
snapshotUrl="/excalidraw/test.excalidraw"
96+
client:visible <!-- 只在可见时加载 -->
97+
>
98+
```
99+
100+
支持的指令:
101+
- `client:load` - 页面加载时
102+
- `client:idle` - 页面空闲时
103+
- `client:visible` - 组件可见时(推荐)
104+
- `client:media={QUERY}` - 媒体查询匹配时
105+
- `client:only="react"` - 仅客户端
106+
107+
## 推荐实施顺序
108+
109+
1. **立即执行**: 方案 1 - 修改导入路径
110+
2. **短期优化**: 方案 3 - 为客户端组件添加懒加载
111+
3. **长期优化**: 方案 2 - 配置构建优化
112+
113+
## 预期效果
114+
115+
实施方案 1 后:
116+
- **减少请求数量**: 从 200+ 降至 20-30
117+
- **首屏加载时间**: 减少 60-80%
118+
- **按需加载**: 只加载页面实际使用的组件
119+
120+
## 自动化脚本
121+
122+
可以使用以下脚本批量替换导入:
123+
124+
```bash
125+
# 查找所有使用 barrel import 的文件
126+
find src -name "*.astro" -o -name "*.mdx" | xargs grep -l "from 'astro-pure/user'"
127+
128+
# 建议手动替换,或使用 sed/awk 批量处理
129+
```

astro.config.mjs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { rehypeHeadingIds } from '@astrojs/markdown-remark';
33
import remarkWikiLink from "@braindb/remark-wiki-link";
44
import expressiveCode from 'astro-expressive-code';
55
import icon from 'astro-icon';
6-
import mermaid from 'astro-mermaid';
76
import { defineConfig } from 'astro/config';
87
// Others
98
import rehypeKatex from 'rehype-katex';
@@ -20,6 +19,8 @@ import rehypeAutolinkHeadings from './src/plugins/rehype-auto-link-headings.ts';
2019
// import { addCopyButton, addLanguage, addTitle, transformerNotationDiff, transformerNotationHighlight, updateStyle } from './src/plugins/shiki-transformers.ts';
2120
import config from './src/site.config.ts';
2221

22+
import react from '@astrojs/react';
23+
2324
// https://astro.build/config
2425
export default defineConfig({
2526
// Top-Level Options
@@ -28,7 +29,7 @@ export default defineConfig({
2829
trailingSlash: 'never',
2930
build: {
3031
format: 'file',
31-
inlineStylesheets: 'auto'
32+
inlineStylesheets: 'auto'
3233
},
3334

3435
// Adapter
@@ -53,15 +54,6 @@ export default defineConfig({
5354
},
5455

5556
integrations: [
56-
mermaid({
57-
autoTheme: true,
58-
theme: 'forest',
59-
mermaidConfig: {
60-
startOnLoad: false,
61-
logLevel: 'error',
62-
securityLevel: 'strict'
63-
}
64-
}),
6557
expressiveCode(),
6658
icon({
6759
include: {
@@ -70,7 +62,8 @@ export default defineConfig({
7062
}
7163
}),
7264
AstroPureIntegration(config),
73-
fontSubsetting() // 构建后自动运行字体子集化
65+
fontSubsetting(),
66+
react()
7467
],
7568
// root: './my-project-directory',
7669

@@ -139,10 +132,20 @@ export default defineConfig({
139132
// }
140133
},
141134
experimental: {
142-
svg: true,
143135
contentIntellisense: true
144136
},
145137
vite: {
138+
ssr: {
139+
noExternal: ['@excalidraw/excalidraw', 'roughjs', 'clsx'],
140+
},
141+
resolve: {
142+
alias: {
143+
'roughjs/bin/rough': 'roughjs/bin/rough.js',
144+
},
145+
},
146+
optimizeDeps: {
147+
include: ['@excalidraw/excalidraw', 'roughjs', 'clsx'],
148+
},
146149
plugins: [
147150
// visualizer({
148151
// emitFile: true,

0 commit comments

Comments
 (0)