@vetala/vetala 0.1.0-beta
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.
Potentially problematic release.
This version of @vetala/vetala might be problematic. Click here for more details.
- package/CONTRIBUTING.md +77 -0
- package/LICENSE +184 -0
- package/README.md +136 -0
- package/THIRD_PARTY_LICENSES.md +17 -0
- package/dist/src/agent.d.ts +30 -0
- package/dist/src/agent.js +216 -0
- package/dist/src/agent.js.map +1 -0
- package/dist/src/approvals.d.ts +18 -0
- package/dist/src/approvals.js +81 -0
- package/dist/src/approvals.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +87 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +12 -0
- package/dist/src/config.js +183 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context-memory.d.ts +7 -0
- package/dist/src/context-memory.js +96 -0
- package/dist/src/context-memory.js.map +1 -0
- package/dist/src/ink/command-suggestions.d.ts +7 -0
- package/dist/src/ink/command-suggestions.js +179 -0
- package/dist/src/ink/command-suggestions.js.map +1 -0
- package/dist/src/ink/ink-terminal-ui.d.ts +36 -0
- package/dist/src/ink/ink-terminal-ui.js +79 -0
- package/dist/src/ink/ink-terminal-ui.js.map +1 -0
- package/dist/src/ink/repl-app.d.ts +9 -0
- package/dist/src/ink/repl-app.js +789 -0
- package/dist/src/ink/repl-app.js.map +1 -0
- package/dist/src/ink/transcript-cards.d.ts +6 -0
- package/dist/src/ink/transcript-cards.js +24 -0
- package/dist/src/ink/transcript-cards.js.map +1 -0
- package/dist/src/path-policy.d.ts +11 -0
- package/dist/src/path-policy.js +67 -0
- package/dist/src/path-policy.js.map +1 -0
- package/dist/src/process-utils.d.ts +13 -0
- package/dist/src/process-utils.js +52 -0
- package/dist/src/process-utils.js.map +1 -0
- package/dist/src/repl.d.ts +9 -0
- package/dist/src/repl.js +13 -0
- package/dist/src/repl.js.map +1 -0
- package/dist/src/sarvam/client.d.ts +15 -0
- package/dist/src/sarvam/client.js +208 -0
- package/dist/src/sarvam/client.js.map +1 -0
- package/dist/src/sarvam/models.d.ts +2 -0
- package/dist/src/sarvam/models.js +7 -0
- package/dist/src/sarvam/models.js.map +1 -0
- package/dist/src/search-provider.d.ts +6 -0
- package/dist/src/search-provider.js +8 -0
- package/dist/src/search-provider.js.map +1 -0
- package/dist/src/session-store.d.ts +19 -0
- package/dist/src/session-store.js +318 -0
- package/dist/src/session-store.js.map +1 -0
- package/dist/src/skills/runtime.d.ts +26 -0
- package/dist/src/skills/runtime.js +317 -0
- package/dist/src/skills/runtime.js.map +1 -0
- package/dist/src/skills/types.d.ts +25 -0
- package/dist/src/skills/types.js +2 -0
- package/dist/src/skills/types.js.map +1 -0
- package/dist/src/terminal-ui.d.ts +29 -0
- package/dist/src/terminal-ui.js +236 -0
- package/dist/src/terminal-ui.js.map +1 -0
- package/dist/src/tools/filesystem.d.ts +2 -0
- package/dist/src/tools/filesystem.js +622 -0
- package/dist/src/tools/filesystem.js.map +1 -0
- package/dist/src/tools/git.d.ts +2 -0
- package/dist/src/tools/git.js +326 -0
- package/dist/src/tools/git.js.map +1 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.js +21 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/registry.d.ts +15 -0
- package/dist/src/tools/registry.js +59 -0
- package/dist/src/tools/registry.js.map +1 -0
- package/dist/src/tools/shell.d.ts +2 -0
- package/dist/src/tools/shell.js +97 -0
- package/dist/src/tools/shell.js.map +1 -0
- package/dist/src/tools/skill.d.ts +3 -0
- package/dist/src/tools/skill.js +130 -0
- package/dist/src/tools/skill.js.map +1 -0
- package/dist/src/tools/web.d.ts +3 -0
- package/dist/src/tools/web.js +144 -0
- package/dist/src/tools/web.js.map +1 -0
- package/dist/src/types.d.ts +236 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/workspace-trust.d.ts +3 -0
- package/dist/src/workspace-trust.js +31 -0
- package/dist/src/workspace-trust.js.map +1 -0
- package/dist/src/xdg.d.ts +9 -0
- package/dist/src/xdg.js +77 -0
- package/dist/src/xdg.js.map +1 -0
- package/package.json +57 -0
- package/skill/agents-md-generator/SKILL.md +75 -0
- package/skill/agents-md-generator/references/agents_md_template.md +160 -0
- package/skill/agents-md-generator/references/loc_measurement.md +67 -0
- package/skill/agents-md-generator/references/monorepo_detection.md +78 -0
- package/skill/agents-md-generator/references/monorepo_strategy.md +60 -0
- package/skill/agents-md-generator/references/read_only_commands.md +151 -0
- package/skill/agents-md-generator/references/update_strategy.md +160 -0
- package/skill/agents-md-generator/references/working_agreements.md +53 -0
- package/skill/biz-opportunity-scout/SKILL.md +53 -0
- package/skill/biz-opportunity-scout/references/competitive_analysis.md +84 -0
- package/skill/biz-opportunity-scout/references/market_sizing.md +68 -0
- package/skill/biz-opportunity-scout/references/pmf_indicators.md +94 -0
- package/skill/biz-opportunity-scout/references/report_template.md +243 -0
- package/skill/biz-opportunity-scout/references/unit_economics.md +97 -0
- package/skill/code-review/SKILL.md +86 -0
- package/skill/code-review/references/change_analysis.md +116 -0
- package/skill/code-review/references/git_operations.md +115 -0
- package/skill/code-review/references/impact_detection.md +149 -0
- package/skill/code-review/references/output_format.md +137 -0
- package/skill/code-review/references/severity_criteria.md +100 -0
- package/skill/code-security-audit/SKILL.md +123 -0
- package/skill/code-security-audit/references/audit_process.md +277 -0
- package/skill/code-security-audit/references/remediation_patterns.md +599 -0
- package/skill/code-security-audit/references/report_format.md +391 -0
- package/skill/code-security-audit/references/security_domains.md +830 -0
- package/skill/code-security-audit/references/vulnerability_patterns.md +813 -0
- package/skill/composition-patterns/SKILL.md +83 -0
- package/skill/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/skill/composition-patterns/rules/architecture-compound-components.md +112 -0
- package/skill/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/skill/composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/skill/composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/skill/composition-patterns/rules/state-context-interface.md +191 -0
- package/skill/composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/skill/composition-patterns/rules/state-lift-state.md +125 -0
- package/skill/deploy-to-vercel/SKILL.md +293 -0
- package/skill/deploy-to-vercel/resources/deploy-sandbox.sh +301 -0
- package/skill/deploy-to-vercel/resources/deploy.sh +301 -0
- package/skill/doc/SKILL_GUIDELINES.md +138 -0
- package/skill/git-workflow/SKILL.md +94 -0
- package/skill/git-workflow/references/advanced-git.md +632 -0
- package/skill/git-workflow/references/branching-strategies.md +344 -0
- package/skill/git-workflow/references/ci-cd-integration.md +683 -0
- package/skill/git-workflow/references/code-quality-tools.md +351 -0
- package/skill/git-workflow/references/commit-conventions.md +439 -0
- package/skill/git-workflow/references/github-releases.md +288 -0
- package/skill/git-workflow/references/pull-request-workflow.md +773 -0
- package/skill/git-workflow/scripts/verify-git-workflow.sh +263 -0
- package/skill/jetbrains-vmoptions/SKILL.md +51 -0
- package/skill/jetbrains-vmoptions/references/common-options.md +357 -0
- package/skill/jetbrains-vmoptions/references/gc-options.md +350 -0
- package/skill/jetbrains-vmoptions/references/memory-options.md +339 -0
- package/skill/jetbrains-vmoptions/references/prerequisite-check.md +65 -0
- package/skill/kysely-converter/SKILL.md +62 -0
- package/skill/kysely-converter/references/delete.md +323 -0
- package/skill/kysely-converter/references/insert.md +386 -0
- package/skill/kysely-converter/references/operators.md +331 -0
- package/skill/kysely-converter/references/select.md +1000 -0
- package/skill/kysely-converter/references/update.md +349 -0
- package/skill/kysely-converter/references/window_function.md +537 -0
- package/skill/react-best-practices/SKILL.md +131 -0
- package/skill/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skill/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skill/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skill/react-best-practices/rules/async-api-routes.md +38 -0
- package/skill/react-best-practices/rules/async-defer-await.md +80 -0
- package/skill/react-best-practices/rules/async-dependencies.md +51 -0
- package/skill/react-best-practices/rules/async-parallel.md +28 -0
- package/skill/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skill/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/skill/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skill/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skill/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skill/react-best-practices/rules/bundle-preload.md +50 -0
- package/skill/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skill/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skill/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skill/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skill/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skill/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skill/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skill/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skill/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skill/react-best-practices/rules/js-early-exit.md +50 -0
- package/skill/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skill/react-best-practices/rules/js-index-maps.md +37 -0
- package/skill/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skill/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skill/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skill/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skill/react-best-practices/rules/rendering-activity.md +26 -0
- package/skill/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skill/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skill/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skill/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skill/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skill/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skill/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skill/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skill/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skill/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skill/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skill/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skill/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skill/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skill/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skill/react-best-practices/rules/rerender-memo.md +44 -0
- package/skill/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skill/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skill/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skill/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skill/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skill/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skill/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skill/react-best-practices/rules/server-cache-react.md +76 -0
- package/skill/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skill/react-best-practices/rules/server-hoist-static-io.md +142 -0
- package/skill/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skill/react-best-practices/rules/server-serialization.md +38 -0
- package/skill/react-native-skills/SKILL.md +115 -0
- package/skill/react-native-skills/rules/animation-derived-value.md +53 -0
- package/skill/react-native-skills/rules/animation-gesture-detector-press.md +95 -0
- package/skill/react-native-skills/rules/animation-gpu-properties.md +65 -0
- package/skill/react-native-skills/rules/design-system-compound-components.md +66 -0
- package/skill/react-native-skills/rules/fonts-config-plugin.md +71 -0
- package/skill/react-native-skills/rules/imports-design-system-folder.md +68 -0
- package/skill/react-native-skills/rules/js-hoist-intl.md +61 -0
- package/skill/react-native-skills/rules/list-performance-callbacks.md +44 -0
- package/skill/react-native-skills/rules/list-performance-function-references.md +132 -0
- package/skill/react-native-skills/rules/list-performance-images.md +53 -0
- package/skill/react-native-skills/rules/list-performance-inline-objects.md +97 -0
- package/skill/react-native-skills/rules/list-performance-item-expensive.md +94 -0
- package/skill/react-native-skills/rules/list-performance-item-memo.md +82 -0
- package/skill/react-native-skills/rules/list-performance-item-types.md +104 -0
- package/skill/react-native-skills/rules/list-performance-virtualize.md +67 -0
- package/skill/react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
- package/skill/react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
- package/skill/react-native-skills/rules/navigation-native-navigators.md +188 -0
- package/skill/react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
- package/skill/react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
- package/skill/react-native-skills/rules/react-state-dispatcher.md +91 -0
- package/skill/react-native-skills/rules/react-state-fallback.md +56 -0
- package/skill/react-native-skills/rules/react-state-minimize.md +65 -0
- package/skill/react-native-skills/rules/rendering-no-falsy-and.md +74 -0
- package/skill/react-native-skills/rules/rendering-text-in-text-component.md +36 -0
- package/skill/react-native-skills/rules/scroll-position-no-state.md +82 -0
- package/skill/react-native-skills/rules/state-ground-truth.md +80 -0
- package/skill/react-native-skills/rules/ui-expo-image.md +66 -0
- package/skill/react-native-skills/rules/ui-image-gallery.md +104 -0
- package/skill/react-native-skills/rules/ui-measure-views.md +78 -0
- package/skill/react-native-skills/rules/ui-menus.md +174 -0
- package/skill/react-native-skills/rules/ui-native-modals.md +77 -0
- package/skill/react-native-skills/rules/ui-pressable.md +61 -0
- package/skill/react-native-skills/rules/ui-safe-area-scroll.md +65 -0
- package/skill/react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
- package/skill/react-native-skills/rules/ui-styling.md +87 -0
- package/skill/react-vite-guide/SKILL.md +101 -0
- package/skill/react-vite-guide/references/composition-patterns.md +709 -0
- package/skill/react-vite-guide/references/performance-optimization.md +1222 -0
- package/skill/react-vite-guide/references/vite-specific.md +385 -0
- package/skill/react-vite-guide/references/web-interface.md +146 -0
- package/skill/skill-maker/SKILL.md +52 -0
- package/skill/skill-maker/references/content_spec.md +67 -0
- package/skill/skill-maker/references/frontmatter_spec.md +96 -0
- package/skill/skill-maker/references/input_validation.md +90 -0
- package/skill/skill-maker/references/skill_structure.md +74 -0
- package/skill/system-prompt-creator/SKILL.md +50 -0
- package/skill/system-prompt-creator/references/data_format_selection.md +135 -0
- package/skill/system-prompt-creator/references/multi_prompt_architecture.md +386 -0
- package/skill/system-prompt-creator/references/prompt_structure.md +140 -0
- package/skill/system-prompt-creator/references/quality_criteria.md +83 -0
- package/skill/typst-creator/SKILL.md +51 -0
- package/skill/typst-creator/references/layout.md +401 -0
- package/skill/typst-creator/references/math.md +297 -0
- package/skill/typst-creator/references/scripting.md +237 -0
- package/skill/typst-creator/references/styling.md +217 -0
- package/skill/typst-creator/references/syntax.md +234 -0
- package/skill/web-design-guidelines/SKILL.md +35 -0
- package/terminal.png +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Compressed Images in Lists
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: faster load times, less memory
|
|
5
|
+
tags: lists, images, performance, optimization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Compressed Images in Lists
|
|
9
|
+
|
|
10
|
+
Always load compressed, appropriately-sized images in lists. Full-resolution
|
|
11
|
+
images consume excessive memory and cause scroll jank. Request thumbnails from
|
|
12
|
+
your server or use an image CDN with resize parameters.
|
|
13
|
+
|
|
14
|
+
**Incorrect (full-resolution images):**
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
function ProductItem({ product }: { product: Product }) {
|
|
18
|
+
return (
|
|
19
|
+
<View>
|
|
20
|
+
{/* 4000x3000 image loaded for a 100x100 thumbnail */}
|
|
21
|
+
<Image
|
|
22
|
+
source={{ uri: product.imageUrl }}
|
|
23
|
+
style={{ width: 100, height: 100 }}
|
|
24
|
+
/>
|
|
25
|
+
<Text>{product.name}</Text>
|
|
26
|
+
</View>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Correct (request appropriately-sized image):**
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
function ProductItem({ product }: { product: Product }) {
|
|
35
|
+
// Request a 200x200 image (2x for retina)
|
|
36
|
+
const thumbnailUrl = `${product.imageUrl}?w=200&h=200&fit=cover`
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<View>
|
|
40
|
+
<Image
|
|
41
|
+
source={{ uri: thumbnailUrl }}
|
|
42
|
+
style={{ width: 100, height: 100 }}
|
|
43
|
+
contentFit='cover'
|
|
44
|
+
/>
|
|
45
|
+
<Text>{product.name}</Text>
|
|
46
|
+
</View>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Use an optimized image component with built-in caching and placeholder support,
|
|
52
|
+
such as `expo-image` or `SolitoImage` (which uses `expo-image` under the hood).
|
|
53
|
+
Request images at 2x the display size for retina screens.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Inline Objects in renderItem
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents unnecessary re-renders of memoized list items
|
|
5
|
+
tags: lists, performance, flatlist, virtualization, memo
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Inline Objects in renderItem
|
|
9
|
+
|
|
10
|
+
Don't create new objects inside `renderItem` to pass as props. Inline objects
|
|
11
|
+
create new references on every render, breaking memoization. Pass primitive
|
|
12
|
+
values directly from `item` instead.
|
|
13
|
+
|
|
14
|
+
**Incorrect (inline object breaks memoization):**
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
function UserList({ users }: { users: User[] }) {
|
|
18
|
+
return (
|
|
19
|
+
<LegendList
|
|
20
|
+
data={users}
|
|
21
|
+
renderItem={({ item }) => (
|
|
22
|
+
<UserRow
|
|
23
|
+
// Bad: new object on every render
|
|
24
|
+
user={{ id: item.id, name: item.name, avatar: item.avatar }}
|
|
25
|
+
/>
|
|
26
|
+
)}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Incorrect (inline style object):**
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
renderItem={({ item }) => (
|
|
36
|
+
<UserRow
|
|
37
|
+
name={item.name}
|
|
38
|
+
// Bad: new style object on every render
|
|
39
|
+
style={{ backgroundColor: item.isActive ? 'green' : 'gray' }}
|
|
40
|
+
/>
|
|
41
|
+
)}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Correct (pass item directly or primitives):**
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
function UserList({ users }: { users: User[] }) {
|
|
48
|
+
return (
|
|
49
|
+
<LegendList
|
|
50
|
+
data={users}
|
|
51
|
+
renderItem={({ item }) => (
|
|
52
|
+
// Good: pass the item directly
|
|
53
|
+
<UserRow user={item} />
|
|
54
|
+
)}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Correct (pass primitives, derive inside child):**
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
renderItem={({ item }) => (
|
|
64
|
+
<UserRow
|
|
65
|
+
id={item.id}
|
|
66
|
+
name={item.name}
|
|
67
|
+
isActive={item.isActive}
|
|
68
|
+
/>
|
|
69
|
+
)}
|
|
70
|
+
|
|
71
|
+
const UserRow = memo(function UserRow({ id, name, isActive }: Props) {
|
|
72
|
+
// Good: derive style inside memoized component
|
|
73
|
+
const backgroundColor = isActive ? 'green' : 'gray'
|
|
74
|
+
return <View style={[styles.row, { backgroundColor }]}>{/* ... */}</View>
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Correct (hoist static styles in module scope):**
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
const activeStyle = { backgroundColor: 'green' }
|
|
82
|
+
const inactiveStyle = { backgroundColor: 'gray' }
|
|
83
|
+
|
|
84
|
+
renderItem={({ item }) => (
|
|
85
|
+
<UserRow
|
|
86
|
+
name={item.name}
|
|
87
|
+
// Good: stable references
|
|
88
|
+
style={item.isActive ? activeStyle : inactiveStyle}
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Passing primitives or stable references allows `memo()` to skip re-renders when
|
|
94
|
+
the actual values haven't changed.
|
|
95
|
+
|
|
96
|
+
**Note:** If you have the React Compiler enabled, it handles memoization
|
|
97
|
+
automatically and these manual optimizations become less critical.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Keep List Items Lightweight
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: reduces render time for visible items during scroll
|
|
5
|
+
tags: lists, performance, virtualization, hooks
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Keep List Items Lightweight
|
|
9
|
+
|
|
10
|
+
List items should be as inexpensive as possible to render. Minimize hooks, avoid
|
|
11
|
+
queries, and limit React Context access. Virtualized lists render many items
|
|
12
|
+
during scroll—expensive items cause jank.
|
|
13
|
+
|
|
14
|
+
**Incorrect (heavy list item):**
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
function ProductRow({ id }: { id: string }) {
|
|
18
|
+
// Bad: query inside list item
|
|
19
|
+
const { data: product } = useQuery(['product', id], () => fetchProduct(id))
|
|
20
|
+
// Bad: multiple context accesses
|
|
21
|
+
const theme = useContext(ThemeContext)
|
|
22
|
+
const user = useContext(UserContext)
|
|
23
|
+
const cart = useContext(CartContext)
|
|
24
|
+
// Bad: expensive computation
|
|
25
|
+
const recommendations = useMemo(
|
|
26
|
+
() => computeRecommendations(product),
|
|
27
|
+
[product]
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return <View>{/* ... */}</View>
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Correct (lightweight list item):**
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
function ProductRow({ name, price, imageUrl }: Props) {
|
|
38
|
+
// Good: receives only primitives, minimal hooks
|
|
39
|
+
return (
|
|
40
|
+
<View>
|
|
41
|
+
<Image source={{ uri: imageUrl }} />
|
|
42
|
+
<Text>{name}</Text>
|
|
43
|
+
<Text>{price}</Text>
|
|
44
|
+
</View>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Move data fetching to parent:**
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
// Parent fetches all data once
|
|
53
|
+
function ProductList() {
|
|
54
|
+
const { data: products } = useQuery(['products'], fetchProducts)
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<LegendList
|
|
58
|
+
data={products}
|
|
59
|
+
renderItem={({ item }) => (
|
|
60
|
+
<ProductRow name={item.name} price={item.price} imageUrl={item.image} />
|
|
61
|
+
)}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**For shared values, use Zustand selectors instead of Context:**
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
// Incorrect: Context causes re-render when any cart value changes
|
|
71
|
+
function ProductRow({ id, name }: Props) {
|
|
72
|
+
const { items } = useContext(CartContext)
|
|
73
|
+
const inCart = items.includes(id)
|
|
74
|
+
// ...
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Correct: Zustand selector only re-renders when this specific value changes
|
|
78
|
+
function ProductRow({ id, name }: Props) {
|
|
79
|
+
// use Set.has (created once at the root) instead of Array.includes()
|
|
80
|
+
const inCart = useCartStore((s) => s.items.has(id))
|
|
81
|
+
// ...
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Guidelines for list items:**
|
|
86
|
+
|
|
87
|
+
- No queries or data fetching
|
|
88
|
+
- No expensive computations (move to parent or memoize at parent level)
|
|
89
|
+
- Prefer Zustand selectors over React Context
|
|
90
|
+
- Minimize useState/useEffect hooks
|
|
91
|
+
- Pass pre-computed values as props
|
|
92
|
+
|
|
93
|
+
The goal: list items should be simple rendering functions that take props and
|
|
94
|
+
return JSX.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pass Primitives to List Items for Memoization
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: enables effective memo() comparison
|
|
5
|
+
tags: lists, performance, memo, primitives
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Pass Primitives to List Items for Memoization
|
|
9
|
+
|
|
10
|
+
When possible, pass only primitive values (strings, numbers, booleans) as props
|
|
11
|
+
to list item components. Primitives enable shallow comparison in `memo()` to
|
|
12
|
+
work correctly, skipping re-renders when values haven't changed.
|
|
13
|
+
|
|
14
|
+
**Incorrect (object prop requires deep comparison):**
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
type User = { id: string; name: string; email: string; avatar: string }
|
|
18
|
+
|
|
19
|
+
const UserRow = memo(function UserRow({ user }: { user: User }) {
|
|
20
|
+
// memo() compares user by reference, not value
|
|
21
|
+
// If parent creates new user object, this re-renders even if data is same
|
|
22
|
+
return <Text>{user.name}</Text>
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
renderItem={({ item }) => <UserRow user={item} />}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This can still be optimized, but it is harder to memoize properly.
|
|
29
|
+
|
|
30
|
+
**Correct (primitive props enable shallow comparison):**
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
const UserRow = memo(function UserRow({
|
|
34
|
+
id,
|
|
35
|
+
name,
|
|
36
|
+
email,
|
|
37
|
+
}: {
|
|
38
|
+
id: string
|
|
39
|
+
name: string
|
|
40
|
+
email: string
|
|
41
|
+
}) {
|
|
42
|
+
// memo() compares each primitive directly
|
|
43
|
+
// Re-renders only if id, name, or email actually changed
|
|
44
|
+
return <Text>{name}</Text>
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
renderItem={({ item }) => (
|
|
48
|
+
<UserRow id={item.id} name={item.name} email={item.email} />
|
|
49
|
+
)}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Pass only what you need:**
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// Incorrect: passing entire item when you only need name
|
|
56
|
+
<UserRow user={item} />
|
|
57
|
+
|
|
58
|
+
// Correct: pass only the fields the component uses
|
|
59
|
+
<UserRow name={item.name} avatarUrl={item.avatar} />
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**For callbacks, hoist or use item ID:**
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
// Incorrect: inline function creates new reference
|
|
66
|
+
<UserRow name={item.name} onPress={() => handlePress(item.id)} />
|
|
67
|
+
|
|
68
|
+
// Correct: pass ID, handle in child
|
|
69
|
+
<UserRow id={item.id} name={item.name} />
|
|
70
|
+
|
|
71
|
+
const UserRow = memo(function UserRow({ id, name }: Props) {
|
|
72
|
+
const handlePress = useCallback(() => {
|
|
73
|
+
// use id here
|
|
74
|
+
}, [id])
|
|
75
|
+
return <Pressable onPress={handlePress}><Text>{name}</Text></Pressable>
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Primitive props make memoization predictable and effective.
|
|
80
|
+
|
|
81
|
+
**Note:** If you have the React Compiler enabled, you do not need to use
|
|
82
|
+
`memo()` or `useCallback()`, but the object references still apply.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Item Types for Heterogeneous Lists
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: efficient recycling, less layout thrashing
|
|
5
|
+
tags: list, performance, recycling, heterogeneous, LegendList
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Item Types for Heterogeneous Lists
|
|
9
|
+
|
|
10
|
+
When a list has different item layouts (messages, images, headers, etc.), use a
|
|
11
|
+
`type` field on each item and provide `getItemType` to the list. This puts items
|
|
12
|
+
into separate recycling pools so a message component never gets recycled into an
|
|
13
|
+
image component.
|
|
14
|
+
|
|
15
|
+
**Incorrect (single component with conditionals):**
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
type Item = { id: string; text?: string; imageUrl?: string; isHeader?: boolean }
|
|
19
|
+
|
|
20
|
+
function ListItem({ item }: { item: Item }) {
|
|
21
|
+
if (item.isHeader) {
|
|
22
|
+
return <HeaderItem title={item.text} />
|
|
23
|
+
}
|
|
24
|
+
if (item.imageUrl) {
|
|
25
|
+
return <ImageItem url={item.imageUrl} />
|
|
26
|
+
}
|
|
27
|
+
return <MessageItem text={item.text} />
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function Feed({ items }: { items: Item[] }) {
|
|
31
|
+
return (
|
|
32
|
+
<LegendList
|
|
33
|
+
data={items}
|
|
34
|
+
renderItem={({ item }) => <ListItem item={item} />}
|
|
35
|
+
recycleItems
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Correct (typed items with separate components):**
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
type HeaderItem = { id: string; type: 'header'; title: string }
|
|
45
|
+
type MessageItem = { id: string; type: 'message'; text: string }
|
|
46
|
+
type ImageItem = { id: string; type: 'image'; url: string }
|
|
47
|
+
type FeedItem = HeaderItem | MessageItem | ImageItem
|
|
48
|
+
|
|
49
|
+
function Feed({ items }: { items: FeedItem[] }) {
|
|
50
|
+
return (
|
|
51
|
+
<LegendList
|
|
52
|
+
data={items}
|
|
53
|
+
keyExtractor={(item) => item.id}
|
|
54
|
+
getItemType={(item) => item.type}
|
|
55
|
+
renderItem={({ item }) => {
|
|
56
|
+
switch (item.type) {
|
|
57
|
+
case 'header':
|
|
58
|
+
return <SectionHeader title={item.title} />
|
|
59
|
+
case 'message':
|
|
60
|
+
return <MessageRow text={item.text} />
|
|
61
|
+
case 'image':
|
|
62
|
+
return <ImageRow url={item.url} />
|
|
63
|
+
}
|
|
64
|
+
}}
|
|
65
|
+
recycleItems
|
|
66
|
+
/>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Why this matters:**
|
|
72
|
+
|
|
73
|
+
- **Recycling efficiency**: Items with the same type share a recycling pool
|
|
74
|
+
- **No layout thrashing**: A header never recycles into an image cell
|
|
75
|
+
- **Type safety**: TypeScript can narrow the item type in each branch
|
|
76
|
+
- **Better size estimation**: Use `getEstimatedItemSize` with `itemType` for
|
|
77
|
+
accurate estimates per type
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
<LegendList
|
|
81
|
+
data={items}
|
|
82
|
+
keyExtractor={(item) => item.id}
|
|
83
|
+
getItemType={(item) => item.type}
|
|
84
|
+
getEstimatedItemSize={(index, item, itemType) => {
|
|
85
|
+
switch (itemType) {
|
|
86
|
+
case 'header':
|
|
87
|
+
return 48
|
|
88
|
+
case 'message':
|
|
89
|
+
return 72
|
|
90
|
+
case 'image':
|
|
91
|
+
return 300
|
|
92
|
+
default:
|
|
93
|
+
return 72
|
|
94
|
+
}
|
|
95
|
+
}}
|
|
96
|
+
renderItem={({ item }) => {
|
|
97
|
+
/* ... */
|
|
98
|
+
}}
|
|
99
|
+
recycleItems
|
|
100
|
+
/>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Reference:
|
|
104
|
+
[LegendList getItemType](https://legendapp.com/open-source/list/api/props/#getitemtype-v2)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use a List Virtualizer for Any List
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: reduced memory, faster mounts
|
|
5
|
+
tags: lists, performance, virtualization, scrollview
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use a List Virtualizer for Any List
|
|
9
|
+
|
|
10
|
+
Use a list virtualizer like LegendList or FlashList instead of ScrollView with
|
|
11
|
+
mapped children—even for short lists. Virtualizers only render visible items,
|
|
12
|
+
reducing memory usage and mount time. ScrollView renders all children upfront,
|
|
13
|
+
which gets expensive quickly.
|
|
14
|
+
|
|
15
|
+
**Incorrect (ScrollView renders all items at once):**
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
function Feed({ items }: { items: Item[] }) {
|
|
19
|
+
return (
|
|
20
|
+
<ScrollView>
|
|
21
|
+
{items.map((item) => (
|
|
22
|
+
<ItemCard key={item.id} item={item} />
|
|
23
|
+
))}
|
|
24
|
+
</ScrollView>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
// 50 items = 50 components mounted, even if only 10 visible
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Correct (virtualizer renders only visible items):**
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { LegendList } from '@legendapp/list'
|
|
34
|
+
|
|
35
|
+
function Feed({ items }: { items: Item[] }) {
|
|
36
|
+
return (
|
|
37
|
+
<LegendList
|
|
38
|
+
data={items}
|
|
39
|
+
// if you aren't using React Compiler, wrap these with useCallback
|
|
40
|
+
renderItem={({ item }) => <ItemCard item={item} />}
|
|
41
|
+
keyExtractor={(item) => item.id}
|
|
42
|
+
estimatedItemSize={80}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
// Only ~10-15 visible items mounted at a time
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Alternative (FlashList):**
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { FlashList } from '@shopify/flash-list'
|
|
53
|
+
|
|
54
|
+
function Feed({ items }: { items: Item[] }) {
|
|
55
|
+
return (
|
|
56
|
+
<FlashList
|
|
57
|
+
data={items}
|
|
58
|
+
// if you aren't using React Compiler, wrap these with useCallback
|
|
59
|
+
renderItem={({ item }) => <ItemCard item={item} />}
|
|
60
|
+
keyExtractor={(item) => item.id}
|
|
61
|
+
/>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Benefits apply to any screen with scrollable content—profiles, settings, feeds,
|
|
67
|
+
search results. Default to virtualization.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Install Native Dependencies in App Directory
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: required for autolinking to work
|
|
5
|
+
tags: monorepo, native, autolinking, installation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Install Native Dependencies in App Directory
|
|
9
|
+
|
|
10
|
+
In a monorepo, packages with native code must be installed in the native app's
|
|
11
|
+
directory directly. Autolinking only scans the app's `node_modules`—it won't
|
|
12
|
+
find native dependencies installed in other packages.
|
|
13
|
+
|
|
14
|
+
**Incorrect (native dep in shared package only):**
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
packages/
|
|
18
|
+
ui/
|
|
19
|
+
package.json # has react-native-reanimated
|
|
20
|
+
app/
|
|
21
|
+
package.json # missing react-native-reanimated
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Autolinking fails—native code not linked.
|
|
25
|
+
|
|
26
|
+
**Correct (native dep in app directory):**
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
packages/
|
|
30
|
+
ui/
|
|
31
|
+
package.json # has react-native-reanimated
|
|
32
|
+
app/
|
|
33
|
+
package.json # also has react-native-reanimated
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
// packages/app/package.json
|
|
38
|
+
{
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"react-native-reanimated": "3.16.1"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Even if the shared package uses the native dependency, the app must also list it
|
|
46
|
+
for autolinking to detect and link the native code.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Single Dependency Versions Across Monorepo
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: avoids duplicate bundles, version conflicts
|
|
5
|
+
tags: monorepo, dependencies, installation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Single Dependency Versions Across Monorepo
|
|
9
|
+
|
|
10
|
+
Use a single version of each dependency across all packages in your monorepo.
|
|
11
|
+
Prefer exact versions over ranges. Multiple versions cause duplicate code in
|
|
12
|
+
bundles, runtime conflicts, and inconsistent behavior across packages.
|
|
13
|
+
|
|
14
|
+
Use a tool like syncpack to enforce this. As a last resort, use yarn resolutions
|
|
15
|
+
or npm overrides.
|
|
16
|
+
|
|
17
|
+
**Incorrect (version ranges, multiple versions):**
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
// packages/app/package.json
|
|
21
|
+
{
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"react-native-reanimated": "^3.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// packages/ui/package.json
|
|
28
|
+
{
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"react-native-reanimated": "^3.5.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Correct (exact versions, single source of truth):**
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
// package.json (root)
|
|
39
|
+
{
|
|
40
|
+
"pnpm": {
|
|
41
|
+
"overrides": {
|
|
42
|
+
"react-native-reanimated": "3.16.1"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// packages/app/package.json
|
|
48
|
+
{
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"react-native-reanimated": "3.16.1"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// packages/ui/package.json
|
|
55
|
+
{
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"react-native-reanimated": "3.16.1"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use your package manager's override/resolution feature to enforce versions at
|
|
63
|
+
the root. When adding dependencies, specify exact versions without `^` or `~`.
|