@jakkrichm/create-nexus-devflow 2.0.20 → 2.0.22

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.
Files changed (258) hide show
  1. package/dist/bin/create-nexus-devflow.js +73 -59
  2. package/dist/bin/create-nexus-devflow.js.map +1 -1
  3. package/dist/lib/ui.d.ts +36 -0
  4. package/dist/lib/ui.js +115 -0
  5. package/dist/lib/ui.js.map +1 -0
  6. package/dist/lib/update.js +19 -8
  7. package/dist/lib/update.js.map +1 -1
  8. package/package.json +1 -1
  9. package/template/.agents/skills/00-discover/SKILL.md +28 -116
  10. package/template/.agents/skills/40-execute/SKILL.md +1 -1
  11. package/template/.agents/skills/50-verify/SKILL.md +28 -161
  12. package/template/.agents/skills/60-report/SKILL.md +19 -92
  13. package/template/.agents/skills/70-release/SKILL.md +36 -11
  14. package/template/.agents/skills/check/SKILL.md +19 -7
  15. package/template/.agents/skills/complete/SKILL.md +21 -10
  16. package/template/.claude/skills/00-discover/SKILL.md +28 -116
  17. package/template/.claude/skills/40-execute/SKILL.md +1 -1
  18. package/template/.claude/skills/50-verify/SKILL.md +28 -161
  19. package/template/.claude/skills/60-report/SKILL.md +19 -92
  20. package/template/.claude/skills/70-release/SKILL.md +36 -11
  21. package/template/.claude/skills/check/SKILL.md +19 -7
  22. package/template/.claude/skills/complete/SKILL.md +21 -10
  23. package/template/AGENTS.md +1 -1
  24. package/template/devflow/context/coding-standards.md +40 -29
  25. package/template/.agents/skills/agent/SKILL.md +0 -165
  26. package/template/.agents/skills/api-and-interface-design/SKILL.md +0 -294
  27. package/template/.agents/skills/app-builder/SKILL.md +0 -75
  28. package/template/.agents/skills/app-builder/agent-coordination.md +0 -71
  29. package/template/.agents/skills/app-builder/feature-building.md +0 -53
  30. package/template/.agents/skills/app-builder/project-detection.md +0 -34
  31. package/template/.agents/skills/app-builder/scaffolding.md +0 -118
  32. package/template/.agents/skills/app-builder/tech-stack.md +0 -40
  33. package/template/.agents/skills/app-builder/templates/SKILL.md +0 -39
  34. package/template/.agents/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -76
  35. package/template/.agents/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -92
  36. package/template/.agents/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -88
  37. package/template/.agents/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -88
  38. package/template/.agents/skills/app-builder/templates/express-api/TEMPLATE.md +0 -83
  39. package/template/.agents/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -90
  40. package/template/.agents/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -90
  41. package/template/.agents/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -122
  42. package/template/.agents/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -122
  43. package/template/.agents/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -169
  44. package/template/.agents/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -134
  45. package/template/.agents/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -83
  46. package/template/.agents/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -119
  47. package/template/.agents/skills/architecture/SKILL.md +0 -55
  48. package/template/.agents/skills/architecture/context-discovery.md +0 -43
  49. package/template/.agents/skills/architecture/examples.md +0 -94
  50. package/template/.agents/skills/architecture/pattern-selection.md +0 -68
  51. package/template/.agents/skills/architecture/patterns-reference.md +0 -50
  52. package/template/.agents/skills/architecture/trade-off-analysis.md +0 -77
  53. package/template/.agents/skills/bash-linux/SKILL.md +0 -199
  54. package/template/.agents/skills/behavioral-modes/SKILL.md +0 -242
  55. package/template/.agents/skills/brainstorm/SKILL.md +0 -168
  56. package/template/.agents/skills/changelog/SKILL.md +0 -109
  57. package/template/.agents/skills/codebase-design/DEEPENING.md +0 -24
  58. package/template/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +0 -28
  59. package/template/.agents/skills/codebase-design/SKILL.md +0 -58
  60. package/template/.agents/skills/commit/SKILL.md +0 -59
  61. package/template/.agents/skills/competitor-analysis/SKILL.md +0 -66
  62. package/template/.agents/skills/context-engineering/SKILL.md +0 -290
  63. package/template/.agents/skills/database-design/SKILL.md +0 -52
  64. package/template/.agents/skills/database-design/database-selection.md +0 -43
  65. package/template/.agents/skills/database-design/indexing.md +0 -39
  66. package/template/.agents/skills/database-design/migrations.md +0 -48
  67. package/template/.agents/skills/database-design/optimization.md +0 -36
  68. package/template/.agents/skills/database-design/orm-selection.md +0 -30
  69. package/template/.agents/skills/database-design/schema-design.md +0 -56
  70. package/template/.agents/skills/database-design/scripts/schema_validator.py +0 -172
  71. package/template/.agents/skills/deploy/SKILL.md +0 -63
  72. package/template/.agents/skills/documentation-and-adrs/SKILL.md +0 -278
  73. package/template/.agents/skills/domain-modeling/ADR-FORMAT.md +0 -47
  74. package/template/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +0 -60
  75. package/template/.agents/skills/domain-modeling/SKILL.md +0 -74
  76. package/template/.agents/skills/followup/SKILL.md +0 -83
  77. package/template/.agents/skills/frontend-ui-engineering/SKILL.md +0 -326
  78. package/template/.agents/skills/frontend-ui-engineering/accessibility-checklist.md +0 -159
  79. package/template/.agents/skills/goal/SKILL.md +0 -148
  80. package/template/.agents/skills/handoff/SKILL.md +0 -46
  81. package/template/.agents/skills/help/SKILL.md +0 -253
  82. package/template/.agents/skills/i18n-localization/SKILL.md +0 -154
  83. package/template/.agents/skills/i18n-localization/scripts/i18n_checker.py +0 -241
  84. package/template/.agents/skills/insight/SKILL.md +0 -42
  85. package/template/.agents/skills/issue-triage/SKILL.md +0 -115
  86. package/template/.agents/skills/lint-and-validate/SKILL.md +0 -45
  87. package/template/.agents/skills/lint-and-validate/scripts/lint_runner.py +0 -184
  88. package/template/.agents/skills/lint-and-validate/scripts/type_coverage.py +0 -173
  89. package/template/.agents/skills/mcp-builder/SKILL.md +0 -176
  90. package/template/.agents/skills/merge/SKILL.md +0 -76
  91. package/template/.agents/skills/mobile-design/SKILL.md +0 -394
  92. package/template/.agents/skills/mobile-design/decision-trees.md +0 -516
  93. package/template/.agents/skills/mobile-design/mobile-backend.md +0 -491
  94. package/template/.agents/skills/mobile-design/mobile-color-system.md +0 -420
  95. package/template/.agents/skills/mobile-design/mobile-debugging.md +0 -122
  96. package/template/.agents/skills/mobile-design/mobile-design-thinking.md +0 -357
  97. package/template/.agents/skills/mobile-design/mobile-navigation.md +0 -458
  98. package/template/.agents/skills/mobile-design/mobile-performance.md +0 -767
  99. package/template/.agents/skills/mobile-design/mobile-testing.md +0 -356
  100. package/template/.agents/skills/mobile-design/mobile-typography.md +0 -433
  101. package/template/.agents/skills/mobile-design/platform-android.md +0 -666
  102. package/template/.agents/skills/mobile-design/platform-ios.md +0 -561
  103. package/template/.agents/skills/mobile-design/scripts/mobile_audit.py +0 -670
  104. package/template/.agents/skills/mobile-design/touch-psychology.md +0 -537
  105. package/template/.agents/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -312
  106. package/template/.agents/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -240
  107. package/template/.agents/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -490
  108. package/template/.agents/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -264
  109. package/template/.agents/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -581
  110. package/template/.agents/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -432
  111. package/template/.agents/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -684
  112. package/template/.agents/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -150
  113. package/template/.agents/skills/nextjs-react-expert/SKILL.md +0 -286
  114. package/template/.agents/skills/nextjs-react-expert/scripts/convert_rules.py +0 -222
  115. package/template/.agents/skills/nextjs-react-expert/scripts/react_performance_checker.py +0 -252
  116. package/template/.agents/skills/nodejs-best-practices/SKILL.md +0 -333
  117. package/template/.agents/skills/package-json-generator/SKILL.md +0 -60
  118. package/template/.agents/skills/package-json-generator/scripts/generate.js +0 -120
  119. package/template/.agents/skills/package-json-generator/scripts/run.sh +0 -19
  120. package/template/.agents/skills/parallel-agents/SKILL.md +0 -144
  121. package/template/.agents/skills/performance-optimization/SKILL.md +0 -299
  122. package/template/.agents/skills/performance-optimization/performance-checklist.md +0 -113
  123. package/template/.agents/skills/powershell-windows/SKILL.md +0 -167
  124. package/template/.agents/skills/pr/SKILL.md +0 -93
  125. package/template/.agents/skills/prd/SKILL.md +0 -127
  126. package/template/.agents/skills/preview/SKILL.md +0 -42
  127. package/template/.agents/skills/python-patterns/SKILL.md +0 -441
  128. package/template/.agents/skills/research/SKILL.md +0 -143
  129. package/template/.agents/skills/review/SKILL.md +0 -71
  130. package/template/.agents/skills/roadmap-strategy/SKILL.md +0 -94
  131. package/template/.agents/skills/security-review/SKILL.md +0 -63
  132. package/template/.agents/skills/seo-fundamentals/SKILL.md +0 -129
  133. package/template/.agents/skills/seo-fundamentals/scripts/seo_checker.py +0 -219
  134. package/template/.agents/skills/server-management/SKILL.md +0 -161
  135. package/template/.agents/skills/simplify/SKILL.md +0 -70
  136. package/template/.agents/skills/skill-development/SKILL.md +0 -86
  137. package/template/.agents/skills/spec/SKILL.md +0 -39
  138. package/template/.agents/skills/spec-driven-development/SKILL.md +0 -207
  139. package/template/.agents/skills/tailwind-patterns/SKILL.md +0 -269
  140. package/template/.agents/skills/type-design/SKILL.md +0 -84
  141. package/template/.agents/skills/ui-ux-pro-max/SKILL.md +0 -75
  142. package/template/.claude/skills/agent/SKILL.md +0 -165
  143. package/template/.claude/skills/api-and-interface-design/SKILL.md +0 -294
  144. package/template/.claude/skills/app-builder/SKILL.md +0 -75
  145. package/template/.claude/skills/app-builder/agent-coordination.md +0 -71
  146. package/template/.claude/skills/app-builder/feature-building.md +0 -53
  147. package/template/.claude/skills/app-builder/project-detection.md +0 -34
  148. package/template/.claude/skills/app-builder/scaffolding.md +0 -118
  149. package/template/.claude/skills/app-builder/tech-stack.md +0 -40
  150. package/template/.claude/skills/app-builder/templates/SKILL.md +0 -39
  151. package/template/.claude/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -76
  152. package/template/.claude/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -92
  153. package/template/.claude/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -88
  154. package/template/.claude/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -88
  155. package/template/.claude/skills/app-builder/templates/express-api/TEMPLATE.md +0 -83
  156. package/template/.claude/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -90
  157. package/template/.claude/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -90
  158. package/template/.claude/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -122
  159. package/template/.claude/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -122
  160. package/template/.claude/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -169
  161. package/template/.claude/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -134
  162. package/template/.claude/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -83
  163. package/template/.claude/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -119
  164. package/template/.claude/skills/architecture/SKILL.md +0 -55
  165. package/template/.claude/skills/architecture/context-discovery.md +0 -43
  166. package/template/.claude/skills/architecture/examples.md +0 -94
  167. package/template/.claude/skills/architecture/pattern-selection.md +0 -68
  168. package/template/.claude/skills/architecture/patterns-reference.md +0 -50
  169. package/template/.claude/skills/architecture/trade-off-analysis.md +0 -77
  170. package/template/.claude/skills/bash-linux/SKILL.md +0 -199
  171. package/template/.claude/skills/behavioral-modes/SKILL.md +0 -242
  172. package/template/.claude/skills/brainstorm/SKILL.md +0 -168
  173. package/template/.claude/skills/changelog/SKILL.md +0 -109
  174. package/template/.claude/skills/codebase-design/DEEPENING.md +0 -24
  175. package/template/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +0 -28
  176. package/template/.claude/skills/codebase-design/SKILL.md +0 -58
  177. package/template/.claude/skills/commit/SKILL.md +0 -59
  178. package/template/.claude/skills/competitor-analysis/SKILL.md +0 -66
  179. package/template/.claude/skills/context-engineering/SKILL.md +0 -290
  180. package/template/.claude/skills/database-design/SKILL.md +0 -52
  181. package/template/.claude/skills/database-design/database-selection.md +0 -43
  182. package/template/.claude/skills/database-design/indexing.md +0 -39
  183. package/template/.claude/skills/database-design/migrations.md +0 -48
  184. package/template/.claude/skills/database-design/optimization.md +0 -36
  185. package/template/.claude/skills/database-design/orm-selection.md +0 -30
  186. package/template/.claude/skills/database-design/schema-design.md +0 -56
  187. package/template/.claude/skills/database-design/scripts/schema_validator.py +0 -172
  188. package/template/.claude/skills/deploy/SKILL.md +0 -63
  189. package/template/.claude/skills/documentation-and-adrs/SKILL.md +0 -278
  190. package/template/.claude/skills/domain-modeling/ADR-FORMAT.md +0 -47
  191. package/template/.claude/skills/domain-modeling/CONTEXT-FORMAT.md +0 -60
  192. package/template/.claude/skills/domain-modeling/SKILL.md +0 -74
  193. package/template/.claude/skills/followup/SKILL.md +0 -83
  194. package/template/.claude/skills/frontend-ui-engineering/SKILL.md +0 -326
  195. package/template/.claude/skills/frontend-ui-engineering/accessibility-checklist.md +0 -159
  196. package/template/.claude/skills/goal/SKILL.md +0 -148
  197. package/template/.claude/skills/handoff/SKILL.md +0 -46
  198. package/template/.claude/skills/help/SKILL.md +0 -253
  199. package/template/.claude/skills/i18n-localization/SKILL.md +0 -154
  200. package/template/.claude/skills/i18n-localization/scripts/i18n_checker.py +0 -241
  201. package/template/.claude/skills/insight/SKILL.md +0 -42
  202. package/template/.claude/skills/issue-triage/SKILL.md +0 -115
  203. package/template/.claude/skills/lint-and-validate/SKILL.md +0 -45
  204. package/template/.claude/skills/lint-and-validate/scripts/lint_runner.py +0 -184
  205. package/template/.claude/skills/lint-and-validate/scripts/type_coverage.py +0 -173
  206. package/template/.claude/skills/mcp-builder/SKILL.md +0 -176
  207. package/template/.claude/skills/merge/SKILL.md +0 -76
  208. package/template/.claude/skills/mobile-design/SKILL.md +0 -394
  209. package/template/.claude/skills/mobile-design/decision-trees.md +0 -516
  210. package/template/.claude/skills/mobile-design/mobile-backend.md +0 -491
  211. package/template/.claude/skills/mobile-design/mobile-color-system.md +0 -420
  212. package/template/.claude/skills/mobile-design/mobile-debugging.md +0 -122
  213. package/template/.claude/skills/mobile-design/mobile-design-thinking.md +0 -357
  214. package/template/.claude/skills/mobile-design/mobile-navigation.md +0 -458
  215. package/template/.claude/skills/mobile-design/mobile-performance.md +0 -767
  216. package/template/.claude/skills/mobile-design/mobile-testing.md +0 -356
  217. package/template/.claude/skills/mobile-design/mobile-typography.md +0 -433
  218. package/template/.claude/skills/mobile-design/platform-android.md +0 -666
  219. package/template/.claude/skills/mobile-design/platform-ios.md +0 -561
  220. package/template/.claude/skills/mobile-design/scripts/mobile_audit.py +0 -670
  221. package/template/.claude/skills/mobile-design/touch-psychology.md +0 -537
  222. package/template/.claude/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -312
  223. package/template/.claude/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -240
  224. package/template/.claude/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -490
  225. package/template/.claude/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -264
  226. package/template/.claude/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -581
  227. package/template/.claude/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -432
  228. package/template/.claude/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -684
  229. package/template/.claude/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -150
  230. package/template/.claude/skills/nextjs-react-expert/SKILL.md +0 -286
  231. package/template/.claude/skills/nextjs-react-expert/scripts/convert_rules.py +0 -222
  232. package/template/.claude/skills/nextjs-react-expert/scripts/react_performance_checker.py +0 -252
  233. package/template/.claude/skills/nodejs-best-practices/SKILL.md +0 -333
  234. package/template/.claude/skills/package-json-generator/SKILL.md +0 -60
  235. package/template/.claude/skills/package-json-generator/scripts/generate.js +0 -120
  236. package/template/.claude/skills/package-json-generator/scripts/run.sh +0 -19
  237. package/template/.claude/skills/parallel-agents/SKILL.md +0 -144
  238. package/template/.claude/skills/performance-optimization/SKILL.md +0 -299
  239. package/template/.claude/skills/performance-optimization/performance-checklist.md +0 -113
  240. package/template/.claude/skills/powershell-windows/SKILL.md +0 -167
  241. package/template/.claude/skills/pr/SKILL.md +0 -93
  242. package/template/.claude/skills/prd/SKILL.md +0 -127
  243. package/template/.claude/skills/preview/SKILL.md +0 -42
  244. package/template/.claude/skills/python-patterns/SKILL.md +0 -441
  245. package/template/.claude/skills/research/SKILL.md +0 -143
  246. package/template/.claude/skills/review/SKILL.md +0 -71
  247. package/template/.claude/skills/roadmap-strategy/SKILL.md +0 -94
  248. package/template/.claude/skills/security-review/SKILL.md +0 -63
  249. package/template/.claude/skills/seo-fundamentals/SKILL.md +0 -129
  250. package/template/.claude/skills/seo-fundamentals/scripts/seo_checker.py +0 -219
  251. package/template/.claude/skills/server-management/SKILL.md +0 -161
  252. package/template/.claude/skills/simplify/SKILL.md +0 -70
  253. package/template/.claude/skills/skill-development/SKILL.md +0 -86
  254. package/template/.claude/skills/spec/SKILL.md +0 -39
  255. package/template/.claude/skills/spec-driven-development/SKILL.md +0 -207
  256. package/template/.claude/skills/tailwind-patterns/SKILL.md +0 -269
  257. package/template/.claude/skills/type-design/SKILL.md +0 -84
  258. package/template/.claude/skills/ui-ux-pro-max/SKILL.md +0 -75
