@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,316 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deco-edge-caching
|
|
3
|
+
description: Configure edge caching for Deco storefronts on Cloudflare Workers using createDecoWorkerEntry, cacheHeaders, detectCacheProfile, and routeCacheDefaults from @decocms/start. Use when setting up worker-entry caching, tuning Cache-Control headers, adding cache profiles for commerce page types (PDP, PLP, search), configuring staleTime for TanStack Router routes, debugging cache HITs/MISSes, or implementing cache purge APIs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deco Edge Caching
|
|
7
|
+
|
|
8
|
+
Complete caching infrastructure for Deco storefronts on Cloudflare Workers, provided by `@decocms/start/sdk`.
|
|
9
|
+
|
|
10
|
+
## Architecture Overview
|
|
11
|
+
|
|
12
|
+
Three caching layers work together:
|
|
13
|
+
|
|
14
|
+
| Layer | What | Where | TTL Control |
|
|
15
|
+
|-------|------|-------|-------------|
|
|
16
|
+
| **Edge cache** | Full HTML responses | Cloudflare Cache API + CDN | `cacheHeaders(profile)` via worker-entry |
|
|
17
|
+
| **Loader cache** | VTEX/Shopify API data | In-memory per-isolate (V8) | `createCachedLoader()` in setup.ts |
|
|
18
|
+
| **Client cache** | Route data after navigation | TanStack Router memory | `routeCacheDefaults(profile)` on routes |
|
|
19
|
+
|
|
20
|
+
The **worker-entry** is the authority for edge caching. Routes declare intent via `headers()` and `staleTime`, but the worker-entry overrides Cache-Control based on URL-detected profiles.
|
|
21
|
+
|
|
22
|
+
## Cache Profiles
|
|
23
|
+
|
|
24
|
+
| Profile | Browser `max-age` | Edge `s-maxage` | SWR | Client `staleTime` |
|
|
25
|
+
|---------|------------------|-----------------|-----|---------------------|
|
|
26
|
+
| `static` | 1 hour | 1 day | 1 day | 5 min |
|
|
27
|
+
| `product` | 60s | 5 min | 1 hour | 1 min |
|
|
28
|
+
| `listing` | 30s | 2 min | 10 min | 1 min |
|
|
29
|
+
| `search` | 0 | 60s | 5 min | 30s |
|
|
30
|
+
| `cart` | private | — | — | 0 |
|
|
31
|
+
| `private` | private | — | — | 0 |
|
|
32
|
+
| `none` | private | — | — | 0 |
|
|
33
|
+
|
|
34
|
+
## URL-to-Profile Detection (built-in)
|
|
35
|
+
|
|
36
|
+
| URL Pattern | Detected Profile |
|
|
37
|
+
|-------------|-----------------|
|
|
38
|
+
| `/` | `static` |
|
|
39
|
+
| `*/p` (ends with /p) | `product` |
|
|
40
|
+
| `/s`, `/s/*`, `?q=` | `search` |
|
|
41
|
+
| `/cart`, `/checkout`, `/account`, `/login` | `private` |
|
|
42
|
+
| `/api/*`, `/deco/*`, `/_server`, `/_build` | `none` |
|
|
43
|
+
| Everything else | `listing` (conservative default) |
|
|
44
|
+
|
|
45
|
+
## Site Worker Entry (10 lines)
|
|
46
|
+
|
|
47
|
+
**CRITICAL**: `wrangler.jsonc` must point to this custom file, NOT to `@tanstack/react-start/server-entry`. TanStack Start's Cloudflare adapter completely ignores custom `export default` — it generates its own handler that calls `createStartHandler` directly. Without a separate worker-entry, none of the caching, admin routes, or purge logic will execute in production.
|
|
48
|
+
|
|
49
|
+
```jsonc
|
|
50
|
+
// wrangler.jsonc
|
|
51
|
+
{
|
|
52
|
+
"main": "./src/worker-entry.ts"
|
|
53
|
+
// NOT: "main": "@tanstack/react-start/server-entry"
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// src/worker-entry.ts
|
|
59
|
+
import "./setup";
|
|
60
|
+
import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
|
|
61
|
+
import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
|
|
62
|
+
|
|
63
|
+
const serverEntry = createServerEntry({
|
|
64
|
+
async fetch(request) {
|
|
65
|
+
return await handler.fetch(request);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export default createDecoWorkerEntry(serverEntry);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### With Custom Overrides
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
export default createDecoWorkerEntry(serverEntry, {
|
|
76
|
+
// Override profile for specific URLs
|
|
77
|
+
detectProfile: (url) => {
|
|
78
|
+
if (url.pathname.startsWith("/institucional")) return "static";
|
|
79
|
+
return null; // fall through to built-in detection
|
|
80
|
+
},
|
|
81
|
+
// Disable mobile/desktop cache key splitting
|
|
82
|
+
deviceSpecificKeys: false,
|
|
83
|
+
// Custom purge token env var
|
|
84
|
+
purgeTokenEnv: "MY_PURGE_TOKEN",
|
|
85
|
+
// Add extra bypass paths
|
|
86
|
+
extraBypassPaths: ["/preview/"],
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Route Setup
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
94
|
+
import { cacheHeaders, routeCacheDefaults } from "@decocms/start/sdk/cacheHeaders";
|
|
95
|
+
|
|
96
|
+
export const Route = createFileRoute("/")({
|
|
97
|
+
...routeCacheDefaults("static"),
|
|
98
|
+
headers: () => cacheHeaders("static"),
|
|
99
|
+
loader: () => loadPage(),
|
|
100
|
+
component: HomePage,
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
For the CMS catch-all route:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
export const Route = createFileRoute("/$")({
|
|
108
|
+
...routeCacheDefaults("listing"),
|
|
109
|
+
headers: () => cacheHeaders("listing"),
|
|
110
|
+
loader: async ({ params }) => { /* ... */ },
|
|
111
|
+
component: CmsPage,
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The worker-entry overrides the route's Cache-Control with the correct profile for each URL (PDP gets `product`, search gets `search`, etc.), so the route's `headers()` serves as a fallback for client-side navigation responses via `/_server`.
|
|
116
|
+
|
|
117
|
+
## Registering Custom Patterns
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
// In setup.ts or worker-entry.ts
|
|
121
|
+
import { registerCachePattern } from "@decocms/start/sdk/cacheHeaders";
|
|
122
|
+
|
|
123
|
+
registerCachePattern({
|
|
124
|
+
test: (pathname) => pathname.startsWith("/blog"),
|
|
125
|
+
profile: "static",
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Custom patterns evaluate before built-in ones.
|
|
130
|
+
|
|
131
|
+
## Factory Features
|
|
132
|
+
|
|
133
|
+
`createDecoWorkerEntry` provides:
|
|
134
|
+
|
|
135
|
+
1. **Cache API integration** — `caches.default.match()` / `.put()` for edge caching
|
|
136
|
+
2. **Device-specific keys** — mobile/desktop get separate cached HTML (`__cf_device` param)
|
|
137
|
+
3. **Per-URL profiles** — `detectCacheProfile(url)` selects the right Cache-Control
|
|
138
|
+
4. **Immutable static assets** — `/_build/assets/*-{hash}.*` get `immutable, max-age=31536000`
|
|
139
|
+
5. **Private path protection** — strips public Cache-Control from cart/checkout/account responses
|
|
140
|
+
6. **Cache API TTL fix** — stores with `max-age={sMaxAge}` since Cache API ignores `s-maxage`
|
|
141
|
+
7. **Purge API** — `POST /_cache/purge` with bearer token to invalidate paths
|
|
142
|
+
8. **Diagnostic headers** — `X-Cache: HIT|MISS` and `X-Cache-Profile: {profile}`
|
|
143
|
+
|
|
144
|
+
## Debugging Cache
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Check profile and cache status
|
|
148
|
+
curl -s -D - -o /dev/null "https://site.com/category-slug" | grep -iE "cache-control|x-cache"
|
|
149
|
+
|
|
150
|
+
# Expected first hit:
|
|
151
|
+
# cache-control: public, max-age=30, s-maxage=120, stale-while-revalidate=600
|
|
152
|
+
# x-cache: MISS
|
|
153
|
+
# x-cache-profile: listing
|
|
154
|
+
|
|
155
|
+
# Expected second hit:
|
|
156
|
+
# cf-cache-status: HIT
|
|
157
|
+
# x-cache: HIT
|
|
158
|
+
# age: 3
|
|
159
|
+
|
|
160
|
+
# Purge cache
|
|
161
|
+
curl -X POST "https://site.com/_cache/purge" \
|
|
162
|
+
-H "Authorization: Bearer $PURGE_TOKEN" \
|
|
163
|
+
-H "Content-Type: application/json" \
|
|
164
|
+
-d '{"paths": ["/", "/vedacao-externa"]}'
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Important**: Use GET requests for testing (not `curl -I` which sends HEAD). The worker-entry only caches GET requests.
|
|
168
|
+
|
|
169
|
+
## Loader Cache (Server-Side SWR)
|
|
170
|
+
|
|
171
|
+
In `setup.ts`, wrap commerce loaders with `createCachedLoader`:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { createCachedLoader } from "@decocms/start/sdk/cachedLoader";
|
|
175
|
+
|
|
176
|
+
const cachedPLP = createCachedLoader("vtex/plp", vtexPLP, {
|
|
177
|
+
policy: "stale-while-revalidate",
|
|
178
|
+
maxAge: 60_000,
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This is per-isolate in-memory cache (V8 Map). Resets on cold start. Includes request deduplication (single-flight) and LRU eviction at 500 entries.
|
|
183
|
+
|
|
184
|
+
## Cache Versioning with BUILD_HASH
|
|
185
|
+
|
|
186
|
+
Deploy-time cache busting uses a `BUILD_HASH` environment variable (typically the git short SHA) passed to `wrangler deploy`. The worker-entry appends this to cache keys so deploying a new version automatically serves fresh content.
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
# .github/workflows/deploy.yml
|
|
190
|
+
- name: Deploy to Cloudflare Workers
|
|
191
|
+
run: npx wrangler deploy
|
|
192
|
+
env:
|
|
193
|
+
BUILD_HASH: ${{ github.sha }}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The worker-entry reads `env.BUILD_HASH` and injects it into cache keys. On new deploys, old cache entries simply expire naturally — no purge needed.
|
|
197
|
+
|
|
198
|
+
## Site-Level Cache Pattern Registration
|
|
199
|
+
|
|
200
|
+
For sites with known institutional/static pages that would otherwise get the conservative 2-min "listing" TTL, register explicit patterns in `setup.ts`:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
// setup.ts
|
|
204
|
+
import { registerCachePattern } from "@decocms/start/sdk/cacheHeaders";
|
|
205
|
+
|
|
206
|
+
// Institutional pages — content changes rarely, promote to 24h edge TTL
|
|
207
|
+
registerCachePattern({
|
|
208
|
+
test: (p) =>
|
|
209
|
+
p.startsWith("/institucional") ||
|
|
210
|
+
p.startsWith("/central-de-atendimento") ||
|
|
211
|
+
p.startsWith("/politica-de-") ||
|
|
212
|
+
p.startsWith("/termos-") ||
|
|
213
|
+
p === "/fale-conosco" ||
|
|
214
|
+
p === "/trabalhe-conosco" ||
|
|
215
|
+
p === "/cadastro" ||
|
|
216
|
+
p === "/televendas",
|
|
217
|
+
profile: "static",
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Promotional/collection pages — already listing-like, but explicit is better
|
|
221
|
+
registerCachePattern({
|
|
222
|
+
test: (p) =>
|
|
223
|
+
p.startsWith("/ofertas") ||
|
|
224
|
+
p.startsWith("/b/") ||
|
|
225
|
+
p.startsWith("/festival-"),
|
|
226
|
+
profile: "listing",
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Custom patterns are evaluated before built-in ones. This is the recommended way to tune caching per-site without modifying the framework.
|
|
231
|
+
|
|
232
|
+
## Client-Side Route Caching (routeCacheDefaults)
|
|
233
|
+
|
|
234
|
+
Without `routeCacheDefaults`, every SPA navigation triggers a fresh server request even if the data was just loaded. This is the most common cause of "slow navigation" reports.
|
|
235
|
+
|
|
236
|
+
The catch-all route `$.tsx` MUST include `routeCacheDefaults`:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
export const Route = createFileRoute("/$")({
|
|
240
|
+
...routeCacheDefaults("listing"), // <-- client-side cache: 1min stale, 5min gc
|
|
241
|
+
loaderDeps: routeConfig.loaderDeps,
|
|
242
|
+
loader: routeConfig.loader,
|
|
243
|
+
headers: ({ loaderData }) => {
|
|
244
|
+
return cacheHeaders(loaderData?.cacheProfile ?? "listing");
|
|
245
|
+
},
|
|
246
|
+
component: CmsPage,
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The homepage should use `cmsHomeRouteConfig` which already includes `routeCacheDefaults("static")`:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
export const Route = createFileRoute("/")({
|
|
254
|
+
...cmsHomeRouteConfig({ defaultTitle: "My Store" }),
|
|
255
|
+
component: HomePage,
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Cache Analysis & Debugging with Stats Lake
|
|
260
|
+
|
|
261
|
+
Deco sites emit CDN usage data to a ClickHouse stats-lake. This enables cache performance analysis:
|
|
262
|
+
|
|
263
|
+
```sql
|
|
264
|
+
-- Cache status breakdown for a site
|
|
265
|
+
SELECT
|
|
266
|
+
JSONExtractString(extra, 'cacheStatus') AS cache_status,
|
|
267
|
+
count() AS requests,
|
|
268
|
+
round(count() * 100.0 / sum(count()) OVER (), 2) AS pct
|
|
269
|
+
FROM fact_usage_daily
|
|
270
|
+
WHERE site_id = <site_id>
|
|
271
|
+
AND date >= today() - 7
|
|
272
|
+
GROUP BY cache_status
|
|
273
|
+
ORDER BY requests DESC;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Understanding "unknown" Cache Status
|
|
277
|
+
|
|
278
|
+
When the Cloudflare Worker uses `caches.default.match()/put()` to serve cached responses internally, the outer CDN reports `cf-cache-status: DYNAMIC` because the Worker is the origin. The stats-lake logs this as "unknown" or empty.
|
|
279
|
+
|
|
280
|
+
This means a high "unknown" percentage does NOT indicate a caching problem — it means the Worker's internal Cache API is handling the request before it reaches the origin CDN layer. This is expected and desirable behavior.
|
|
281
|
+
|
|
282
|
+
To verify actual cache performance:
|
|
283
|
+
1. Check `X-Cache: HIT|MISS` header (set by the worker-entry)
|
|
284
|
+
2. Check `X-Cache-Profile` header (shows which profile was detected)
|
|
285
|
+
3. Query stats-lake grouping by `cacheStatus` AND response status codes
|
|
286
|
+
|
|
287
|
+
### Comparing Staging vs Production Cache
|
|
288
|
+
|
|
289
|
+
When migrating to TanStack Workers, compare cache metrics:
|
|
290
|
+
- Production (Deno/Fresh on Kubernetes) typically shows high HIT rates because traffic volume keeps caches warm
|
|
291
|
+
- Staging Workers may show lower HIT rates due to lower traffic, plus "unknown" status from internal Cache API
|
|
292
|
+
- The "unknown" requests on Workers are functionally equivalent to HITs — they're served from the Worker's Cache API without hitting the origin server function
|
|
293
|
+
|
|
294
|
+
## Key Constraints
|
|
295
|
+
|
|
296
|
+
- **Cache API ignores `s-maxage`** — the factory uses `max-age` equal to `sMaxAge` when storing in Cache API
|
|
297
|
+
- **In-memory loader cache is ephemeral** — resets when Workers isolates recycle (~30s idle)
|
|
298
|
+
- **Device keys add a query param** — `__cf_device=mobile|desktop` is appended to cache keys, so purging must clear both
|
|
299
|
+
- **Non-200 responses are never cached** — only 200 OK goes into Cache API
|
|
300
|
+
- **`/_server` paths always bypass cache** — TanStack Start RPC requests are never edge-cached
|
|
301
|
+
- **UTM parameters are stripped** — `utm_*`, `gclid`, `fbclid` are removed from cache keys to improve hit rates
|
|
302
|
+
- **Segment hashing** — user segments (from matchers/flags) are hashed into the cache key so different audiences get different cached responses
|
|
303
|
+
|
|
304
|
+
## Package Exports
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
// Headers and profiles
|
|
308
|
+
import { cacheHeaders, routeCacheDefaults, detectCacheProfile } from "@decocms/start/sdk/cacheHeaders";
|
|
309
|
+
import { getCacheProfileConfig, registerCachePattern } from "@decocms/start/sdk/cacheHeaders";
|
|
310
|
+
|
|
311
|
+
// Worker entry factory
|
|
312
|
+
import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
|
|
313
|
+
|
|
314
|
+
// Loader cache
|
|
315
|
+
import { createCachedLoader, clearLoaderCache } from "@decocms/start/sdk/cachedLoader";
|
|
316
|
+
```
|