@kood/claude-code 0.3.12 → 0.3.14

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 (92) hide show
  1. package/dist/index.js +30 -8
  2. package/package.json +4 -4
  3. package/templates/.claude/skills/nextjs-react-best-practices/AGENTS.md +663 -0
  4. package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +269 -0
  5. package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +751 -0
  6. package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +431 -0
  7. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-defer-await.md +80 -0
  8. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-dependencies.md +36 -0
  9. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-loader.md +44 -0
  10. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-parallel.md +28 -0
  11. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  12. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-conditional.md +31 -0
  13. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  14. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-lazy-routes.md +67 -0
  15. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-preload.md +50 -0
  16. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-event-listeners.md +74 -0
  17. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-tanstack-query.md +77 -0
  18. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-batch-dom-css.md +82 -0
  19. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-function-results.md +80 -0
  20. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-property-access.md +28 -0
  21. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-storage.md +70 -0
  22. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-combine-iterations.md +32 -0
  23. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-early-exit.md +50 -0
  24. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-hoist-regexp.md +45 -0
  25. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-index-maps.md +37 -0
  26. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-length-check-first.md +49 -0
  27. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-min-max-loop.md +82 -0
  28. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-set-map-lookups.md +24 -0
  29. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  30. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  31. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-conditional-render.md +40 -0
  32. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-content-visibility.md +38 -0
  33. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  34. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-svg-precision.md +28 -0
  35. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-defer-reads.md +39 -0
  36. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-dependencies.md +45 -0
  37. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-derived-state.md +29 -0
  38. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  39. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  40. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-memo.md +44 -0
  41. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-transitions.md +40 -0
  42. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-cache-lru.md +41 -0
  43. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +67 -0
  44. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-parallel-fetching.md +60 -0
  45. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +38 -0
  46. package/templates/.claude/skills/vercel-react-best-practices/AGENTS.md +0 -2249
  47. package/templates/.claude/skills/vercel-react-best-practices/SKILL.md +0 -125
  48. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/advanced-event-handler-refs.md +0 -0
  49. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/advanced-use-latest.md +0 -0
  50. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-api-routes.md +0 -0
  51. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-defer-await.md +0 -0
  52. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-dependencies.md +0 -0
  53. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-parallel.md +0 -0
  54. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-suspense-boundaries.md +0 -0
  55. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-barrel-imports.md +0 -0
  56. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-conditional.md +0 -0
  57. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-defer-third-party.md +0 -0
  58. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-dynamic-imports.md +0 -0
  59. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-preload.md +0 -0
  60. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/client-event-listeners.md +0 -0
  61. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/client-swr-dedup.md +0 -0
  62. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-batch-dom-css.md +0 -0
  63. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-cache-function-results.md +0 -0
  64. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-cache-property-access.md +0 -0
  65. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-cache-storage.md +0 -0
  66. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-combine-iterations.md +0 -0
  67. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-early-exit.md +0 -0
  68. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-hoist-regexp.md +0 -0
  69. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-index-maps.md +0 -0
  70. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-length-check-first.md +0 -0
  71. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-min-max-loop.md +0 -0
  72. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-set-map-lookups.md +0 -0
  73. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-tosorted-immutable.md +0 -0
  74. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-activity.md +0 -0
  75. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
  76. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-conditional-render.md +0 -0
  77. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-content-visibility.md +0 -0
  78. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-hoist-jsx.md +0 -0
  79. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
  80. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-svg-precision.md +0 -0
  81. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-defer-reads.md +0 -0
  82. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-dependencies.md +0 -0
  83. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-derived-state.md +0 -0
  84. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-functional-setstate.md +0 -0
  85. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-lazy-state-init.md +0 -0
  86. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-memo.md +0 -0
  87. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-transitions.md +0 -0
  88. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-after-nonblocking.md +0 -0
  89. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-cache-lru.md +0 -0
  90. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-cache-react.md +0 -0
  91. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-parallel-fetching.md +0 -0
  92. /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-serialization.md +0 -0
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Conditional Module Loading
3
+ impact: HIGH
4
+ impactDescription: loads large data only when needed
5
+ tags: bundle, conditional-loading, lazy-loading
6
+ ---
7
+
8
+ ## Conditional Module Loading
9
+
10
+ Load large data or modules only when a feature is activated.
11
+
12
+ **Example (lazy-load animation frames):**
13
+
14
+ ```tsx
15
+ function AnimationPlayer({ enabled }: { enabled: boolean }) {
16
+ const [frames, setFrames] = useState<Frame[] | null>(null)
17
+
18
+ useEffect(() => {
19
+ if (enabled && !frames && typeof window !== 'undefined') {
20
+ import('./animation-frames.js')
21
+ .then(mod => setFrames(mod.frames))
22
+ .catch(() => setEnabled(false))
23
+ }
24
+ }, [enabled, frames])
25
+
26
+ if (!frames) return <Skeleton />
27
+ return <Canvas frames={frames} />
28
+ }
29
+ ```
30
+
31
+ The `typeof window !== 'undefined'` check prevents bundling this module for SSR, optimizing server bundle size and build speed.
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Defer Non-Critical Third-Party Libraries
3
+ impact: MEDIUM
4
+ impactDescription: loads after hydration
5
+ tags: bundle, third-party, analytics, defer
6
+ ---
7
+
8
+ ## Defer Non-Critical Third-Party Libraries
9
+
10
+ Analytics, logging, and error tracking don't block user interaction. Load them after hydration.
11
+
12
+ **Incorrect (blocks initial bundle):**
13
+
14
+ ```tsx
15
+ import { Analytics } from '@vercel/analytics/react'
16
+
17
+ export default function RootLayout({ children }) {
18
+ return (
19
+ <html>
20
+ <body>
21
+ {children}
22
+ <Analytics />
23
+ </body>
24
+ </html>
25
+ )
26
+ }
27
+ ```
28
+
29
+ **Correct (loads after hydration):**
30
+
31
+ ```tsx
32
+ import dynamic from 'next/dynamic'
33
+
34
+ const Analytics = dynamic(
35
+ () => import('@vercel/analytics/react').then(m => m.Analytics),
36
+ { ssr: false }
37
+ )
38
+
39
+ export default function RootLayout({ children }) {
40
+ return (
41
+ <html>
42
+ <body>
43
+ {children}
44
+ <Analytics />
45
+ </body>
46
+ </html>
47
+ )
48
+ }
49
+ ```
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: Route-Based Code Splitting
3
+ impact: CRITICAL
4
+ impactDescription: 30-50% smaller initial bundle
5
+ tags: bundle, lazy-loading, code-splitting, routes
6
+ ---
7
+
8
+ ## Route-Based Code Splitting
9
+
10
+ TanStack Router automatically code-splits by route. Use `lazy()` for heavy components within routes to reduce bundle size further.
11
+
12
+ **Incorrect (heavy component loaded upfront):**
13
+
14
+ ```tsx
15
+ import { createFileRoute } from '@tanstack/react-router'
16
+ import HeavyEditor from '@/components/HeavyEditor' // 500KB bundle
17
+
18
+ export const Route = createFileRoute('/editor')({
19
+ component: () => <HeavyEditor />
20
+ })
21
+ // Entire 500KB loads even if user never visits /editor
22
+ ```
23
+
24
+ **Correct (lazy load heavy components):**
25
+
26
+ ```tsx
27
+ import { createFileRoute } from '@tanstack/react-router'
28
+ import { lazy, Suspense } from 'react'
29
+
30
+ const HeavyEditor = lazy(() => import('@/components/HeavyEditor'))
31
+
32
+ export const Route = createFileRoute('/editor')({
33
+ component: () => (
34
+ <Suspense fallback={<EditorSkeleton />}>
35
+ <HeavyEditor />
36
+ </Suspense>
37
+ )
38
+ })
39
+ // 500KB only loads when user navigates to /editor
40
+ ```
41
+
42
+ **For multiple heavy dependencies:**
43
+
44
+ ```tsx
45
+ import { lazy, Suspense } from 'react'
46
+
47
+ const ChartComponent = lazy(() => import('@/components/ChartComponent'))
48
+ const PDFViewer = lazy(() => import('@/components/PDFViewer'))
49
+ const VideoPlayer = lazy(() => import('@/components/VideoPlayer'))
50
+
51
+ export const Route = createFileRoute('/dashboard')({
52
+ component: () => (
53
+ <div>
54
+ <Suspense fallback={<ChartSkeleton />}>
55
+ <ChartComponent />
56
+ </Suspense>
57
+ <Suspense fallback={<PDFSkeleton />}>
58
+ <PDFViewer />
59
+ </Suspense>
60
+ </div>
61
+ )
62
+ })
63
+ ```
64
+
65
+ Heavy libraries to consider lazy loading: chart libraries (recharts, chart.js), rich text editors (tiptap, slate), PDF viewers, video players, 3D renderers, data visualization.
66
+
67
+ This reduces initial bundle by 30-50% and improves Time to Interactive.
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: Preload Based on User Intent
3
+ impact: MEDIUM
4
+ impactDescription: reduces perceived latency
5
+ tags: bundle, preload, user-intent, hover
6
+ ---
7
+
8
+ ## Preload Based on User Intent
9
+
10
+ Preload heavy bundles before they're needed to reduce perceived latency.
11
+
12
+ **Example (preload on hover/focus):**
13
+
14
+ ```tsx
15
+ function EditorButton({ onClick }: { onClick: () => void }) {
16
+ const preload = () => {
17
+ if (typeof window !== 'undefined') {
18
+ void import('./monaco-editor')
19
+ }
20
+ }
21
+
22
+ return (
23
+ <button
24
+ onMouseEnter={preload}
25
+ onFocus={preload}
26
+ onClick={onClick}
27
+ >
28
+ Open Editor
29
+ </button>
30
+ )
31
+ }
32
+ ```
33
+
34
+ **Example (preload when feature flag is enabled):**
35
+
36
+ ```tsx
37
+ function FlagsProvider({ children, flags }: Props) {
38
+ useEffect(() => {
39
+ if (flags.editorEnabled && typeof window !== 'undefined') {
40
+ void import('./monaco-editor').then(mod => mod.init())
41
+ }
42
+ }, [flags.editorEnabled])
43
+
44
+ return <FlagsContext.Provider value={flags}>
45
+ {children}
46
+ </FlagsContext.Provider>
47
+ }
48
+ ```
49
+
50
+ The `typeof window !== 'undefined'` check prevents bundling preloaded modules for SSR, optimizing server bundle size and build speed.
@@ -0,0 +1,74 @@
1
+ ---
2
+ title: Deduplicate Global Event Listeners
3
+ impact: LOW
4
+ impactDescription: single listener for N components
5
+ tags: client, swr, event-listeners, subscription
6
+ ---
7
+
8
+ ## Deduplicate Global Event Listeners
9
+
10
+ Use `useSWRSubscription()` to share global event listeners across component instances.
11
+
12
+ **Incorrect (N instances = N listeners):**
13
+
14
+ ```tsx
15
+ function useKeyboardShortcut(key: string, callback: () => void) {
16
+ useEffect(() => {
17
+ const handler = (e: KeyboardEvent) => {
18
+ if (e.metaKey && e.key === key) {
19
+ callback()
20
+ }
21
+ }
22
+ window.addEventListener('keydown', handler)
23
+ return () => window.removeEventListener('keydown', handler)
24
+ }, [key, callback])
25
+ }
26
+ ```
27
+
28
+ When using the `useKeyboardShortcut` hook multiple times, each instance will register a new listener.
29
+
30
+ **Correct (N instances = 1 listener):**
31
+
32
+ ```tsx
33
+ import useSWRSubscription from 'swr/subscription'
34
+
35
+ // Module-level Map to track callbacks per key
36
+ const keyCallbacks = new Map<string, Set<() => void>>()
37
+
38
+ function useKeyboardShortcut(key: string, callback: () => void) {
39
+ // Register this callback in the Map
40
+ useEffect(() => {
41
+ if (!keyCallbacks.has(key)) {
42
+ keyCallbacks.set(key, new Set())
43
+ }
44
+ keyCallbacks.get(key)!.add(callback)
45
+
46
+ return () => {
47
+ const set = keyCallbacks.get(key)
48
+ if (set) {
49
+ set.delete(callback)
50
+ if (set.size === 0) {
51
+ keyCallbacks.delete(key)
52
+ }
53
+ }
54
+ }
55
+ }, [key, callback])
56
+
57
+ useSWRSubscription('global-keydown', () => {
58
+ const handler = (e: KeyboardEvent) => {
59
+ if (e.metaKey && keyCallbacks.has(e.key)) {
60
+ keyCallbacks.get(e.key)!.forEach(cb => cb())
61
+ }
62
+ }
63
+ window.addEventListener('keydown', handler)
64
+ return () => window.removeEventListener('keydown', handler)
65
+ })
66
+ }
67
+
68
+ function Profile() {
69
+ // Multiple shortcuts will share the same listener
70
+ useKeyboardShortcut('p', () => { /* ... */ })
71
+ useKeyboardShortcut('k', () => { /* ... */ })
72
+ // ...
73
+ }
74
+ ```
@@ -0,0 +1,77 @@
1
+ ---
2
+ title: Use TanStack Query for Automatic Caching and Deduplication
3
+ impact: MEDIUM-HIGH
4
+ impactDescription: eliminates duplicate requests
5
+ tags: client, cache, tanstack-query, deduplication
6
+ ---
7
+
8
+ ## Use TanStack Query for Automatic Caching and Deduplication
9
+
10
+ Wrap server function calls with TanStack Query to enable automatic request deduplication, caching, and background refetching.
11
+
12
+ **Incorrect (no deduplication, each component fetches):**
13
+
14
+ ```tsx
15
+ import { useState, useEffect } from 'react'
16
+ import { getUsers } from '@/functions/data'
17
+
18
+ function UserList() {
19
+ const [users, setUsers] = useState([])
20
+
21
+ useEffect(() => {
22
+ getUsers().then(setUsers)
23
+ }, [])
24
+
25
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
26
+ }
27
+
28
+ // If UserList is used 3 times on a page, getUsers() is called 3 times
29
+ ```
30
+
31
+ **Correct (automatic deduplication, single request):**
32
+
33
+ ```tsx
34
+ import { useQuery } from '@tanstack/react-query'
35
+ import { getUsers } from '@/functions/data'
36
+
37
+ function UserList() {
38
+ const { data: users = [] } = useQuery({
39
+ queryKey: ['users'],
40
+ queryFn: () => getUsers()
41
+ })
42
+
43
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
44
+ }
45
+
46
+ // Multiple instances share one request, with automatic cache invalidation
47
+ ```
48
+
49
+ **With mutations:**
50
+
51
+ ```tsx
52
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
53
+ import { getUsers, createUser } from '@/functions/data'
54
+
55
+ function UserManager() {
56
+ const queryClient = useQueryClient()
57
+
58
+ const { data: users = [] } = useQuery({
59
+ queryKey: ['users'],
60
+ queryFn: () => getUsers()
61
+ })
62
+
63
+ const mutation = useMutation({
64
+ mutationFn: createUser,
65
+ onSuccess: () => {
66
+ // Automatically refetch users
67
+ queryClient.invalidateQueries({ queryKey: ['users'] })
68
+ }
69
+ })
70
+
71
+ return <div>...</div>
72
+ }
73
+ ```
74
+
75
+ TanStack Query provides: request deduplication, background refetching, cache invalidation, optimistic updates, retry logic, and loading/error states.
76
+
77
+ Reference: [TanStack Query](https://tanstack.com/query)
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: Batch DOM CSS Changes
3
+ impact: MEDIUM
4
+ impactDescription: reduces reflows/repaints
5
+ tags: javascript, dom, css, performance, reflow
6
+ ---
7
+
8
+ ## Batch DOM CSS Changes
9
+
10
+ Avoid changing styles one property at a time. Group multiple CSS changes together via classes or `cssText` to minimize browser reflows.
11
+
12
+ **Incorrect (multiple reflows):**
13
+
14
+ ```typescript
15
+ function updateElementStyles(element: HTMLElement) {
16
+ // Each line triggers a reflow
17
+ element.style.width = '100px'
18
+ element.style.height = '200px'
19
+ element.style.backgroundColor = 'blue'
20
+ element.style.border = '1px solid black'
21
+ }
22
+ ```
23
+
24
+ **Correct (add class - single reflow):**
25
+
26
+ ```typescript
27
+ // CSS file
28
+ .highlighted-box {
29
+ width: 100px;
30
+ height: 200px;
31
+ background-color: blue;
32
+ border: 1px solid black;
33
+ }
34
+
35
+ // JavaScript
36
+ function updateElementStyles(element: HTMLElement) {
37
+ element.classList.add('highlighted-box')
38
+ }
39
+ ```
40
+
41
+ **Correct (change cssText - single reflow):**
42
+
43
+ ```typescript
44
+ function updateElementStyles(element: HTMLElement) {
45
+ element.style.cssText = `
46
+ width: 100px;
47
+ height: 200px;
48
+ background-color: blue;
49
+ border: 1px solid black;
50
+ `
51
+ }
52
+ ```
53
+
54
+ **React example:**
55
+
56
+ ```tsx
57
+ // Incorrect: changing styles one by one
58
+ function Box({ isHighlighted }: { isHighlighted: boolean }) {
59
+ const ref = useRef<HTMLDivElement>(null)
60
+
61
+ useEffect(() => {
62
+ if (ref.current && isHighlighted) {
63
+ ref.current.style.width = '100px'
64
+ ref.current.style.height = '200px'
65
+ ref.current.style.backgroundColor = 'blue'
66
+ }
67
+ }, [isHighlighted])
68
+
69
+ return <div ref={ref}>Content</div>
70
+ }
71
+
72
+ // Correct: toggle class
73
+ function Box({ isHighlighted }: { isHighlighted: boolean }) {
74
+ return (
75
+ <div className={isHighlighted ? 'highlighted-box' : ''}>
76
+ Content
77
+ </div>
78
+ )
79
+ }
80
+ ```
81
+
82
+ Prefer CSS classes over inline styles when possible. Classes are cached by the browser and provide better separation of concerns.
@@ -0,0 +1,80 @@
1
+ ---
2
+ title: Cache Repeated Function Calls
3
+ impact: MEDIUM
4
+ impactDescription: avoid redundant computation
5
+ tags: javascript, cache, memoization, performance
6
+ ---
7
+
8
+ ## Cache Repeated Function Calls
9
+
10
+ Use a module-level Map to cache function results when the same function is called repeatedly with the same inputs during render.
11
+
12
+ **Incorrect (redundant computation):**
13
+
14
+ ```typescript
15
+ function ProjectList({ projects }: { projects: Project[] }) {
16
+ return (
17
+ <div>
18
+ {projects.map(project => {
19
+ // slugify() called 100+ times for same project names
20
+ const slug = slugify(project.name)
21
+
22
+ return <ProjectCard key={project.id} slug={slug} />
23
+ })}
24
+ </div>
25
+ )
26
+ }
27
+ ```
28
+
29
+ **Correct (cached results):**
30
+
31
+ ```typescript
32
+ // Module-level cache
33
+ const slugifyCache = new Map<string, string>()
34
+
35
+ function cachedSlugify(text: string): string {
36
+ if (slugifyCache.has(text)) {
37
+ return slugifyCache.get(text)!
38
+ }
39
+ const result = slugify(text)
40
+ slugifyCache.set(text, result)
41
+ return result
42
+ }
43
+
44
+ function ProjectList({ projects }: { projects: Project[] }) {
45
+ return (
46
+ <div>
47
+ {projects.map(project => {
48
+ // Computed only once per unique project name
49
+ const slug = cachedSlugify(project.name)
50
+
51
+ return <ProjectCard key={project.id} slug={slug} />
52
+ })}
53
+ </div>
54
+ )
55
+ }
56
+ ```
57
+
58
+ **Simpler pattern for single-value functions:**
59
+
60
+ ```typescript
61
+ let isLoggedInCache: boolean | null = null
62
+
63
+ function isLoggedIn(): boolean {
64
+ if (isLoggedInCache !== null) {
65
+ return isLoggedInCache
66
+ }
67
+
68
+ isLoggedInCache = document.cookie.includes('auth=')
69
+ return isLoggedInCache
70
+ }
71
+
72
+ // Clear cache when auth changes
73
+ function onAuthChange() {
74
+ isLoggedInCache = null
75
+ }
76
+ ```
77
+
78
+ Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
79
+
80
+ Reference: [How we made the Vercel Dashboard twice as fast](https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast)
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Cache Property Access in Loops
3
+ impact: LOW-MEDIUM
4
+ impactDescription: reduces lookups
5
+ tags: javascript, loops, optimization, caching
6
+ ---
7
+
8
+ ## Cache Property Access in Loops
9
+
10
+ Cache object property lookups in hot paths.
11
+
12
+ **Incorrect (3 lookups × N iterations):**
13
+
14
+ ```typescript
15
+ for (let i = 0; i < arr.length; i++) {
16
+ process(obj.config.settings.value)
17
+ }
18
+ ```
19
+
20
+ **Correct (1 lookup total):**
21
+
22
+ ```typescript
23
+ const value = obj.config.settings.value
24
+ const len = arr.length
25
+ for (let i = 0; i < len; i++) {
26
+ process(value)
27
+ }
28
+ ```
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: Cache Storage API Calls
3
+ impact: LOW-MEDIUM
4
+ impactDescription: reduces expensive I/O
5
+ tags: javascript, localStorage, storage, caching, performance
6
+ ---
7
+
8
+ ## Cache Storage API Calls
9
+
10
+ `localStorage`, `sessionStorage`, and `document.cookie` are synchronous and expensive. Cache reads in memory.
11
+
12
+ **Incorrect (reads storage on every call):**
13
+
14
+ ```typescript
15
+ function getTheme() {
16
+ return localStorage.getItem('theme') ?? 'light'
17
+ }
18
+ // Called 10 times = 10 storage reads
19
+ ```
20
+
21
+ **Correct (Map cache):**
22
+
23
+ ```typescript
24
+ const storageCache = new Map<string, string | null>()
25
+
26
+ function getLocalStorage(key: string) {
27
+ if (!storageCache.has(key)) {
28
+ storageCache.set(key, localStorage.getItem(key))
29
+ }
30
+ return storageCache.get(key)
31
+ }
32
+
33
+ function setLocalStorage(key: string, value: string) {
34
+ localStorage.setItem(key, value)
35
+ storageCache.set(key, value) // keep cache in sync
36
+ }
37
+ ```
38
+
39
+ Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
40
+
41
+ **Cookie caching:**
42
+
43
+ ```typescript
44
+ let cookieCache: Record<string, string> | null = null
45
+
46
+ function getCookie(name: string) {
47
+ if (!cookieCache) {
48
+ cookieCache = Object.fromEntries(
49
+ document.cookie.split('; ').map(c => c.split('='))
50
+ )
51
+ }
52
+ return cookieCache[name]
53
+ }
54
+ ```
55
+
56
+ **Important (invalidate on external changes):**
57
+
58
+ If storage can change externally (another tab, server-set cookies), invalidate cache:
59
+
60
+ ```typescript
61
+ window.addEventListener('storage', (e) => {
62
+ if (e.key) storageCache.delete(e.key)
63
+ })
64
+
65
+ document.addEventListener('visibilitychange', () => {
66
+ if (document.visibilityState === 'visible') {
67
+ storageCache.clear()
68
+ }
69
+ })
70
+ ```
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Combine Multiple Array Iterations
3
+ impact: LOW-MEDIUM
4
+ impactDescription: reduces iterations
5
+ tags: javascript, arrays, loops, performance
6
+ ---
7
+
8
+ ## Combine Multiple Array Iterations
9
+
10
+ Multiple `.filter()` or `.map()` calls iterate the array multiple times. Combine into one loop.
11
+
12
+ **Incorrect (3 iterations):**
13
+
14
+ ```typescript
15
+ const admins = users.filter(u => u.isAdmin)
16
+ const testers = users.filter(u => u.isTester)
17
+ const inactive = users.filter(u => !u.isActive)
18
+ ```
19
+
20
+ **Correct (1 iteration):**
21
+
22
+ ```typescript
23
+ const admins: User[] = []
24
+ const testers: User[] = []
25
+ const inactive: User[] = []
26
+
27
+ for (const user of users) {
28
+ if (user.isAdmin) admins.push(user)
29
+ if (user.isTester) testers.push(user)
30
+ if (!user.isActive) inactive.push(user)
31
+ }
32
+ ```
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: Early Return from Functions
3
+ impact: LOW-MEDIUM
4
+ impactDescription: avoids unnecessary computation
5
+ tags: javascript, functions, optimization, early-return
6
+ ---
7
+
8
+ ## Early Return from Functions
9
+
10
+ Return early when result is determined to skip unnecessary processing.
11
+
12
+ **Incorrect (processes all items even after finding answer):**
13
+
14
+ ```typescript
15
+ function validateUsers(users: User[]) {
16
+ let hasError = false
17
+ let errorMessage = ''
18
+
19
+ for (const user of users) {
20
+ if (!user.email) {
21
+ hasError = true
22
+ errorMessage = 'Email required'
23
+ }
24
+ if (!user.name) {
25
+ hasError = true
26
+ errorMessage = 'Name required'
27
+ }
28
+ // Continues checking all users even after error found
29
+ }
30
+
31
+ return hasError ? { valid: false, error: errorMessage } : { valid: true }
32
+ }
33
+ ```
34
+
35
+ **Correct (returns immediately on first error):**
36
+
37
+ ```typescript
38
+ function validateUsers(users: User[]) {
39
+ for (const user of users) {
40
+ if (!user.email) {
41
+ return { valid: false, error: 'Email required' }
42
+ }
43
+ if (!user.name) {
44
+ return { valid: false, error: 'Name required' }
45
+ }
46
+ }
47
+
48
+ return { valid: true }
49
+ }
50
+ ```