@@ -1,684 +0,0 @@
1
- # 7. JavaScript Performance
2
-
3
- > **Impact:** LOW-MEDIUM
4
- > **Focus:** Micro-optimizations for hot paths can add up to meaningful improvements.
5
-
6
- ---
7
-
8
- ## Overview
9
-
10
- This section contains **12 rules** focused on javascript performance.
11
-
12
- ---
13
-
14
- ## Rule 7.1: Avoid Layout Thrashing
15
-
16
- **Impact:** MEDIUM
17
- **Tags:** javascript, dom, css, performance, reflow, layout-thrashing
18
-
19
- ## Avoid Layout Thrashing
20
-
21
- Avoid interleaving style writes with layout reads. When you read a layout property (like `offsetWidth`, `getBoundingClientRect()`, or `getComputedStyle()`) between style changes, the browser is forced to trigger a synchronous reflow.
22
-
23
- **This is OK (browser batches style changes):**
24
- ```typescript
25
- function updateElementStyles(element: HTMLElement) {
26
- // Each line invalidates style, but browser batches the recalculation
27
- element.style.width = '100px'
28
- element.style.height = '200px'
29
- element.style.backgroundColor = 'blue'
30
- element.style.border = '1px solid black'
31
- }
32
- ```
33
-
34
- **Incorrect (interleaved reads and writes force reflows):**
35
- ```typescript
36
- function layoutThrashing(element: HTMLElement) {
37
- element.style.width = '100px'
38
- const width = element.offsetWidth // Forces reflow
39
- element.style.height = '200px'
40
- const height = element.offsetHeight // Forces another reflow
41
- }
42
- ```
43
-
44
- **Correct (batch writes, then read once):**
45
- ```typescript
46
- function updateElementStyles(element: HTMLElement) {
47
- // Batch all writes together
48
- element.style.width = '100px'
49
- element.style.height = '200px'
50
- element.style.backgroundColor = 'blue'
51
- element.style.border = '1px solid black'
52
-
53
- // Read after all writes are done (single reflow)
54
- const { width, height } = element.getBoundingClientRect()
55
- }
56
- ```
57
-
58
- **Correct (batch reads, then writes):**
59
- ```typescript
60
- function avoidThrashing(element: HTMLElement) {
61
- // Read phase - all layout queries first
62
- const rect1 = element.getBoundingClientRect()
63
- const offsetWidth = element.offsetWidth
64
- const offsetHeight = element.offsetHeight
65
-
66
- // Write phase - all style changes after
67
- element.style.width = '100px'
68
- element.style.height = '200px'
69
- }
70
- ```
71
-
72
- **Better: use CSS classes**
73
- ```css
74
- .highlighted-box {
75
- width: 100px;
76
- height: 200px;
77
- background-color: blue;
78
- border: 1px solid black;
79
- }
80
- ```
81
- ```typescript
82
- function updateElementStyles(element: HTMLElement) {
83
- element.classList.add('highlighted-box')
84
-
85
- const { width, height } = element.getBoundingClientRect()
86
- }
87
- ```
88
-
89
- **React example:**
90
- ```tsx
91
- // Incorrect: interleaving style changes with layout queries
92
- function Box({ isHighlighted }: { isHighlighted: boolean }) {
93
- const ref = useRef<HTMLDivElement>(null)
94
-
95
- useEffect(() => {
96
- if (ref.current && isHighlighted) {
97
- ref.current.style.width = '100px'
98
- const width = ref.current.offsetWidth // Forces layout
99
- ref.current.style.height = '200px'
100
- }
101
- }, [isHighlighted])
102
-
103
- return <div ref={ref}>Content</div>
104
- }
105
-
106
- // Correct: toggle class
107
- function Box({ isHighlighted }: { isHighlighted: boolean }) {
108
- return (
109
- <div className={isHighlighted ? 'highlighted-box' : ''}>
110
- Content
111
- </div>
112
- )
113
- }
114
- ```
115
-
116
- Prefer CSS classes over inline styles when possible. CSS files are cached by the browser, and classes provide better separation of concerns and are easier to maintain.
117
-
118
- See [this gist](https://gist.github.com/paulirish/5d52fb081b3570c81e3a) and [CSS Triggers](https://csstriggers.com/) for more information on layout-forcing operations.
119
-
120
- ---
121
-
122
- ## Rule 7.2: Build Index Maps for Repeated Lookups
123
-
124
- **Impact:** LOW-MEDIUM
125
- **Tags:** javascript, map, indexing, optimization, performance
126
-
127
- ## Build Index Maps for Repeated Lookups
128
-
129
- Multiple `.find()` calls by the same key should use a Map.
130
-
131
- **Incorrect (O(n) per lookup):**
132
-
133
- ```typescript
134
- function processOrders(orders: Order[], users: User[]) {
135
- return orders.map(order => ({
136
- ...order,
137
- user: users.find(u => u.id === order.userId)
138
- }))
139
- }
140
- ```
141
-
142
- **Correct (O(1) per lookup):**
143
-
144
- ```typescript
145
- function processOrders(orders: Order[], users: User[]) {
146
- const userById = new Map(users.map(u => [u.id, u]))
147
-
148
- return orders.map(order => ({
149
- ...order,
150
- user: userById.get(order.userId)
151
- }))
152
- }
153
- ```
154
-
155
- Build map once (O(n)), then all lookups are O(1).
156
- For 1000 orders × 1000 users: 1M ops → 2K ops.
157
-
158
- ---
159
-
160
- ## Rule 7.3: Cache Property Access in Loops
161
-
162
- **Impact:** LOW-MEDIUM
163
- **Tags:** javascript, loops, optimization, caching
164
-
165
- ## Cache Property Access in Loops
166
-
167
- Cache object property lookups in hot paths.
168
-
169
- **Incorrect (3 lookups × N iterations):**
170
-
171
- ```typescript
172
- for (let i = 0; i < arr.length; i++) {
173
- process(obj.config.settings.value)
174
- }
175
- ```
176
-
177
- **Correct (1 lookup total):**
178
-
179
- ```typescript
180
- const value = obj.config.settings.value
181
- const len = arr.length
182
- for (let i = 0; i < len; i++) {
183
- process(value)
184
- }
185
- ```
186
-
187
- ---
188
-
189
- ## Rule 7.4: Cache Repeated Function Calls
190
-
191
- **Impact:** MEDIUM
192
- **Tags:** javascript, cache, memoization, performance
193
-
194
- ## Cache Repeated Function Calls
195
-
196
- Use a module-level Map to cache function results when the same function is called repeatedly with the same inputs during render.
197
-
198
- **Incorrect (redundant computation):**
199
-
200
- ```typescript
201
- function ProjectList({ projects }: { projects: Project[] }) {
202
- return (
203
- <div>
204
- {projects.map(project => {
205
- // slugify() called 100+ times for same project names
206
- const slug = slugify(project.name)
207
-
208
- return <ProjectCard key={project.id} slug={slug} />
209
- })}
210
- </div>
211
- )
212
- }
213
- ```
214
-
215
- **Correct (cached results):**
216
-
217
- ```typescript
218
- // Module-level cache
219
- const slugifyCache = new Map<string, string>()
220
-
221
- function cachedSlugify(text: string): string {
222
- if (slugifyCache.has(text)) {
223
- return slugifyCache.get(text)!
224
- }
225
- const result = slugify(text)
226
- slugifyCache.set(text, result)
227
- return result
228
- }
229
-
230
- function ProjectList({ projects }: { projects: Project[] }) {
231
- return (
232
- <div>
233
- {projects.map(project => {
234
- // Computed only once per unique project name
235
- const slug = cachedSlugify(project.name)
236
-
237
- return <ProjectCard key={project.id} slug={slug} />
238
- })}
239
- </div>
240
- )
241
- }
242
- ```
243
-
244
- **Simpler pattern for single-value functions:**
245
-
246
- ```typescript
247
- let isLoggedInCache: boolean | null = null
248
-
249
- function isLoggedIn(): boolean {
250
- if (isLoggedInCache !== null) {
251
- return isLoggedInCache
252
- }
253
-
254
- isLoggedInCache = document.cookie.includes('auth=')
255
- return isLoggedInCache
256
- }
257
-
258
- // Clear cache when auth changes
259
- function onAuthChange() {
260
- isLoggedInCache = null
261
- }
262
- ```
263
-
264
- Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
265
-
266
- Reference: [How we made the Vercel Dashboard twice as fast](https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast)
267
-
268
- ---
269
-
270
- ## Rule 7.5: Cache Storage API Calls
271
-
272
- **Impact:** LOW-MEDIUM
273
- **Tags:** javascript, localStorage, storage, caching, performance
274
-
275
- ## Cache Storage API Calls
276
-
277
- `localStorage`, `sessionStorage`, and `document.cookie` are synchronous and expensive. Cache reads in memory.
278
-
279
- **Incorrect (reads storage on every call):**
280
-
281
- ```typescript
282
- function getTheme() {
283
- return localStorage.getItem('theme') ?? 'light'
284
- }
285
- // Called 10 times = 10 storage reads
286
- ```
287
-
288
- **Correct (Map cache):**
289
-
290
- ```typescript
291
- const storageCache = new Map<string, string | null>()
292
-
293
- function getLocalStorage(key: string) {
294
- if (!storageCache.has(key)) {
295
- storageCache.set(key, localStorage.getItem(key))
296
- }
297
- return storageCache.get(key)
298
- }
299
-
300
- function setLocalStorage(key: string, value: string) {
301
- localStorage.setItem(key, value)
302
- storageCache.set(key, value) // keep cache in sync
303
- }
304
- ```
305
-
306
- Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
307
-
308
- **Cookie caching:**
309
-
310
- ```typescript
311
- let cookieCache: Record<string, string> | null = null
312
-
313
- function getCookie(name: string) {
314
- if (!cookieCache) {
315
- cookieCache = Object.fromEntries(
316
- document.cookie.split('; ').map(c => c.split('='))
317
- )
318
- }
319
- return cookieCache[name]
320
- }
321
- ```
322
-
323
- **Important (invalidate on external changes):**
324
-
325
- If storage can change externally (another tab, server-set cookies), invalidate cache:
326
-
327
- ```typescript
328
- window.addEventListener('storage', (e) => {
329
- if (e.key) storageCache.delete(e.key)
330
- })
331
-
332
- document.addEventListener('visibilitychange', () => {
333
- if (document.visibilityState === 'visible') {
334
- storageCache.clear()
335
- }
336
- })
337
- ```
338
-
339
- ---
340
-
341
- ## Rule 7.6: Combine Multiple Array Iterations
342
-
343
- **Impact:** LOW-MEDIUM
344
- **Tags:** javascript, arrays, loops, performance
345
-
346
- ## Combine Multiple Array Iterations
347
-
348
- Multiple `.filter()` or `.map()` calls iterate the array multiple times. Combine into one loop.
349
-
350
- **Incorrect (3 iterations):**
351
-
352
- ```typescript
353
- const admins = users.filter(u => u.isAdmin)
354
- const testers = users.filter(u => u.isTester)
355
- const inactive = users.filter(u => !u.isActive)
356
- ```
357
-
358
- **Correct (1 iteration):**
359
-
360
- ```typescript
361
- const admins: User[] = []
362
- const testers: User[] = []
363
- const inactive: User[] = []
364
-
365
- for (const user of users) {
366
- if (user.isAdmin) admins.push(user)
367
- if (user.isTester) testers.push(user)
368
- if (!user.isActive) inactive.push(user)
369
- }
370
- ```
371
-
372
- ---
373
-
374
- ## Rule 7.7: Early Length Check for Array Comparisons
375
-
376
- **Impact:** MEDIUM-HIGH
377
- **Tags:** javascript, arrays, performance, optimization, comparison
378
-
379
- ## Early Length Check for Array Comparisons
380
-
381
- When comparing arrays with expensive operations (sorting, deep equality, serialization), check lengths first. If lengths differ, the arrays cannot be equal.
382
-
383
- In real-world applications, this optimization is especially valuable when the comparison runs in hot paths (event handlers, render loops).
384
-
385
- **Incorrect (always runs expensive comparison):**
386
-
387
- ```typescript
388
- function hasChanges(current: string[], original: string[]) {
389
- // Always sorts and joins, even when lengths differ
390
- return current.sort().join() !== original.sort().join()
391
- }
392
- ```
393
-
394
- Two O(n log n) sorts run even when `current.length` is 5 and `original.length` is 100. There is also overhead of joining the arrays and comparing the strings.
395
-
396
- **Correct (O(1) length check first):**
397
-
398
- ```typescript
399
- function hasChanges(current: string[], original: string[]) {
400
- // Early return if lengths differ
401
- if (current.length !== original.length) {
402
- return true
403
- }
404
- // Only sort when lengths match
405
- const currentSorted = current.toSorted()
406
- const originalSorted = original.toSorted()
407
- for (let i = 0; i < currentSorted.length; i++) {
408
- if (currentSorted[i] !== originalSorted[i]) {
409
- return true
410
- }
411
- }
412
- return false
413
- }
414
- ```
415
-
416
- This new approach is more efficient because:
417
- - It avoids the overhead of sorting and joining the arrays when lengths differ
418
- - It avoids consuming memory for the joined strings (especially important for large arrays)
419
- - It avoids mutating the original arrays
420
- - It returns early when a difference is found
421
-
422
- ---
423
-
424
- ## Rule 7.8: Early Return from Functions
425
-
426
- **Impact:** LOW-MEDIUM
427
- **Tags:** javascript, functions, optimization, early-return
428
-
429
- ## Early Return from Functions
430
-
431
- Return early when result is determined to skip unnecessary processing.
432
-
433
- **Incorrect (processes all items even after finding answer):**
434
-
435
- ```typescript
436
- function validateUsers(users: User[]) {
437
- let hasError = false
438
- let errorMessage = ''
439
-
440
- for (const user of users) {
441
- if (!user.email) {
442
- hasError = true
443
- errorMessage = 'Email required'
444
- }
445
- if (!user.name) {
446
- hasError = true
447
- errorMessage = 'Name required'
448
- }
449
- // Continues checking all users even after error found
450
- }
451
-
452
- return hasError ? { valid: false, error: errorMessage } : { valid: true }
453
- }
454
- ```
455
-
456
- **Correct (returns immediately on first error):**
457
-
458
- ```typescript
459
- function validateUsers(users: User[]) {
460
- for (const user of users) {
461
- if (!user.email) {
462
- return { valid: false, error: 'Email required' }
463
- }
464
- if (!user.name) {
465
- return { valid: false, error: 'Name required' }
466
- }
467
- }
468
-
469
- return { valid: true }
470
- }
471
- ```
472
-
473
- ---
474
-
475
- ## Rule 7.9: Hoist RegExp Creation
476
-
477
- **Impact:** LOW-MEDIUM
478
- **Tags:** javascript, regexp, optimization, memoization
479
-
480
- ## Hoist RegExp Creation
481
-
482
- Don't create RegExp inside render. Hoist to module scope or memoize with `useMemo()`.
483
-
484
- **Incorrect (new RegExp every render):**
485
-
486
- ```tsx
487
- function Highlighter({ text, query }: Props) {
488
- const regex = new RegExp(`(${query})`, 'gi')
489
- const parts = text.split(regex)
490
- return <>{parts.map((part, i) => ...)}</>
491
- }
492
- ```
493
-
494
- **Correct (memoize or hoist):**
495
-
496
- ```tsx
497
- const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
498
-
499
- function Highlighter({ text, query }: Props) {
500
- const regex = useMemo(
501
- () => new RegExp(`(${escapeRegex(query)})`, 'gi'),
502
- [query]
503
- )
504
- const parts = text.split(regex)
505
- return <>{parts.map((part, i) => ...)}</>
506
- }
507
- ```
508
-
509
- **Warning (global regex has mutable state):**
510
-
511
- Global regex (`/g`) has mutable `lastIndex` state:
512
-
513
- ```typescript
514
- const regex = /foo/g
515
- regex.test('foo') // true, lastIndex = 3
516
- regex.test('foo') // false, lastIndex = 0
517
- ```
518
-
519
- ---
520
-
521
- ## Rule 7.10: Use Loop for Min/Max Instead of Sort
522
-
523
- **Impact:** LOW
524
- **Tags:** javascript, arrays, performance, sorting, algorithms
525
-
526
- ## Use Loop for Min/Max Instead of Sort
527
-
528
- Finding the smallest or largest element only requires a single pass through the array. Sorting is wasteful and slower.
529
-
530
- **Incorrect (O(n log n) - sort to find latest):**
531
-
532
- ```typescript
533
- interface Project {
534
- id: string
535
- name: string
536
- updatedAt: number
537
- }
538
-
539
- function getLatestProject(projects: Project[]) {
540
- const sorted = [...projects].sort((a, b) => b.updatedAt - a.updatedAt)
541
- return sorted[0]
542
- }
543
- ```
544
-
545
- Sorts the entire array just to find the maximum value.
546
-
547
- **Incorrect (O(n log n) - sort for oldest and newest):**
548
-
549
- ```typescript
550
- function getOldestAndNewest(projects: Project[]) {
551
- const sorted = [...projects].sort((a, b) => a.updatedAt - b.updatedAt)
552
- return { oldest: sorted[0], newest: sorted[sorted.length - 1] }
553
- }
554
- ```
555
-
556
- Still sorts unnecessarily when only min/max are needed.
557
-
558
- **Correct (O(n) - single loop):**
559
-
560
- ```typescript
561
- function getLatestProject(projects: Project[]) {
562
- if (projects.length === 0) return null
563
-
564
- let latest = projects[0]
565
-
566
- for (let i = 1; i < projects.length; i++) {
567
- if (projects[i].updatedAt > latest.updatedAt) {
568
- latest = projects[i]
569
- }
570
- }
571
-
572
- return latest
573
- }
574
-
575
- function getOldestAndNewest(projects: Project[]) {
576
- if (projects.length === 0) return { oldest: null, newest: null }
577
-
578
- let oldest = projects[0]
579
- let newest = projects[0]
580
-
581
- for (let i = 1; i < projects.length; i++) {
582
- if (projects[i].updatedAt < oldest.updatedAt) oldest = projects[i]
583
- if (projects[i].updatedAt > newest.updatedAt) newest = projects[i]
584
- }
585
-
586
- return { oldest, newest }
587
- }
588
- ```
589
-
590
- Single pass through the array, no copying, no sorting.
591
-
592
- **Alternative (Math.min/Math.max for small arrays):**
593
-
594
- ```typescript
595
- const numbers = [5, 2, 8, 1, 9]
596
- const min = Math.min(...numbers)
597
- const max = Math.max(...numbers)
598
- ```
599
-
600
- This works for small arrays, but can be slower or just throw an error for very large arrays due to spread operator limitations. Maximal array length is approximately 124000 in Chrome 143 and 638000 in Safari 18; exact numbers may vary - see [the fiddle](https://jsfiddle.net/qw1jabsx/4/). Use the loop approach for reliability.
601
-
602
- ---
603
-
604
- ## Rule 7.11: Use Set/Map for O(1) Lookups
605
-
606
- **Impact:** LOW-MEDIUM
607
- **Tags:** javascript, set, map, data-structures, performance
608
-
609
- ## Use Set/Map for O(1) Lookups
610
-
611
- Convert arrays to Set/Map for repeated membership checks.
612
-
613
- **Incorrect (O(n) per check):**
614
-
615
- ```typescript
616
- const allowedIds = ['a', 'b', 'c', ...]
617
- items.filter(item => allowedIds.includes(item.id))
618
- ```
619
-
620
- **Correct (O(1) per check):**
621
-
622
- ```typescript
623
- const allowedIds = new Set(['a', 'b', 'c', ...])
624
- items.filter(item => allowedIds.has(item.id))
625
- ```
626
-
627
- ---
628
-
629
- ## Rule 7.12: Use toSorted() Instead of sort() for Immutability
630
-
631
- **Impact:** MEDIUM-HIGH
632
- **Tags:** javascript, arrays, immutability, react, state, mutation
633
-
634
- ## Use toSorted() Instead of sort() for Immutability
635
-
636
- `.sort()` mutates the array in place, which can cause bugs with React state and props. Use `.toSorted()` to create a new sorted array without mutation.
637
-
638
- **Incorrect (mutates original array):**
639
-
640
- ```typescript
641
- function UserList({ users }: { users: User[] }) {
642
- // Mutates the users prop array!
643
- const sorted = useMemo(
644
- () => users.sort((a, b) => a.name.localeCompare(b.name)),
645
- [users]
646
- )
647
- return <div>{sorted.map(renderUser)}</div>
648
- }
649
- ```
650
-
651
- **Correct (creates new array):**
652
-
653
- ```typescript
654
- function UserList({ users }: { users: User[] }) {
655
- // Creates new sorted array, original unchanged
656
- const sorted = useMemo(
657
- () => users.toSorted((a, b) => a.name.localeCompare(b.name)),
658
- [users]
659
- )
660
- return <div>{sorted.map(renderUser)}</div>
661
- }
662
- ```
663
-
664
- **Why this matters in React:**
665
-
666
- 1. Props/state mutations break React's immutability model - React expects props and state to be treated as read-only
667
- 2. Causes stale closure bugs - Mutating arrays inside closures (callbacks, effects) can lead to unexpected behavior
668
-
669
- **Browser support (fallback for older browsers):**
670
-
671
- `.toSorted()` is available in all modern browsers (Chrome 110+, Safari 16+, Firefox 115+, Node.js 20+). For older environments, use spread operator:
672
-
673
- ```typescript
674
- // Fallback for older browsers
675
- const sorted = [...items].sort((a, b) => a.value - b.value)
676
- ```
677
-
678
- **Other immutable array methods:**
679
-
680
- - `.toSorted()` - immutable sort
681
- - `.toReversed()` - immutable reverse
682
- - `.toSpliced()` - immutable splice
683
- - `.with()` - immutable element replacement
684
-