@tinkcarlos/skillora 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/.temp-skill-index.md +245 -0
- package/.claude/skills/SKILL.md +264 -0
- package/.claude/skills/api-scaffolding/SKILL.md +431 -0
- package/.claude/skills/api-scaffolding/agents/backend-architect.md +282 -0
- package/.claude/skills/api-scaffolding/agents/django-pro.md +144 -0
- package/.claude/skills/api-scaffolding/agents/fastapi-pro.md +156 -0
- package/.claude/skills/api-scaffolding/agents/graphql-architect.md +146 -0
- package/.claude/skills/api-scaffolding/skills/fastapi-templates/SKILL.md +171 -0
- package/.claude/skills/api-testing-observability/SKILL.md +583 -0
- package/.claude/skills/api-testing-observability/agents/api-documenter.md +146 -0
- package/.claude/skills/api-testing-observability/commands/api-mock.md +1320 -0
- package/.claude/skills/brainstorming/SKILL.md +283 -0
- package/.claude/skills/bug-fixing/SKILL.md +382 -0
- package/.claude/skills/bug-fixing/references/backend-guide.md +132 -0
- package/.claude/skills/bug-fixing/references/bug-guide.md +354 -0
- package/.claude/skills/bug-fixing/references/bug-record-template.md +134 -0
- package/.claude/skills/bug-fixing/references/bug-records.md +88 -0
- package/.claude/skills/bug-fixing/references/code-review-gate.md +81 -0
- package/.claude/skills/bug-fixing/references/common-bugs.md +140 -0
- package/.claude/skills/bug-fixing/references/complete-workflow.md +361 -0
- package/.claude/skills/bug-fixing/references/config-driven-fixes.md +136 -0
- package/.claude/skills/bug-fixing/references/context-isolation-protocol.md +268 -0
- package/.claude/skills/bug-fixing/references/cross-surface-regression.md +120 -0
- package/.claude/skills/bug-fixing/references/database-investigation.md +129 -0
- package/.claude/skills/bug-fixing/references/dependency-and-integrity-protocol.md +369 -0
- package/.claude/skills/bug-fixing/references/fix-completeness-checklist.md +239 -0
- package/.claude/skills/bug-fixing/references/frontend-guide.md +219 -0
- package/.claude/skills/bug-fixing/references/fullstack-joint-guide.md +123 -0
- package/.claude/skills/bug-fixing/references/functional-breakage.md +117 -0
- package/.claude/skills/bug-fixing/references/ide-lint-errors-guide.md +176 -0
- package/.claude/skills/bug-fixing/references/impact-analysis.md +511 -0
- package/.claude/skills/bug-fixing/references/investigation-checklist.md +263 -0
- package/.claude/skills/bug-fixing/references/knowledge-extraction-guide.md +531 -0
- package/.claude/skills/bug-fixing/references/knowledge-workflow.md +212 -0
- package/.claude/skills/bug-fixing/references/post-edit-quality-gate.md +30 -0
- package/.claude/skills/bug-fixing/references/python-env-and-testing.md +126 -0
- package/.claude/skills/bug-fixing/references/rca-guide.md +428 -0
- package/.claude/skills/bug-fixing/references/similar-bug-patterns.md +113 -0
- package/.claude/skills/bug-fixing/references/skill-delegation-guide.md +350 -0
- package/.claude/skills/bug-fixing/references/skill-orchestration.md +155 -0
- package/.claude/skills/bug-fixing/references/testing-strategy.md +350 -0
- package/.claude/skills/bug-fixing/references/tooling-build-scripts.md +162 -0
- package/.claude/skills/bug-fixing/references/user-input-validation.md +77 -0
- package/.claude/skills/bug-fixing/references/ux-patterns.md +158 -0
- package/.claude/skills/bug-fixing/references/windows-terminal-hygiene.md +106 -0
- package/.claude/skills/bug-fixing/references/zero-regression-matrix.md +239 -0
- package/.claude/skills/bug-fixing/references/zero-risk-protocol.md +102 -0
- package/.claude/skills/bug-fixing/scripts/format_code.py +611 -0
- package/.claude/skills/bug-fixing/scripts/generate_report_template.py +74 -0
- package/.claude/skills/bug-fixing/scripts/lint_check.py +816 -0
- package/.claude/skills/bug-fixing/scripts/requirements.txt +36 -0
- package/.claude/skills/cicd-pipeline/SKILL.md +300 -0
- package/.claude/skills/code-review/SKILL.md +535 -0
- package/.claude/skills/code-review/references/anti-pattern-scan.md +102 -0
- package/.claude/skills/code-review/references/automated-analysis.md +456 -0
- package/.claude/skills/code-review/references/backend-common-issues.md +589 -0
- package/.claude/skills/code-review/references/backend-expert-guide.md +415 -0
- package/.claude/skills/code-review/references/backend-review.md +868 -0
- package/.claude/skills/code-review/references/batch-processing-strategy.md +198 -0
- package/.claude/skills/code-review/references/call-chain-analysis-protocol.md +166 -0
- package/.claude/skills/code-review/references/common-patterns.md +321 -0
- package/.claude/skills/code-review/references/configuration-review.md +425 -0
- package/.claude/skills/code-review/references/control-flow-completeness.md +114 -0
- package/.claude/skills/code-review/references/database-review.md +298 -0
- package/.claude/skills/code-review/references/dependency-and-integrity-protocol.md +313 -0
- package/.claude/skills/code-review/references/external-standards.md +51 -0
- package/.claude/skills/code-review/references/feature-review.md +329 -0
- package/.claude/skills/code-review/references/file-review-template.md +326 -0
- package/.claude/skills/code-review/references/frontend-advanced.md +654 -0
- package/.claude/skills/code-review/references/frontend-common-issues.md +482 -0
- package/.claude/skills/code-review/references/frontend-expert-guide.md +342 -0
- package/.claude/skills/code-review/references/frontend-review.md +783 -0
- package/.claude/skills/code-review/references/fullstack-consistency.md +418 -0
- package/.claude/skills/code-review/references/fullstack-review.md +477 -0
- package/.claude/skills/code-review/references/functional-completeness.md +386 -0
- package/.claude/skills/code-review/references/hidden-bugs-detection.md +473 -0
- package/.claude/skills/code-review/references/ide-lint-errors-guide.md +173 -0
- package/.claude/skills/code-review/references/infrastructure-review.md +453 -0
- package/.claude/skills/code-review/references/iteration-review.md +264 -0
- package/.claude/skills/code-review/references/job-review.md +335 -0
- package/.claude/skills/code-review/references/layered-checklist-protocol.md +157 -0
- package/.claude/skills/code-review/references/logic-completeness.md +535 -0
- package/.claude/skills/code-review/references/mandatory-checklist.md +288 -0
- package/.claude/skills/code-review/references/multi-language-guide.md +800 -0
- package/.claude/skills/code-review/references/new-project-review.md +226 -0
- package/.claude/skills/code-review/references/non-code-files-review.md +451 -0
- package/.claude/skills/code-review/references/overlooked-issues.md +657 -0
- package/.claude/skills/code-review/references/platform-specific-review.md +195 -0
- package/.claude/skills/code-review/references/precision-analysis-protocol.md +260 -0
- package/.claude/skills/code-review/references/python-patterns.md +494 -0
- package/.claude/skills/code-review/references/rca-techniques.md +362 -0
- package/.claude/skills/code-review/references/report-template.md +430 -0
- package/.claude/skills/code-review/references/resource-limits-and-degradation.md +137 -0
- package/.claude/skills/code-review/references/review-dimensions.md +311 -0
- package/.claude/skills/code-review/references/review-guide.md +202 -0
- package/.claude/skills/code-review/references/review-knowledge-workflow.md +257 -0
- package/.claude/skills/code-review/references/review-progress-tracker-protocol.md +172 -0
- package/.claude/skills/code-review/references/review-record-template.md +195 -0
- package/.claude/skills/code-review/references/skill-orchestration.md +143 -0
- package/.claude/skills/code-review/references/ui-ux-review.md +470 -0
- package/.claude/skills/containerization/SKILL.md +313 -0
- package/.claude/skills/database-migrations/agents/database-admin.md +142 -0
- package/.claude/skills/database-migrations/agents/database-optimizer.md +144 -0
- package/.claude/skills/database-migrations/commands/migration-observability.md +408 -0
- package/.claude/skills/database-migrations/commands/sql-migrations.md +492 -0
- package/.claude/skills/finishing-a-development-branch/SKILL.md +319 -0
- package/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/.claude/skills/frontend-design/SKILL.md +587 -0
- package/.claude/skills/frontend-design/references/color-consistency.md +487 -0
- package/.claude/skills/frontend-design/references/color-palettes-full.md +657 -0
- package/.claude/skills/frontend-design/references/design-system-generator.md +285 -0
- package/.claude/skills/frontend-design/references/font-pairings-full.md +705 -0
- package/.claude/skills/frontend-design/references/industry-anti-patterns.md +281 -0
- package/.claude/skills/frontend-design/references/layout-anti-patterns.md +582 -0
- package/.claude/skills/frontend-design/references/motion-patterns.md +659 -0
- package/.claude/skills/frontend-design/references/pre-delivery-checklist.md +153 -0
- package/.claude/skills/frontend-design/references/responsive-design.md +555 -0
- package/.claude/skills/frontend-design/references/style-modification-rules.md +335 -0
- package/.claude/skills/frontend-design/references/ui-styles-full.md +383 -0
- package/.claude/skills/frontend-design/references/ui-styles-rating.md +191 -0
- package/.claude/skills/frontend-design/references/ux-guidelines.md +640 -0
- package/.claude/skills/fullstack-developer/SKILL.md +512 -0
- package/.claude/skills/fullstack-developer/references/api-contract-guide.md +312 -0
- package/.claude/skills/fullstack-developer/references/api-response-patterns.md +223 -0
- package/.claude/skills/fullstack-developer/references/async-patterns.md +220 -0
- package/.claude/skills/fullstack-developer/references/bug-prevention.md +914 -0
- package/.claude/skills/fullstack-developer/references/code-quality-checklist.md +271 -0
- package/.claude/skills/fullstack-developer/references/complete-development-workflow.md +278 -0
- package/.claude/skills/fullstack-developer/references/context-isolation-protocol.md +256 -0
- package/.claude/skills/fullstack-developer/references/database-migration.md +331 -0
- package/.claude/skills/fullstack-developer/references/dependency-and-integrity-protocol.md +390 -0
- package/.claude/skills/fullstack-developer/references/development-phases.md +333 -0
- package/.claude/skills/fullstack-developer/references/expert-guide.md +214 -0
- package/.claude/skills/fullstack-developer/references/file-import-patterns.md +114 -0
- package/.claude/skills/fullstack-developer/references/graceful-degradation-patterns.md +78 -0
- package/.claude/skills/fullstack-developer/references/ide-lint-errors-guide.md +183 -0
- package/.claude/skills/fullstack-developer/references/integration-testing.md +301 -0
- package/.claude/skills/fullstack-developer/references/mock-api-patterns.md +307 -0
- package/.claude/skills/fullstack-developer/references/phase-gate-template.md +249 -0
- package/.claude/skills/fullstack-developer/references/post-edit-quality-gate.md +30 -0
- package/.claude/skills/fullstack-developer/references/python-engineering.md +79 -0
- package/.claude/skills/fullstack-developer/references/skill-orchestration.md +214 -0
- package/.claude/skills/fullstack-developer/references/skill-router-table.md +304 -0
- package/.claude/skills/fullstack-developer/references/state-sync.md +217 -0
- package/.claude/skills/fullstack-developer/references/ui-testing-checklist.md +292 -0
- package/.claude/skills/fullstack-developer/scripts/format_code.py +611 -0
- package/.claude/skills/fullstack-developer/scripts/lint_check.py +816 -0
- package/.claude/skills/fullstack-developer/scripts/requirements.txt +36 -0
- package/.claude/skills/performance-optimization/SKILL.md +250 -0
- package/.claude/skills/product-requirements/SKILL.md +357 -0
- package/.claude/skills/product-requirements/references/acceptance-criteria.md +335 -0
- package/.claude/skills/product-requirements/references/answer-first-questioning-protocol.md +299 -0
- package/.claude/skills/product-requirements/references/competitive-analysis-guide.md +183 -0
- package/.claude/skills/product-requirements/references/document-accuracy-protocol.md +253 -0
- package/.claude/skills/product-requirements/references/document-management-protocol.md +278 -0
- package/.claude/skills/product-requirements/references/external-standards.md +62 -0
- package/.claude/skills/product-requirements/references/feature-spec-template.md +359 -0
- package/.claude/skills/product-requirements/references/knowledge-acquisition-protocol.md +251 -0
- package/.claude/skills/product-requirements/references/plan-execution-protocol.md +334 -0
- package/.claude/skills/product-requirements/references/plan-generation-protocol.md +264 -0
- package/.claude/skills/product-requirements/references/prioritization-frameworks.md +80 -0
- package/.claude/skills/product-requirements/references/requirement-decomposition-protocol.md +291 -0
- package/.claude/skills/product-requirements/references/user-story-examples.md +297 -0
- package/.claude/skills/product-requirements/references/workflow-templates.md +266 -0
- package/.claude/skills/react-best-practices/SKILL.md +198 -0
- package/.claude/skills/react-best-practices/references/advanced-patterns.md +94 -0
- package/.claude/skills/react-best-practices/references/bundle-optimization.md +182 -0
- package/.claude/skills/react-best-practices/references/client-data-fetching.md +112 -0
- package/.claude/skills/react-best-practices/references/complete-guide.md +2249 -0
- package/.claude/skills/react-best-practices/references/eliminating-waterfalls.md +169 -0
- package/.claude/skills/react-best-practices/references/javascript-performance.md +256 -0
- package/.claude/skills/react-best-practices/references/rendering-performance.md +230 -0
- package/.claude/skills/react-best-practices/references/rerender-optimization.md +214 -0
- package/.claude/skills/react-best-practices/references/server-performance.md +182 -0
- package/.claude/skills/security-audit/SKILL.md +226 -0
- package/.claude/skills/shared-references/advanced-debugging-techniques.md +186 -0
- package/.claude/skills/shared-references/code-quality-checklist.md +218 -0
- package/.claude/skills/shared-references/code-review-efficiency-guide.md +125 -0
- package/.claude/skills/shared-references/mcp-dependency-compatibility-protocol.md +276 -0
- package/.claude/skills/shared-references/skill-call-graph.md +230 -0
- package/.claude/skills/shared-references/skill-orchestration-protocol.md +281 -0
- package/.claude/skills/shared-references/subagent-dispatch-templates.md +199 -0
- package/.claude/skills/skill-expert-skills/LICENSE.txt +204 -0
- package/.claude/skills/skill-expert-skills/QUICK_NAVIGATION.md +374 -0
- package/.claude/skills/skill-expert-skills/SKILL.md +247 -0
- package/.claude/skills/skill-expert-skills/docs/_index.md +91 -0
- package/.claude/skills/skill-expert-skills/references/deep-research-methodology.md +389 -0
- package/.claude/skills/skill-expert-skills/references/docs-generation-workflow.md +398 -0
- package/.claude/skills/skill-expert-skills/references/domain-expertise-protocol.md +343 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/_index.md +54 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/backend-expertise.md +517 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/bug-fixing-expertise.md +363 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/code-review-expertise.md +392 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/frontend-expertise.md +410 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge-template.md +503 -0
- package/.claude/skills/skill-expert-skills/references/examples.md +782 -0
- package/.claude/skills/skill-expert-skills/references/integration-examples.md +655 -0
- package/.claude/skills/skill-expert-skills/references/knowledge-validation-checklist.md +246 -0
- package/.claude/skills/skill-expert-skills/references/latest-knowledge-acquisition.md +461 -0
- package/.claude/skills/skill-expert-skills/references/mcp-tools-guide.md +439 -0
- package/.claude/skills/skill-expert-skills/references/official-best-practices.md +616 -0
- package/.claude/skills/skill-expert-skills/references/patterns.md +218 -0
- package/.claude/skills/skill-expert-skills/references/plugin-skills-guide.md +432 -0
- package/.claude/skills/skill-expert-skills/references/requirement-elicitation-protocol.md +290 -0
- package/.claude/skills/skill-expert-skills/references/skill-creator-SKILL.md +353 -0
- package/.claude/skills/skill-expert-skills/references/skill-templates.md +583 -0
- package/.claude/skills/skill-expert-skills/references/skills-knowledge-base.md +561 -0
- package/.claude/skills/skill-expert-skills/references/tools-guide.md +379 -0
- package/.claude/skills/skill-expert-skills/references/troubleshooting.md +378 -0
- package/.claude/skills/skill-expert-skills/references/universality-guide.md +205 -0
- package/.claude/skills/skill-expert-skills/references/writing-style-guide.md +466 -0
- package/.claude/skills/skill-expert-skills/scripts/__pycache__/quick_validate.cpython-313.pyc +0 -0
- package/.claude/skills/skill-expert-skills/scripts/__pycache__/universal_validate.cpython-313.pyc +0 -0
- package/.claude/skills/skill-expert-skills/scripts/analyze_trigger.py +425 -0
- package/.claude/skills/skill-expert-skills/scripts/diff_with_official.py +188 -0
- package/.claude/skills/skill-expert-skills/scripts/init_skill.py +349 -0
- package/.claude/skills/skill-expert-skills/scripts/package_skill.py +156 -0
- package/.claude/skills/skill-expert-skills/scripts/quick_validate.py +493 -0
- package/.claude/skills/skill-expert-skills/scripts/requirements.txt +2 -0
- package/.claude/skills/skill-expert-skills/scripts/universal_validate.py +182 -0
- package/.claude/skills/skill-expert-skills/scripts/upgrade_skill.py +431 -0
- package/.claude/skills/subagent-driven-development/SKILL.md +268 -0
- package/.claude/skills/test-driven-development/SKILL.md +246 -0
- package/.claude/skills/test-driven-development/references/testing-anti-patterns.md +192 -0
- package/.claude/skills/using-git-worktrees/SKILL.md +266 -0
- package/.claude/skills/using-skillstack/SKILL.md +127 -0
- package/.claude/skills/vercel-deploy/SKILL.md +166 -0
- package/.claude/skills/vercel-deploy/scripts/deploy.sh +249 -0
- package/.claude/skills/verification-before-completion/SKILL.md +305 -0
- package/.claude/skills/writing-plans/SKILL.md +259 -0
- package/README.md +69 -0
- package/bin/cli.js +468 -0
- package/lib/init.js +333 -0
- package/package.json +29 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Eliminating Waterfalls
|
|
2
|
+
|
|
3
|
+
**Impact: CRITICAL**
|
|
4
|
+
|
|
5
|
+
Waterfalls are the #1 performance killer. Each sequential await adds full network latency.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Defer Await Until Needed
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH (avoids blocking unused code paths)**
|
|
12
|
+
|
|
13
|
+
Move `await` operations into the branches where they're actually used.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// ❌ Incorrect: blocks both branches
|
|
17
|
+
async function handleRequest(userId: string, skipProcessing: boolean) {
|
|
18
|
+
const userData = await fetchUserData(userId)
|
|
19
|
+
|
|
20
|
+
if (skipProcessing) {
|
|
21
|
+
return { skipped: true }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return processUserData(userData)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ✅ Correct: only blocks when needed
|
|
28
|
+
async function handleRequest(userId: string, skipProcessing: boolean) {
|
|
29
|
+
if (skipProcessing) {
|
|
30
|
+
return { skipped: true }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const userData = await fetchUserData(userId)
|
|
34
|
+
return processUserData(userData)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. Dependency-Based Parallelization
|
|
41
|
+
|
|
42
|
+
**Impact: CRITICAL (2-10× improvement)**
|
|
43
|
+
|
|
44
|
+
Use `better-all` to maximize parallelism for operations with partial dependencies.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// ❌ Incorrect: profile waits for config unnecessarily
|
|
48
|
+
const [user, config] = await Promise.all([
|
|
49
|
+
fetchUser(),
|
|
50
|
+
fetchConfig()
|
|
51
|
+
])
|
|
52
|
+
const profile = await fetchProfile(user.id)
|
|
53
|
+
|
|
54
|
+
// ✅ Correct: config and profile run in parallel
|
|
55
|
+
import { all } from 'better-all'
|
|
56
|
+
|
|
57
|
+
const { user, config, profile } = await all({
|
|
58
|
+
async user() { return fetchUser() },
|
|
59
|
+
async config() { return fetchConfig() },
|
|
60
|
+
async profile() {
|
|
61
|
+
return fetchProfile((await this.$.user).id)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Reference: https://github.com/shuding/better-all
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 3. Prevent Waterfall Chains in API Routes
|
|
71
|
+
|
|
72
|
+
**Impact: CRITICAL (2-10× improvement)**
|
|
73
|
+
|
|
74
|
+
Start independent operations immediately, even if you don't await them yet.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// ❌ Incorrect: config waits for auth, data waits for both
|
|
78
|
+
export async function GET(request: Request) {
|
|
79
|
+
const session = await auth()
|
|
80
|
+
const config = await fetchConfig()
|
|
81
|
+
const data = await fetchData(session.user.id)
|
|
82
|
+
return Response.json({ data, config })
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ✅ Correct: auth and config start immediately
|
|
86
|
+
export async function GET(request: Request) {
|
|
87
|
+
const sessionPromise = auth()
|
|
88
|
+
const configPromise = fetchConfig()
|
|
89
|
+
const session = await sessionPromise
|
|
90
|
+
const [config, data] = await Promise.all([
|
|
91
|
+
configPromise,
|
|
92
|
+
fetchData(session.user.id)
|
|
93
|
+
])
|
|
94
|
+
return Response.json({ data, config })
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 4. Promise.all() for Independent Operations
|
|
101
|
+
|
|
102
|
+
**Impact: CRITICAL (2-10× improvement)**
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// ❌ Incorrect: sequential execution, 3 round trips
|
|
106
|
+
const user = await fetchUser()
|
|
107
|
+
const posts = await fetchPosts()
|
|
108
|
+
const comments = await fetchComments()
|
|
109
|
+
|
|
110
|
+
// ✅ Correct: parallel execution, 1 round trip
|
|
111
|
+
const [user, posts, comments] = await Promise.all([
|
|
112
|
+
fetchUser(),
|
|
113
|
+
fetchPosts(),
|
|
114
|
+
fetchComments()
|
|
115
|
+
])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 5. Strategic Suspense Boundaries
|
|
121
|
+
|
|
122
|
+
**Impact: HIGH (faster initial paint)**
|
|
123
|
+
|
|
124
|
+
Use Suspense boundaries to show wrapper UI faster while data loads.
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
// ❌ Incorrect: wrapper blocked by data fetching
|
|
128
|
+
async function Page() {
|
|
129
|
+
const data = await fetchData() // Blocks entire page
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
<div>Sidebar</div>
|
|
134
|
+
<div>Header</div>
|
|
135
|
+
<div>
|
|
136
|
+
<DataDisplay data={data} />
|
|
137
|
+
</div>
|
|
138
|
+
<div>Footer</div>
|
|
139
|
+
</div>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ✅ Correct: wrapper shows immediately, data streams in
|
|
144
|
+
function Page() {
|
|
145
|
+
return (
|
|
146
|
+
<div>
|
|
147
|
+
<div>Sidebar</div>
|
|
148
|
+
<div>Header</div>
|
|
149
|
+
<div>
|
|
150
|
+
<Suspense fallback={<Skeleton />}>
|
|
151
|
+
<DataDisplay />
|
|
152
|
+
</Suspense>
|
|
153
|
+
</div>
|
|
154
|
+
<div>Footer</div>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function DataDisplay() {
|
|
160
|
+
const data = await fetchData() // Only blocks this component
|
|
161
|
+
return <div>{data.content}</div>
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**When NOT to use:**
|
|
166
|
+
- Critical data needed for layout decisions
|
|
167
|
+
- SEO-critical content above the fold
|
|
168
|
+
- Small, fast queries where suspense overhead isn't worth it
|
|
169
|
+
- When you want to avoid layout shift
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# JavaScript Performance
|
|
2
|
+
|
|
3
|
+
**Impact: LOW-MEDIUM**
|
|
4
|
+
|
|
5
|
+
Micro-optimizations for hot paths can add up to meaningful improvements.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Batch DOM CSS Changes
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM (reduces reflows/repaints)**
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// ❌ Incorrect: multiple reflows
|
|
15
|
+
function updateElementStyles(element: HTMLElement) {
|
|
16
|
+
element.style.width = '100px'
|
|
17
|
+
element.style.height = '200px'
|
|
18
|
+
element.style.backgroundColor = 'blue'
|
|
19
|
+
element.style.border = '1px solid black'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ✅ Correct: add class - single reflow
|
|
23
|
+
// CSS: .highlighted-box { width: 100px; height: 200px; ... }
|
|
24
|
+
function updateElementStyles(element: HTMLElement) {
|
|
25
|
+
element.classList.add('highlighted-box')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ✅ Correct: change cssText - single reflow
|
|
29
|
+
function updateElementStyles(element: HTMLElement) {
|
|
30
|
+
element.style.cssText = `
|
|
31
|
+
width: 100px;
|
|
32
|
+
height: 200px;
|
|
33
|
+
background-color: blue;
|
|
34
|
+
border: 1px solid black;
|
|
35
|
+
`
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Build Index Maps for Repeated Lookups
|
|
42
|
+
|
|
43
|
+
**Impact: LOW-MEDIUM (1M ops to 2K ops)**
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// ❌ Incorrect (O(n) per lookup)
|
|
47
|
+
function processOrders(orders: Order[], users: User[]) {
|
|
48
|
+
return orders.map(order => ({
|
|
49
|
+
...order,
|
|
50
|
+
user: users.find(u => u.id === order.userId)
|
|
51
|
+
}))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ✅ Correct (O(1) per lookup)
|
|
55
|
+
function processOrders(orders: Order[], users: User[]) {
|
|
56
|
+
const userById = new Map(users.map(u => [u.id, u]))
|
|
57
|
+
|
|
58
|
+
return orders.map(order => ({
|
|
59
|
+
...order,
|
|
60
|
+
user: userById.get(order.userId)
|
|
61
|
+
}))
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For 1000 orders × 1000 users: 1M ops → 2K ops.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3. Cache Property Access in Loops
|
|
70
|
+
|
|
71
|
+
**Impact: LOW-MEDIUM (reduces lookups)**
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// ❌ Incorrect: 3 lookups × N iterations
|
|
75
|
+
for (let i = 0; i < arr.length; i++) {
|
|
76
|
+
process(obj.config.settings.value)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ✅ Correct: 1 lookup total
|
|
80
|
+
const value = obj.config.settings.value
|
|
81
|
+
const len = arr.length
|
|
82
|
+
for (let i = 0; i < len; i++) {
|
|
83
|
+
process(value)
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 4. Cache Repeated Function Calls
|
|
90
|
+
|
|
91
|
+
**Impact: MEDIUM (avoid redundant computation)**
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// ❌ Incorrect: redundant computation
|
|
95
|
+
function ProjectList({ projects }: { projects: Project[] }) {
|
|
96
|
+
return (
|
|
97
|
+
<div>
|
|
98
|
+
{projects.map(project => {
|
|
99
|
+
const slug = slugify(project.name) // Called 100+ times
|
|
100
|
+
return <ProjectCard key={project.id} slug={slug} />
|
|
101
|
+
})}
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ✅ Correct: cached results
|
|
107
|
+
const slugifyCache = new Map<string, string>()
|
|
108
|
+
|
|
109
|
+
function cachedSlugify(text: string): string {
|
|
110
|
+
if (slugifyCache.has(text)) {
|
|
111
|
+
return slugifyCache.get(text)!
|
|
112
|
+
}
|
|
113
|
+
const result = slugify(text)
|
|
114
|
+
slugifyCache.set(text, result)
|
|
115
|
+
return result
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function ProjectList({ projects }: { projects: Project[] }) {
|
|
119
|
+
return (
|
|
120
|
+
<div>
|
|
121
|
+
{projects.map(project => {
|
|
122
|
+
const slug = cachedSlugify(project.name)
|
|
123
|
+
return <ProjectCard key={project.id} slug={slug} />
|
|
124
|
+
})}
|
|
125
|
+
</div>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 5. Cache Storage API Calls
|
|
133
|
+
|
|
134
|
+
**Impact: LOW-MEDIUM (reduces expensive I/O)**
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// ❌ Incorrect: reads storage on every call
|
|
138
|
+
function getTheme() {
|
|
139
|
+
return localStorage.getItem('theme') ?? 'light'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ✅ Correct: Map cache
|
|
143
|
+
const storageCache = new Map<string, string | null>()
|
|
144
|
+
|
|
145
|
+
function getLocalStorage(key: string) {
|
|
146
|
+
if (!storageCache.has(key)) {
|
|
147
|
+
storageCache.set(key, localStorage.getItem(key))
|
|
148
|
+
}
|
|
149
|
+
return storageCache.get(key)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function setLocalStorage(key: string, value: string) {
|
|
153
|
+
localStorage.setItem(key, value)
|
|
154
|
+
storageCache.set(key, value)
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 6. Combine Multiple Array Iterations
|
|
161
|
+
|
|
162
|
+
**Impact: LOW-MEDIUM (reduces iterations)**
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// ❌ Incorrect: 3 iterations
|
|
166
|
+
const admins = users.filter(u => u.isAdmin)
|
|
167
|
+
const testers = users.filter(u => u.isTester)
|
|
168
|
+
const inactive = users.filter(u => !u.isActive)
|
|
169
|
+
|
|
170
|
+
// ✅ Correct: 1 iteration
|
|
171
|
+
const admins: User[] = []
|
|
172
|
+
const testers: User[] = []
|
|
173
|
+
const inactive: User[] = []
|
|
174
|
+
|
|
175
|
+
for (const user of users) {
|
|
176
|
+
if (user.isAdmin) admins.push(user)
|
|
177
|
+
if (user.isTester) testers.push(user)
|
|
178
|
+
if (!user.isActive) inactive.push(user)
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 7. Early Length Check for Array Comparisons
|
|
185
|
+
|
|
186
|
+
**Impact: MEDIUM-HIGH**
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// ❌ Incorrect: always runs expensive comparison
|
|
190
|
+
function hasChanges(current: string[], original: string[]) {
|
|
191
|
+
return current.sort().join() !== original.sort().join()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ✅ Correct: O(1) length check first
|
|
195
|
+
function hasChanges(current: string[], original: string[]) {
|
|
196
|
+
if (current.length !== original.length) {
|
|
197
|
+
return true
|
|
198
|
+
}
|
|
199
|
+
const currentSorted = current.toSorted()
|
|
200
|
+
const originalSorted = original.toSorted()
|
|
201
|
+
for (let i = 0; i < currentSorted.length; i++) {
|
|
202
|
+
if (currentSorted[i] !== originalSorted[i]) {
|
|
203
|
+
return true
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return false
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 8. Use Set/Map for O(1) Lookups
|
|
213
|
+
|
|
214
|
+
**Impact: LOW-MEDIUM (O(n) to O(1))**
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// ❌ Incorrect (O(n) per check)
|
|
218
|
+
const allowedIds = ['a', 'b', 'c', ...]
|
|
219
|
+
items.filter(item => allowedIds.includes(item.id))
|
|
220
|
+
|
|
221
|
+
// ✅ Correct (O(1) per check)
|
|
222
|
+
const allowedIds = new Set(['a', 'b', 'c', ...])
|
|
223
|
+
items.filter(item => allowedIds.has(item.id))
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 9. Use toSorted() Instead of sort() for Immutability
|
|
229
|
+
|
|
230
|
+
**Impact: MEDIUM-HIGH (prevents mutation bugs)**
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// ❌ Incorrect: mutates original array
|
|
234
|
+
function UserList({ users }: { users: User[] }) {
|
|
235
|
+
const sorted = useMemo(
|
|
236
|
+
() => users.sort((a, b) => a.name.localeCompare(b.name)),
|
|
237
|
+
[users]
|
|
238
|
+
)
|
|
239
|
+
return <div>{sorted.map(renderUser)}</div>
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ✅ Correct: creates new array
|
|
243
|
+
function UserList({ users }: { users: User[] }) {
|
|
244
|
+
const sorted = useMemo(
|
|
245
|
+
() => users.toSorted((a, b) => a.name.localeCompare(b.name)),
|
|
246
|
+
[users]
|
|
247
|
+
)
|
|
248
|
+
return <div>{sorted.map(renderUser)}</div>
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Other immutable array methods:**
|
|
253
|
+
- `.toSorted()` - immutable sort
|
|
254
|
+
- `.toReversed()` - immutable reverse
|
|
255
|
+
- `.toSpliced()` - immutable splice
|
|
256
|
+
- `.with()` - immutable element replacement
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Rendering Performance
|
|
2
|
+
|
|
3
|
+
**Impact: MEDIUM**
|
|
4
|
+
|
|
5
|
+
Optimizing the rendering process reduces the work the browser needs to do.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Animate SVG Wrapper Instead of SVG Element
|
|
10
|
+
|
|
11
|
+
**Impact: LOW (enables hardware acceleration)**
|
|
12
|
+
|
|
13
|
+
Many browsers don't have hardware acceleration for CSS3 animations on SVG elements.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
// ❌ Incorrect: animating SVG directly - no hardware acceleration
|
|
17
|
+
function LoadingSpinner() {
|
|
18
|
+
return (
|
|
19
|
+
<svg
|
|
20
|
+
className="animate-spin"
|
|
21
|
+
width="24"
|
|
22
|
+
height="24"
|
|
23
|
+
viewBox="0 0 24 24"
|
|
24
|
+
>
|
|
25
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" />
|
|
26
|
+
</svg>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ✅ Correct: animating wrapper div - hardware accelerated
|
|
31
|
+
function LoadingSpinner() {
|
|
32
|
+
return (
|
|
33
|
+
<div className="animate-spin">
|
|
34
|
+
<svg
|
|
35
|
+
width="24"
|
|
36
|
+
height="24"
|
|
37
|
+
viewBox="0 0 24 24"
|
|
38
|
+
>
|
|
39
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" />
|
|
40
|
+
</svg>
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 2. CSS content-visibility for Long Lists
|
|
49
|
+
|
|
50
|
+
**Impact: HIGH (faster initial render)**
|
|
51
|
+
|
|
52
|
+
Apply `content-visibility: auto` to defer off-screen rendering.
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
.message-item {
|
|
56
|
+
content-visibility: auto;
|
|
57
|
+
contain-intrinsic-size: 0 80px;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
function MessageList({ messages }: { messages: Message[] }) {
|
|
63
|
+
return (
|
|
64
|
+
<div className="overflow-y-auto h-screen">
|
|
65
|
+
{messages.map(msg => (
|
|
66
|
+
<div key={msg.id} className="message-item">
|
|
67
|
+
<Avatar user={msg.author} />
|
|
68
|
+
<div>{msg.content}</div>
|
|
69
|
+
</div>
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For 1000 messages, browser skips layout/paint for ~990 off-screen items (10× faster initial render).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 3. Hoist Static JSX Elements
|
|
81
|
+
|
|
82
|
+
**Impact: LOW (avoids re-creation)**
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// ❌ Incorrect: recreates element every render
|
|
86
|
+
function LoadingSkeleton() {
|
|
87
|
+
return <div className="animate-pulse h-20 bg-gray-200" />
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Container() {
|
|
91
|
+
return (
|
|
92
|
+
<div>
|
|
93
|
+
{loading && <LoadingSkeleton />}
|
|
94
|
+
</div>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ✅ Correct: reuses same element
|
|
99
|
+
const loadingSkeleton = (
|
|
100
|
+
<div className="animate-pulse h-20 bg-gray-200" />
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
function Container() {
|
|
104
|
+
return (
|
|
105
|
+
<div>
|
|
106
|
+
{loading && loadingSkeleton}
|
|
107
|
+
</div>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Note:** If React Compiler is enabled, this is automatic.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 4. Optimize SVG Precision
|
|
117
|
+
|
|
118
|
+
**Impact: LOW (reduces file size)**
|
|
119
|
+
|
|
120
|
+
```svg
|
|
121
|
+
<!-- ❌ Incorrect: excessive precision -->
|
|
122
|
+
<path d="M 10.293847 20.847362 L 30.938472 40.192837" />
|
|
123
|
+
|
|
124
|
+
<!-- ✅ Correct: 1 decimal place -->
|
|
125
|
+
<path d="M 10.3 20.8 L 30.9 40.2" />
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Automate with SVGO:**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx svgo --precision=1 --multipass icon.svg
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 5. Prevent Hydration Mismatch Without Flickering
|
|
137
|
+
|
|
138
|
+
**Impact: MEDIUM (avoids visual flicker and hydration errors)**
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
// ❌ Incorrect: breaks SSR
|
|
142
|
+
function ThemeWrapper({ children }: { children: ReactNode }) {
|
|
143
|
+
const theme = localStorage.getItem('theme') || 'light'
|
|
144
|
+
return <div className={theme}>{children}</div>
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ❌ Incorrect: visual flickering
|
|
148
|
+
function ThemeWrapper({ children }: { children: ReactNode }) {
|
|
149
|
+
const [theme, setTheme] = useState('light')
|
|
150
|
+
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
const stored = localStorage.getItem('theme')
|
|
153
|
+
if (stored) setTheme(stored)
|
|
154
|
+
}, [])
|
|
155
|
+
|
|
156
|
+
return <div className={theme}>{children}</div>
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ✅ Correct: no flicker, no hydration mismatch
|
|
160
|
+
function ThemeWrapper({ children }: { children: ReactNode }) {
|
|
161
|
+
return (
|
|
162
|
+
<>
|
|
163
|
+
<div id="theme-wrapper">
|
|
164
|
+
{children}
|
|
165
|
+
</div>
|
|
166
|
+
<script
|
|
167
|
+
dangerouslySetInnerHTML={{
|
|
168
|
+
__html: `
|
|
169
|
+
(function() {
|
|
170
|
+
try {
|
|
171
|
+
var theme = localStorage.getItem('theme') || 'light';
|
|
172
|
+
var el = document.getElementById('theme-wrapper');
|
|
173
|
+
if (el) el.className = theme;
|
|
174
|
+
} catch (e) {}
|
|
175
|
+
})();
|
|
176
|
+
`,
|
|
177
|
+
}}
|
|
178
|
+
/>
|
|
179
|
+
</>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 6. Use Activity Component for Show/Hide
|
|
187
|
+
|
|
188
|
+
**Impact: MEDIUM (preserves state/DOM)**
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { Activity } from 'react'
|
|
192
|
+
|
|
193
|
+
function Dropdown({ isOpen }: Props) {
|
|
194
|
+
return (
|
|
195
|
+
<Activity mode={isOpen ? 'visible' : 'hidden'}>
|
|
196
|
+
<ExpensiveMenu />
|
|
197
|
+
</Activity>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Avoids expensive re-renders and state loss.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 7. Use Explicit Conditional Rendering
|
|
207
|
+
|
|
208
|
+
**Impact: LOW (prevents rendering 0 or NaN)**
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
// ❌ Incorrect: renders "0" when count is 0
|
|
212
|
+
function Badge({ count }: { count: number }) {
|
|
213
|
+
return (
|
|
214
|
+
<div>
|
|
215
|
+
{count && <span className="badge">{count}</span>}
|
|
216
|
+
</div>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
// When count = 0, renders: <div>0</div>
|
|
220
|
+
|
|
221
|
+
// ✅ Correct: renders nothing when count is 0
|
|
222
|
+
function Badge({ count }: { count: number }) {
|
|
223
|
+
return (
|
|
224
|
+
<div>
|
|
225
|
+
{count > 0 ? <span className="badge">{count}</span> : null}
|
|
226
|
+
</div>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
// When count = 0, renders: <div></div>
|
|
230
|
+
```
|