@decocms/start 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/skills/deco-api-call-dedup/SKILL.md +443 -0
- package/.cursor/skills/deco-apps-architecture/SKILL.md +255 -0
- package/.cursor/skills/deco-apps-architecture/app-pattern.md +288 -0
- package/.cursor/skills/deco-apps-architecture/commerce-types.md +239 -0
- package/.cursor/skills/deco-apps-architecture/new-app-guide.md +268 -0
- package/.cursor/skills/deco-apps-architecture/scripts-codegen.md +148 -0
- package/.cursor/skills/deco-apps-architecture/shared-utils.md +181 -0
- package/.cursor/skills/deco-apps-architecture/vtex-deep-structure.md +253 -0
- package/.cursor/skills/deco-apps-architecture/website-app.md +169 -0
- package/.cursor/skills/deco-apps-vtex-porting/SKILL.md +189 -0
- package/.cursor/skills/deco-apps-vtex-porting/adaptation-patterns.md +335 -0
- package/.cursor/skills/deco-apps-vtex-porting/commerce-porting.md +155 -0
- package/.cursor/skills/deco-apps-vtex-porting/cookie-auth-patterns.md +148 -0
- package/.cursor/skills/deco-apps-vtex-porting/structure-map.md +234 -0
- package/.cursor/skills/deco-apps-vtex-porting/transform-mapping.md +99 -0
- package/.cursor/skills/deco-apps-vtex-porting/website-porting.md +194 -0
- package/.cursor/skills/deco-apps-vtex-review/SKILL.md +234 -0
- package/.cursor/skills/deco-async-rendering-architecture/SKILL.md +270 -0
- package/.cursor/skills/deco-async-rendering-site-guide/SKILL.md +417 -0
- package/.cursor/skills/deco-cms-layout-caching/SKILL.md +293 -0
- package/.cursor/skills/deco-cms-route-config/SKILL.md +388 -0
- package/.cursor/skills/deco-core-architecture/SKILL.md +185 -0
- package/.cursor/skills/deco-core-architecture/blocks.md +196 -0
- package/.cursor/skills/deco-core-architecture/deco-vs-deco-start.md +191 -0
- package/.cursor/skills/deco-core-architecture/engine.md +220 -0
- package/.cursor/skills/deco-core-architecture/hooks-components.md +157 -0
- package/.cursor/skills/deco-core-architecture/plugins-clients.md +136 -0
- package/.cursor/skills/deco-core-architecture/runtime.md +116 -0
- package/.cursor/skills/deco-core-architecture/site-usage.md +165 -0
- package/.cursor/skills/deco-e2e-testing/SKILL.md +372 -0
- package/.cursor/skills/deco-e2e-testing/discovery.md +337 -0
- package/.cursor/skills/deco-e2e-testing/scripts/scaffold.sh +81 -0
- package/.cursor/skills/deco-e2e-testing/selectors.md +175 -0
- package/.cursor/skills/deco-e2e-testing/templates/package.json +18 -0
- package/.cursor/skills/deco-e2e-testing/templates/playwright.config.ts +65 -0
- package/.cursor/skills/deco-e2e-testing/templates/scripts/baseline.ts +279 -0
- package/.cursor/skills/deco-e2e-testing/templates/scripts/run-e2e.ts +194 -0
- package/.cursor/skills/deco-e2e-testing/templates/specs/ecommerce-flow.spec.ts +612 -0
- package/.cursor/skills/deco-e2e-testing/templates/tsconfig.json +12 -0
- package/.cursor/skills/deco-e2e-testing/templates/utils/metrics-collector.ts +918 -0
- package/.cursor/skills/deco-e2e-testing/troubleshooting.md +602 -0
- package/.cursor/skills/deco-edge-caching/SKILL.md +316 -0
- package/.cursor/skills/deco-full-analysis/SKILL.md +898 -0
- package/.cursor/skills/deco-full-analysis/checklists/asset-optimization.md +251 -0
- package/.cursor/skills/deco-full-analysis/checklists/bug-fix.md +189 -0
- package/.cursor/skills/deco-full-analysis/checklists/cache-strategy.md +144 -0
- package/.cursor/skills/deco-full-analysis/checklists/dependency-update.md +150 -0
- package/.cursor/skills/deco-full-analysis/checklists/hydration-fix.md +191 -0
- package/.cursor/skills/deco-full-analysis/checklists/image-optimization.md +180 -0
- package/.cursor/skills/deco-full-analysis/checklists/loader-optimization.md +165 -0
- package/.cursor/skills/deco-full-analysis/checklists/seo-fix.md +183 -0
- package/.cursor/skills/deco-full-analysis/checklists/site-cleanup.md +281 -0
- package/.cursor/skills/deco-full-analysis/discovery.md +548 -0
- package/.cursor/skills/deco-incident-debugging/SKILL.md +378 -0
- package/.cursor/skills/deco-incident-debugging/headless-mode.md +510 -0
- package/.cursor/skills/deco-incident-debugging/learnings-index.md +227 -0
- package/.cursor/skills/deco-incident-debugging/triage-workflow.md +312 -0
- package/.cursor/skills/deco-islands-migration/SKILL.md +251 -0
- package/.cursor/skills/deco-loader-n-plus-1-detector/SKILL.md +275 -0
- package/.cursor/skills/deco-performance-audit/SKILL.md +530 -0
- package/.cursor/skills/deco-performance-audit/tools-reference.md +428 -0
- package/.cursor/skills/deco-performance-audit/workflow.md +457 -0
- package/.cursor/skills/deco-server-functions-invoke/SKILL.md +92 -0
- package/.cursor/skills/deco-server-functions-invoke/architecture.md +166 -0
- package/.cursor/skills/deco-server-functions-invoke/generator.md +122 -0
- package/.cursor/skills/deco-server-functions-invoke/problem.md +98 -0
- package/.cursor/skills/deco-server-functions-invoke/troubleshooting.md +110 -0
- package/.cursor/skills/deco-site-deployment/SKILL.md +396 -0
- package/.cursor/skills/deco-site-memory-debugging/SKILL.md +121 -0
- package/.cursor/skills/deco-site-memory-debugging/cdp-connection.md +222 -0
- package/.cursor/skills/deco-site-memory-debugging/memory-analysis.md +362 -0
- package/.cursor/skills/deco-site-patterns/SKILL.md +124 -0
- package/.cursor/skills/deco-site-patterns/app-composition.md +337 -0
- package/.cursor/skills/deco-site-patterns/client-patterns.md +341 -0
- package/.cursor/skills/deco-site-patterns/cms-wiring.md +230 -0
- package/.cursor/skills/deco-site-patterns/section-patterns.md +340 -0
- package/.cursor/skills/deco-site-scaling-tuning/SKILL.md +240 -0
- package/.cursor/skills/deco-site-scaling-tuning/analysis-scripts.md +267 -0
- package/.cursor/skills/deco-start-architecture/SKILL.md +218 -0
- package/.cursor/skills/deco-start-architecture/admin-protocol.md +156 -0
- package/.cursor/skills/deco-start-architecture/cms-resolution.md +201 -0
- package/.cursor/skills/deco-start-architecture/code-quality.md +158 -0
- package/.cursor/skills/deco-start-architecture/gap-analysis.md +129 -0
- package/.cursor/skills/deco-start-architecture/sdk-utilities.md +197 -0
- package/.cursor/skills/deco-start-architecture/worker-entry-caching.md +154 -0
- package/.cursor/skills/deco-startup-analysis/SKILL.md +248 -0
- package/.cursor/skills/deco-storefront-test-checklist/SKILL.md +369 -0
- package/.cursor/skills/deco-tanstack-hydration-fixes/SKILL.md +468 -0
- package/.cursor/skills/deco-tanstack-navigation/SKILL.md +681 -0
- package/.cursor/skills/deco-tanstack-search/SKILL.md +411 -0
- package/.cursor/skills/deco-tanstack-storefront-patterns/SKILL.md +1013 -0
- package/.cursor/skills/deco-to-tanstack-migration/SKILL.md +518 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/codemod-commands.md +174 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/commerce/README.md +78 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/deco-framework/README.md +128 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/gotchas.md +719 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/imports/README.md +70 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/platform-hooks/README.md +154 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/signals/README.md +220 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/vite-config/README.md +78 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/package-json.md +55 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/root-route.md +110 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/router.md +96 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/setup-ts.md +167 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/vite-config.md +122 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/worker-entry.md +67 -0
- package/.cursor/skills/deco-typescript-fixes/SKILL.md +178 -0
- package/.cursor/skills/deco-typescript-fixes/common-fixes.md +330 -0
- package/.cursor/skills/deco-typescript-fixes/strategy.md +148 -0
- package/.cursor/skills/deco-variant-selection-perf/SKILL.md +272 -0
- package/.cursor/skills/deco-vtex-fetch-cache/SKILL.md +225 -0
- package/.cursor/skills/find-skills/SKILL.md +133 -0
- package/.cursor/skills/incident-report/SKILL.md +179 -0
- package/.cursor/skills/incident-report/references/5-whys.md +75 -0
- package/.cursor/skills/incident-report/templates/client-report.md +187 -0
- package/.cursor/skills/incident-report/templates/internal-report.md +206 -0
- package/.cursor/skills/template-skill/SKILL.md +38 -0
- package/.github/workflows/release.yml +32 -0
- package/.releaserc.json +25 -0
- package/CLAUDE.md +135 -0
- package/GAP_ANALYSIS.md +224 -0
- package/GAP_ANALYSIS_V2.md +1013 -0
- package/biome.json +39 -0
- package/knip.json +5 -0
- package/package.json +87 -0
- package/scripts/generate-blocks.ts +69 -0
- package/scripts/generate-invoke.ts +378 -0
- package/scripts/generate-schema.ts +657 -0
- package/src/admin/cors.ts +29 -0
- package/src/admin/decofile.ts +72 -0
- package/src/admin/index.ts +24 -0
- package/src/admin/invoke.ts +163 -0
- package/src/admin/liveControls.ts +29 -0
- package/src/admin/meta.ts +70 -0
- package/src/admin/render.ts +205 -0
- package/src/admin/schema.ts +686 -0
- package/src/admin/setup.ts +44 -0
- package/src/cms/index.ts +59 -0
- package/src/cms/loader.ts +180 -0
- package/src/cms/registry.ts +162 -0
- package/src/cms/resolve.ts +1005 -0
- package/src/cms/sectionLoaders.ts +294 -0
- package/src/hooks/DecoPageRenderer.tsx +444 -0
- package/src/hooks/LazySection.tsx +109 -0
- package/src/hooks/LiveControls.tsx +108 -0
- package/src/hooks/SectionErrorFallback.tsx +85 -0
- package/src/hooks/index.ts +8 -0
- package/src/index.ts +5 -0
- package/src/matchers/builtins.ts +184 -0
- package/src/matchers/posthog.ts +154 -0
- package/src/middleware/decoState.ts +55 -0
- package/src/middleware/healthMetrics.ts +131 -0
- package/src/middleware/index.ts +80 -0
- package/src/middleware/liveness.ts +21 -0
- package/src/middleware/observability.ts +205 -0
- package/src/routes/adminRoutes.ts +83 -0
- package/src/routes/cmsRoute.ts +302 -0
- package/src/routes/components.tsx +34 -0
- package/src/routes/index.ts +15 -0
- package/src/sdk/analytics.ts +72 -0
- package/src/sdk/cacheHeaders.ts +268 -0
- package/src/sdk/cachedLoader.ts +206 -0
- package/src/sdk/clx.ts +3 -0
- package/src/sdk/cookie.ts +39 -0
- package/src/sdk/createInvoke.ts +57 -0
- package/src/sdk/csp.ts +59 -0
- package/src/sdk/env.ts +27 -0
- package/src/sdk/index.ts +63 -0
- package/src/sdk/instrumentedFetch.ts +137 -0
- package/src/sdk/invoke.ts +133 -0
- package/src/sdk/mergeCacheControl.ts +150 -0
- package/src/sdk/redirects.ts +217 -0
- package/src/sdk/requestContext.ts +184 -0
- package/src/sdk/serverTimings.ts +68 -0
- package/src/sdk/signal.ts +41 -0
- package/src/sdk/sitemap.ts +143 -0
- package/src/sdk/urlUtils.ts +117 -0
- package/src/sdk/useDevice.ts +82 -0
- package/src/sdk/useId.ts +7 -0
- package/src/sdk/useScript.ts +101 -0
- package/src/sdk/workerEntry.ts +703 -0
- package/src/sdk/wrapCaughtErrors.ts +107 -0
- package/src/types/index.ts +39 -0
- package/src/types/widgets.ts +13 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Asset Optimization Checklist
|
|
2
|
+
|
|
3
|
+
17 learnings from real Deco sites. Check these during analysis.
|
|
4
|
+
|
|
5
|
+
## Third-Party Scripts
|
|
6
|
+
|
|
7
|
+
### 1. On-Demand Script Loading
|
|
8
|
+
**Check**: Are heavy scripts loaded on page load?
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
// Bad: Loads immediately
|
|
12
|
+
<script src="https://chat-widget.com/bundle.js" />
|
|
13
|
+
|
|
14
|
+
// Good: Load on interaction
|
|
15
|
+
function ChatButton() {
|
|
16
|
+
const [loaded, setLoaded] = useState(false);
|
|
17
|
+
|
|
18
|
+
const loadChat = () => {
|
|
19
|
+
if (!loaded) {
|
|
20
|
+
const script = document.createElement('script');
|
|
21
|
+
script.src = "https://chat-widget.com/bundle.js";
|
|
22
|
+
document.body.appendChild(script);
|
|
23
|
+
setLoaded(true);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return <button onClick={loadChat}>Chat</button>;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Route-Specific Script Injection
|
|
32
|
+
**Check**: Do scripts load on pages where they're not used?
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// Good: Only load on relevant pages
|
|
36
|
+
const isCheckout = ctx.url.pathname.startsWith('/checkout');
|
|
37
|
+
const isPDP = ctx.url.pathname.includes('/p');
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
{isCheckout && <PaymentScript />}
|
|
42
|
+
{isPDP && <ReviewScript />}
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Script Localization
|
|
48
|
+
**Check**: Are external scripts hosted locally?
|
|
49
|
+
- Localize frequently used scripts to `/static`
|
|
50
|
+
- Improves reliability and performance
|
|
51
|
+
- Works offline
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Before: External
|
|
55
|
+
<script src="https://unpkg.com/htmx.org@1.9.10" />
|
|
56
|
+
|
|
57
|
+
// After: Local
|
|
58
|
+
<script src="/static/htmx-1.9.10.js" />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 4. GTM Implementation
|
|
62
|
+
**Check**: Does GTM have noscript fallback?
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<!-- Head -->
|
|
66
|
+
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXX');</script>
|
|
67
|
+
|
|
68
|
+
<!-- Body (required) -->
|
|
69
|
+
<noscript>
|
|
70
|
+
<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXX" />
|
|
71
|
+
</noscript>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 5. Third-Party Widget Removal
|
|
75
|
+
**Check**: Are there unused third-party widgets?
|
|
76
|
+
- Audit PDP for review widgets that can be lazy-loaded
|
|
77
|
+
- Remove chat widgets from pages where not needed
|
|
78
|
+
- Defer non-critical analytics
|
|
79
|
+
|
|
80
|
+
## Section Optimization
|
|
81
|
+
|
|
82
|
+
### 6. Lazy Section Loading
|
|
83
|
+
**Check**: Are heavy below-fold sections lazy?
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"__resolveType": "website/sections/Rendering/Lazy.tsx",
|
|
88
|
+
"section": { "__resolveType": "site/sections/Product/Reviews.tsx" }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Best candidates for lazy loading:
|
|
93
|
+
- Product shelves
|
|
94
|
+
- Reviews
|
|
95
|
+
- Similar products
|
|
96
|
+
- FAQ sections
|
|
97
|
+
- Instagram feeds
|
|
98
|
+
|
|
99
|
+
### 7. Skeleton/Fallback Pattern
|
|
100
|
+
**Check**: Do async sections have loading states?
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
export function LoadingFallback() {
|
|
104
|
+
return (
|
|
105
|
+
<div class="animate-pulse">
|
|
106
|
+
<div class="h-8 bg-gray-200 rounded w-1/3 mb-4" />
|
|
107
|
+
<div class="grid grid-cols-4 gap-4">
|
|
108
|
+
{[...Array(4)].map(() => (
|
|
109
|
+
<div class="h-64 bg-gray-200 rounded" />
|
|
110
|
+
))}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 8. Video Section Handling
|
|
118
|
+
**Check**: Are video sections wrapped in Lazy/Deferred?
|
|
119
|
+
- Native video or iframes should NOT be lazy wrapped
|
|
120
|
+
- Causes interaction breakage
|
|
121
|
+
- Only lazy wrap if explicitly needed
|
|
122
|
+
|
|
123
|
+
## Block Architecture
|
|
124
|
+
|
|
125
|
+
### 9. Block Flattening
|
|
126
|
+
**Check**: Are there unnecessary PageInclude wrappers?
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
// Bad: Extra resolution overhead
|
|
130
|
+
{
|
|
131
|
+
"__resolveType": "website/sections/PageInclude.tsx",
|
|
132
|
+
"page": { "__resolveType": "Header-Block" }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Good: Direct reference
|
|
136
|
+
{
|
|
137
|
+
"__resolveType": "$Header-Block"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Migration
|
|
142
|
+
|
|
143
|
+
### 10. Standard Library Migration
|
|
144
|
+
**Check**: Are there `deco-sites/std` imports?
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Bad: Legacy
|
|
148
|
+
import { Image } from "deco-sites/std/components/Image.tsx";
|
|
149
|
+
|
|
150
|
+
// Good: Modern
|
|
151
|
+
import { Image } from "apps/website/components/Image.tsx";
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Audit all imports and replace:
|
|
155
|
+
- `deco-sites/std` → `apps/`
|
|
156
|
+
|
|
157
|
+
## Layout Stability
|
|
158
|
+
|
|
159
|
+
### 11. Aspect Ratio Reservation
|
|
160
|
+
**Check**: Do images/videos cause CLS?
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
// Good: Reserve space
|
|
164
|
+
<div class="aspect-video relative">
|
|
165
|
+
<Image class="absolute inset-0 w-full h-full object-cover" />
|
|
166
|
+
</div>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Security
|
|
170
|
+
|
|
171
|
+
### 12. CSP Hardening
|
|
172
|
+
**Check**: Are CSP headers configured?
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// In _middleware.ts
|
|
176
|
+
const cspHeader = [
|
|
177
|
+
"default-src 'self'",
|
|
178
|
+
"script-src 'self' 'unsafe-inline' https://www.googletagmanager.com",
|
|
179
|
+
"worker-src 'self'",
|
|
180
|
+
"frame-ancestors 'self'",
|
|
181
|
+
].join("; ");
|
|
182
|
+
|
|
183
|
+
response.headers.set("Content-Security-Policy", cspHeader);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 13. Service Worker Strategy
|
|
187
|
+
**Check**: Is Service Worker strategy optimal?
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// Avoid: NetworkOnly as default (negates caching)
|
|
191
|
+
defaultStrategy: "NetworkOnly"
|
|
192
|
+
|
|
193
|
+
// Better: CacheFirst or StaleWhileRevalidate
|
|
194
|
+
defaultStrategy: "CacheFirst"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Deno Configuration
|
|
198
|
+
|
|
199
|
+
### 14. Deno Native Optimization
|
|
200
|
+
**Check**: Is `nodeModulesDir` enabled unnecessarily?
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
// deno.json - disable if not needed
|
|
204
|
+
{
|
|
205
|
+
"nodeModulesDir": false // Faster startup, less disk
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 15. Relative Path Invocation
|
|
210
|
+
**Check**: Are loaders using absolute URLs?
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Bad: Cross-domain overhead
|
|
214
|
+
fetch("https://mysite.com/live/invoke/...");
|
|
215
|
+
|
|
216
|
+
// Good: Relative path
|
|
217
|
+
fetch("/live/invoke/...");
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Quick Audit Commands
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Find deco-sites/std imports
|
|
224
|
+
grep -r "deco-sites/std" sections/ loaders/ components/
|
|
225
|
+
|
|
226
|
+
# Find third-party scripts
|
|
227
|
+
grep -r '<script src="http' sections/ components/
|
|
228
|
+
|
|
229
|
+
# Find sections without LoadingFallback
|
|
230
|
+
for f in sections/**/*.tsx; do
|
|
231
|
+
grep -q "LoadingFallback" "$f" || echo "Missing fallback: $f"
|
|
232
|
+
done
|
|
233
|
+
|
|
234
|
+
# Check CSP headers
|
|
235
|
+
grep -r "Content-Security-Policy" routes/ _middleware.ts
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Asset Audit Table
|
|
239
|
+
|
|
240
|
+
Add this to AGENTS.md:
|
|
241
|
+
|
|
242
|
+
```markdown
|
|
243
|
+
## Third-Party Scripts
|
|
244
|
+
|
|
245
|
+
| Script | Pages | Load Strategy | Action |
|
|
246
|
+
|--------|-------|---------------|--------|
|
|
247
|
+
| GTM | All | Head | ✅ OK |
|
|
248
|
+
| Chat Widget | All | Eager | 🔴 Make lazy |
|
|
249
|
+
| Reviews | PDP | Eager | 🟡 Consider lazy |
|
|
250
|
+
| Payment | Checkout | Conditional | ✅ OK |
|
|
251
|
+
```
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Bug Fix Checklist
|
|
2
|
+
|
|
3
|
+
8 learnings from real Deco sites. Check these during analysis.
|
|
4
|
+
|
|
5
|
+
## Defensive Coding
|
|
6
|
+
|
|
7
|
+
### 1. Defensive Prop Handling
|
|
8
|
+
**Check**: Are CMS-configurable props accessed safely?
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
// Bad: Crashes on undefined
|
|
12
|
+
const title = props.title.toUpperCase();
|
|
13
|
+
const items = props.items.map(i => i.name);
|
|
14
|
+
|
|
15
|
+
// Good: Optional chaining
|
|
16
|
+
const title = props.title?.toUpperCase() ?? "";
|
|
17
|
+
const items = props.items?.map(i => i?.name) ?? [];
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
CMS props can be:
|
|
21
|
+
- Undefined (not configured)
|
|
22
|
+
- Null (explicitly cleared)
|
|
23
|
+
- Empty arrays/strings
|
|
24
|
+
|
|
25
|
+
### 2. Safe Request Parsing
|
|
26
|
+
**Check**: Are API routes handling malformed requests?
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// Bad: Crashes on empty/malformed body
|
|
30
|
+
export async function handler(req: Request) {
|
|
31
|
+
const body = await req.json();
|
|
32
|
+
return Response.json({ ok: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Good: Try-catch wrapper
|
|
36
|
+
export async function handler(req: Request) {
|
|
37
|
+
try {
|
|
38
|
+
const body = await req.json();
|
|
39
|
+
// ... process
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return new Response("Bad Request", { status: 400 });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 3. Current Product Exclusion
|
|
47
|
+
**Check**: Do "Related Products" shelves include current product?
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// Good: Filter out current product
|
|
51
|
+
const relatedProducts = allProducts.filter(p => p.id !== currentProductId);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Content Sanitization
|
|
55
|
+
|
|
56
|
+
### 4. Protocol Upgrade Filter
|
|
57
|
+
**Check**: Does external content have `http://` links?
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// Good: Upgrade to HTTPS
|
|
61
|
+
function sanitizeContent(html: string): string {
|
|
62
|
+
return html.replace(/http:\/\//g, 'https://');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Apply to product descriptions, CMS content, etc.
|
|
66
|
+
<div dangerouslySetInnerHTML={{
|
|
67
|
+
__html: sanitizeContent(product.description)
|
|
68
|
+
}} />
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Mixed content blocks images, scripts, and iframes.
|
|
72
|
+
|
|
73
|
+
### 5. UTM Injection Prevention
|
|
74
|
+
**Check**: Are empty links being processed?
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Bad: Crashes on empty href
|
|
78
|
+
document.querySelectorAll('a').forEach(link => {
|
|
79
|
+
const url = new URL(link.href); // Crashes if href is ""
|
|
80
|
+
url.searchParams.set('utm_source', 'site');
|
|
81
|
+
link.href = url.toString();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Good: Validate first
|
|
85
|
+
document.querySelectorAll('a[href]').forEach(link => {
|
|
86
|
+
if (!link.href || link.href === '#') return;
|
|
87
|
+
try {
|
|
88
|
+
const url = new URL(link.href);
|
|
89
|
+
url.searchParams.set('utm_source', 'site');
|
|
90
|
+
link.href = url.toString();
|
|
91
|
+
} catch {}
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## SEO & Indexing
|
|
96
|
+
|
|
97
|
+
### 6. Soft Out-of-Stock Handling
|
|
98
|
+
**Check**: Do out-of-stock pages return 404?
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Bad: 404 for out-of-stock (loses SEO)
|
|
102
|
+
if (!product.available) {
|
|
103
|
+
return new Response("Not Found", { status: 404 });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Good: 200 with unavailable state
|
|
107
|
+
if (!product.available) {
|
|
108
|
+
return renderUnavailablePage(product); // Status 200
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Out-of-stock products should:
|
|
113
|
+
- Return 200 status
|
|
114
|
+
- Show "unavailable" UI
|
|
115
|
+
- Keep structured data
|
|
116
|
+
- Maintain SEO value
|
|
117
|
+
|
|
118
|
+
## UI Stability
|
|
119
|
+
|
|
120
|
+
### 7. Smooth Image Transitions
|
|
121
|
+
**Check**: Do hover effects cause flickering?
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
/* Bad: Flicker on hover */
|
|
125
|
+
.product-card:hover .secondary-image {
|
|
126
|
+
display: block; /* Hidden class uses display:none */
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Good: Opacity transition */
|
|
130
|
+
.product-card .secondary-image {
|
|
131
|
+
opacity: 0;
|
|
132
|
+
transition: opacity 0.3s;
|
|
133
|
+
}
|
|
134
|
+
.product-card:hover .secondary-image {
|
|
135
|
+
opacity: 1;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Never combine `display: none` with opacity transitions.
|
|
140
|
+
|
|
141
|
+
### 8. Pricing Consistency
|
|
142
|
+
**Check**: Is promotional logic duplicated?
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Bad: Different calculations in different places
|
|
146
|
+
// ProductCard.tsx
|
|
147
|
+
const price = product.price * 0.9;
|
|
148
|
+
|
|
149
|
+
// ProductDetails.tsx
|
|
150
|
+
const price = product.price - 10;
|
|
151
|
+
|
|
152
|
+
// Good: Centralized utility
|
|
153
|
+
// utils/pricing.ts
|
|
154
|
+
export function calculateFinalPrice(product: Product): number {
|
|
155
|
+
const promotion = getActivePromotion(product);
|
|
156
|
+
return applyPromotion(product.price, promotion);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Centralize:
|
|
161
|
+
- Discount calculations
|
|
162
|
+
- Promotion logic
|
|
163
|
+
- Price formatting
|
|
164
|
+
|
|
165
|
+
## Quick Audit Commands
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Find unsafe prop access (no optional chaining)
|
|
169
|
+
grep -rn "props\.\w\+\." sections/ | grep -v "props\.\w\+?\."
|
|
170
|
+
|
|
171
|
+
# Find direct URL construction without try-catch
|
|
172
|
+
grep -rn "new URL" islands/ | grep -v "try"
|
|
173
|
+
|
|
174
|
+
# Find http:// in content
|
|
175
|
+
grep -r "http://" .deco/blocks/*.json | grep -v "https://"
|
|
176
|
+
|
|
177
|
+
# Find 404 responses
|
|
178
|
+
grep -r "status: 404" loaders/ sections/
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Common Bug Patterns
|
|
182
|
+
|
|
183
|
+
| Bug | Symptom | Fix |
|
|
184
|
+
|-----|---------|-----|
|
|
185
|
+
| Null prop access | White screen, error in console | Add optional chaining |
|
|
186
|
+
| Mixed content | Images not loading | Upgrade http to https |
|
|
187
|
+
| OOS 404 | SEO drops for seasonal items | Return 200 with unavailable UI |
|
|
188
|
+
| Duplicate pricing | Different prices across site | Centralize price logic |
|
|
189
|
+
| Flickering images | Visual glitch on hover | Use opacity not display |
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Cache Strategy Checklist
|
|
2
|
+
|
|
3
|
+
7 learnings from real Deco sites. Check these during analysis.
|
|
4
|
+
|
|
5
|
+
## Loader Caching
|
|
6
|
+
|
|
7
|
+
### 1. Stale-While-Revalidate Pattern
|
|
8
|
+
**Check**: Do custom loaders have cache configuration?
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
// Good: Has caching
|
|
12
|
+
export const cache = "stale-while-revalidate";
|
|
13
|
+
|
|
14
|
+
export const cacheKey = (props: Props) =>
|
|
15
|
+
`${props.productId}-${props.locale}`;
|
|
16
|
+
|
|
17
|
+
export default async function loader(props: Props) {
|
|
18
|
+
// ...
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Deterministic Cache Keys
|
|
23
|
+
**Check**: Are cache keys based on unique identifiers?
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// Bad: Uses full URL (includes tracking params)
|
|
27
|
+
export const cacheKey = (props: Props, req: Request) => req.url;
|
|
28
|
+
|
|
29
|
+
// Good: Uses only relevant data
|
|
30
|
+
export const cacheKey = (props: Props) => {
|
|
31
|
+
const facets = [...(props.facets || [])].sort();
|
|
32
|
+
return `${props.query}-${facets.join(",")}`;
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Common mistakes**:
|
|
37
|
+
- Including UTM parameters in cache key
|
|
38
|
+
- Including session/user-specific data
|
|
39
|
+
- Using unsorted arrays (order changes = cache miss)
|
|
40
|
+
|
|
41
|
+
### 3. Loader Deduplication via Shared Blocks
|
|
42
|
+
**Check**: Are the same loaders configured inline in multiple places?
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
// Bad: Same loader inline in multiple pages
|
|
46
|
+
// pages-Home.json, pages-PLP.json, pages-PDP.json all have:
|
|
47
|
+
{ "loader": { "productId": "..." } }
|
|
48
|
+
|
|
49
|
+
// Good: Reference shared block
|
|
50
|
+
{ "__resolveType": "$live/loaders/Loader.tsx", "loader": "PDP-Main-Loader" }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Benefits:
|
|
54
|
+
- Single cache entry for same data
|
|
55
|
+
- Easier to update
|
|
56
|
+
- Better hit rate
|
|
57
|
+
|
|
58
|
+
## Rate Limiting
|
|
59
|
+
|
|
60
|
+
### 4. Bot-Specific Rate Limiting
|
|
61
|
+
**Check**: Do bots and users share rate limits?
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// In _middleware.ts
|
|
65
|
+
const isBot = req.headers.get("user-agent")?.includes("bot");
|
|
66
|
+
|
|
67
|
+
if (isBot) {
|
|
68
|
+
// Apply stricter rate limiting for bots
|
|
69
|
+
const botRateLimit = await checkBotRateLimit(ip);
|
|
70
|
+
if (botRateLimit.exceeded) {
|
|
71
|
+
return new Response("Too Many Requests", { status: 429 });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 5. Granular Rate Limit Tracking
|
|
77
|
+
**Check**: Is rate limiting per-endpoint or global?
|
|
78
|
+
- Track rate limits per endpoint for critical paths
|
|
79
|
+
- Allow more requests to cached endpoints
|
|
80
|
+
|
|
81
|
+
## SSR Caching
|
|
82
|
+
|
|
83
|
+
### 6. SSR Promotion Fetching
|
|
84
|
+
**Check**: Is promotion data fetched client-side causing CLS?
|
|
85
|
+
- Fetch discount/promotion rules on server
|
|
86
|
+
- Prevents price flickering
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// Good: Fetch on server
|
|
90
|
+
export default async function ProductCard({ product }: Props) {
|
|
91
|
+
const promotion = await fetchPromotion(product.id);
|
|
92
|
+
const finalPrice = applyPromotion(product.price, promotion);
|
|
93
|
+
return <Card price={finalPrice} />;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 7. Related Products Caching
|
|
98
|
+
**Check**: Do related product loaders have cache?
|
|
99
|
+
- Often high-volume, low-change-rate
|
|
100
|
+
- Good candidate for aggressive caching
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
export const cache = "stale-while-revalidate";
|
|
104
|
+
export const cacheKey = (props: Props) => `related-${props.productId}`;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Cache Audit Table
|
|
108
|
+
|
|
109
|
+
Add this to AGENTS.md:
|
|
110
|
+
|
|
111
|
+
```markdown
|
|
112
|
+
## Caching Inventory
|
|
113
|
+
|
|
114
|
+
| Loader | Cache | Cache Key | Priority |
|
|
115
|
+
|--------|-------|-----------|----------|
|
|
116
|
+
| `loaders/search/intelligentSearch.ts` | ❌ None | - | 🔴 High |
|
|
117
|
+
| `loaders/product/buyTogether.ts` | ✅ SWR | productId | - |
|
|
118
|
+
| `loaders/getUserGeolocation.ts` | ❌ None | - | 🟡 Medium |
|
|
119
|
+
| `vtex/loaders/categories/tree.ts` | ❌ None | - | 🔴 High |
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Quick Audit Commands
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Find loaders without cache
|
|
126
|
+
grep -L "export const cache" loaders/**/*.ts
|
|
127
|
+
|
|
128
|
+
# Find loaders with cache but no cacheKey
|
|
129
|
+
grep -l "export const cache" loaders/**/*.ts | xargs grep -L "cacheKey"
|
|
130
|
+
|
|
131
|
+
# Find inline loaders in page blocks (should be shared)
|
|
132
|
+
grep -r '"loader":' .deco/blocks/pages-*.json | grep -v "__resolveType"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Common Cache Durations
|
|
136
|
+
|
|
137
|
+
| Content Type | Strategy | TTL |
|
|
138
|
+
|--------------|----------|-----|
|
|
139
|
+
| Product details | SWR | 5 min |
|
|
140
|
+
| Category tree | SWR | 1 hour |
|
|
141
|
+
| Search results | SWR | 1 min |
|
|
142
|
+
| Reviews | SWR | 15 min |
|
|
143
|
+
| Static content | SWR | 1 day |
|
|
144
|
+
| User-specific | None | - |
|