@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.
Files changed (185) hide show
  1. package/.cursor/skills/deco-api-call-dedup/SKILL.md +443 -0
  2. package/.cursor/skills/deco-apps-architecture/SKILL.md +255 -0
  3. package/.cursor/skills/deco-apps-architecture/app-pattern.md +288 -0
  4. package/.cursor/skills/deco-apps-architecture/commerce-types.md +239 -0
  5. package/.cursor/skills/deco-apps-architecture/new-app-guide.md +268 -0
  6. package/.cursor/skills/deco-apps-architecture/scripts-codegen.md +148 -0
  7. package/.cursor/skills/deco-apps-architecture/shared-utils.md +181 -0
  8. package/.cursor/skills/deco-apps-architecture/vtex-deep-structure.md +253 -0
  9. package/.cursor/skills/deco-apps-architecture/website-app.md +169 -0
  10. package/.cursor/skills/deco-apps-vtex-porting/SKILL.md +189 -0
  11. package/.cursor/skills/deco-apps-vtex-porting/adaptation-patterns.md +335 -0
  12. package/.cursor/skills/deco-apps-vtex-porting/commerce-porting.md +155 -0
  13. package/.cursor/skills/deco-apps-vtex-porting/cookie-auth-patterns.md +148 -0
  14. package/.cursor/skills/deco-apps-vtex-porting/structure-map.md +234 -0
  15. package/.cursor/skills/deco-apps-vtex-porting/transform-mapping.md +99 -0
  16. package/.cursor/skills/deco-apps-vtex-porting/website-porting.md +194 -0
  17. package/.cursor/skills/deco-apps-vtex-review/SKILL.md +234 -0
  18. package/.cursor/skills/deco-async-rendering-architecture/SKILL.md +270 -0
  19. package/.cursor/skills/deco-async-rendering-site-guide/SKILL.md +417 -0
  20. package/.cursor/skills/deco-cms-layout-caching/SKILL.md +293 -0
  21. package/.cursor/skills/deco-cms-route-config/SKILL.md +388 -0
  22. package/.cursor/skills/deco-core-architecture/SKILL.md +185 -0
  23. package/.cursor/skills/deco-core-architecture/blocks.md +196 -0
  24. package/.cursor/skills/deco-core-architecture/deco-vs-deco-start.md +191 -0
  25. package/.cursor/skills/deco-core-architecture/engine.md +220 -0
  26. package/.cursor/skills/deco-core-architecture/hooks-components.md +157 -0
  27. package/.cursor/skills/deco-core-architecture/plugins-clients.md +136 -0
  28. package/.cursor/skills/deco-core-architecture/runtime.md +116 -0
  29. package/.cursor/skills/deco-core-architecture/site-usage.md +165 -0
  30. package/.cursor/skills/deco-e2e-testing/SKILL.md +372 -0
  31. package/.cursor/skills/deco-e2e-testing/discovery.md +337 -0
  32. package/.cursor/skills/deco-e2e-testing/scripts/scaffold.sh +81 -0
  33. package/.cursor/skills/deco-e2e-testing/selectors.md +175 -0
  34. package/.cursor/skills/deco-e2e-testing/templates/package.json +18 -0
  35. package/.cursor/skills/deco-e2e-testing/templates/playwright.config.ts +65 -0
  36. package/.cursor/skills/deco-e2e-testing/templates/scripts/baseline.ts +279 -0
  37. package/.cursor/skills/deco-e2e-testing/templates/scripts/run-e2e.ts +194 -0
  38. package/.cursor/skills/deco-e2e-testing/templates/specs/ecommerce-flow.spec.ts +612 -0
  39. package/.cursor/skills/deco-e2e-testing/templates/tsconfig.json +12 -0
  40. package/.cursor/skills/deco-e2e-testing/templates/utils/metrics-collector.ts +918 -0
  41. package/.cursor/skills/deco-e2e-testing/troubleshooting.md +602 -0
  42. package/.cursor/skills/deco-edge-caching/SKILL.md +316 -0
  43. package/.cursor/skills/deco-full-analysis/SKILL.md +898 -0
  44. package/.cursor/skills/deco-full-analysis/checklists/asset-optimization.md +251 -0
  45. package/.cursor/skills/deco-full-analysis/checklists/bug-fix.md +189 -0
  46. package/.cursor/skills/deco-full-analysis/checklists/cache-strategy.md +144 -0
  47. package/.cursor/skills/deco-full-analysis/checklists/dependency-update.md +150 -0
  48. package/.cursor/skills/deco-full-analysis/checklists/hydration-fix.md +191 -0
  49. package/.cursor/skills/deco-full-analysis/checklists/image-optimization.md +180 -0
  50. package/.cursor/skills/deco-full-analysis/checklists/loader-optimization.md +165 -0
  51. package/.cursor/skills/deco-full-analysis/checklists/seo-fix.md +183 -0
  52. package/.cursor/skills/deco-full-analysis/checklists/site-cleanup.md +281 -0
  53. package/.cursor/skills/deco-full-analysis/discovery.md +548 -0
  54. package/.cursor/skills/deco-incident-debugging/SKILL.md +378 -0
  55. package/.cursor/skills/deco-incident-debugging/headless-mode.md +510 -0
  56. package/.cursor/skills/deco-incident-debugging/learnings-index.md +227 -0
  57. package/.cursor/skills/deco-incident-debugging/triage-workflow.md +312 -0
  58. package/.cursor/skills/deco-islands-migration/SKILL.md +251 -0
  59. package/.cursor/skills/deco-loader-n-plus-1-detector/SKILL.md +275 -0
  60. package/.cursor/skills/deco-performance-audit/SKILL.md +530 -0
  61. package/.cursor/skills/deco-performance-audit/tools-reference.md +428 -0
  62. package/.cursor/skills/deco-performance-audit/workflow.md +457 -0
  63. package/.cursor/skills/deco-server-functions-invoke/SKILL.md +92 -0
  64. package/.cursor/skills/deco-server-functions-invoke/architecture.md +166 -0
  65. package/.cursor/skills/deco-server-functions-invoke/generator.md +122 -0
  66. package/.cursor/skills/deco-server-functions-invoke/problem.md +98 -0
  67. package/.cursor/skills/deco-server-functions-invoke/troubleshooting.md +110 -0
  68. package/.cursor/skills/deco-site-deployment/SKILL.md +396 -0
  69. package/.cursor/skills/deco-site-memory-debugging/SKILL.md +121 -0
  70. package/.cursor/skills/deco-site-memory-debugging/cdp-connection.md +222 -0
  71. package/.cursor/skills/deco-site-memory-debugging/memory-analysis.md +362 -0
  72. package/.cursor/skills/deco-site-patterns/SKILL.md +124 -0
  73. package/.cursor/skills/deco-site-patterns/app-composition.md +337 -0
  74. package/.cursor/skills/deco-site-patterns/client-patterns.md +341 -0
  75. package/.cursor/skills/deco-site-patterns/cms-wiring.md +230 -0
  76. package/.cursor/skills/deco-site-patterns/section-patterns.md +340 -0
  77. package/.cursor/skills/deco-site-scaling-tuning/SKILL.md +240 -0
  78. package/.cursor/skills/deco-site-scaling-tuning/analysis-scripts.md +267 -0
  79. package/.cursor/skills/deco-start-architecture/SKILL.md +218 -0
  80. package/.cursor/skills/deco-start-architecture/admin-protocol.md +156 -0
  81. package/.cursor/skills/deco-start-architecture/cms-resolution.md +201 -0
  82. package/.cursor/skills/deco-start-architecture/code-quality.md +158 -0
  83. package/.cursor/skills/deco-start-architecture/gap-analysis.md +129 -0
  84. package/.cursor/skills/deco-start-architecture/sdk-utilities.md +197 -0
  85. package/.cursor/skills/deco-start-architecture/worker-entry-caching.md +154 -0
  86. package/.cursor/skills/deco-startup-analysis/SKILL.md +248 -0
  87. package/.cursor/skills/deco-storefront-test-checklist/SKILL.md +369 -0
  88. package/.cursor/skills/deco-tanstack-hydration-fixes/SKILL.md +468 -0
  89. package/.cursor/skills/deco-tanstack-navigation/SKILL.md +681 -0
  90. package/.cursor/skills/deco-tanstack-search/SKILL.md +411 -0
  91. package/.cursor/skills/deco-tanstack-storefront-patterns/SKILL.md +1013 -0
  92. package/.cursor/skills/deco-to-tanstack-migration/SKILL.md +518 -0
  93. package/.cursor/skills/deco-to-tanstack-migration/references/codemod-commands.md +174 -0
  94. package/.cursor/skills/deco-to-tanstack-migration/references/commerce/README.md +78 -0
  95. package/.cursor/skills/deco-to-tanstack-migration/references/deco-framework/README.md +128 -0
  96. package/.cursor/skills/deco-to-tanstack-migration/references/gotchas.md +719 -0
  97. package/.cursor/skills/deco-to-tanstack-migration/references/imports/README.md +70 -0
  98. package/.cursor/skills/deco-to-tanstack-migration/references/platform-hooks/README.md +154 -0
  99. package/.cursor/skills/deco-to-tanstack-migration/references/signals/README.md +220 -0
  100. package/.cursor/skills/deco-to-tanstack-migration/references/vite-config/README.md +78 -0
  101. package/.cursor/skills/deco-to-tanstack-migration/templates/package-json.md +55 -0
  102. package/.cursor/skills/deco-to-tanstack-migration/templates/root-route.md +110 -0
  103. package/.cursor/skills/deco-to-tanstack-migration/templates/router.md +96 -0
  104. package/.cursor/skills/deco-to-tanstack-migration/templates/setup-ts.md +167 -0
  105. package/.cursor/skills/deco-to-tanstack-migration/templates/vite-config.md +122 -0
  106. package/.cursor/skills/deco-to-tanstack-migration/templates/worker-entry.md +67 -0
  107. package/.cursor/skills/deco-typescript-fixes/SKILL.md +178 -0
  108. package/.cursor/skills/deco-typescript-fixes/common-fixes.md +330 -0
  109. package/.cursor/skills/deco-typescript-fixes/strategy.md +148 -0
  110. package/.cursor/skills/deco-variant-selection-perf/SKILL.md +272 -0
  111. package/.cursor/skills/deco-vtex-fetch-cache/SKILL.md +225 -0
  112. package/.cursor/skills/find-skills/SKILL.md +133 -0
  113. package/.cursor/skills/incident-report/SKILL.md +179 -0
  114. package/.cursor/skills/incident-report/references/5-whys.md +75 -0
  115. package/.cursor/skills/incident-report/templates/client-report.md +187 -0
  116. package/.cursor/skills/incident-report/templates/internal-report.md +206 -0
  117. package/.cursor/skills/template-skill/SKILL.md +38 -0
  118. package/.github/workflows/release.yml +32 -0
  119. package/.releaserc.json +25 -0
  120. package/CLAUDE.md +135 -0
  121. package/GAP_ANALYSIS.md +224 -0
  122. package/GAP_ANALYSIS_V2.md +1013 -0
  123. package/biome.json +39 -0
  124. package/knip.json +5 -0
  125. package/package.json +87 -0
  126. package/scripts/generate-blocks.ts +69 -0
  127. package/scripts/generate-invoke.ts +378 -0
  128. package/scripts/generate-schema.ts +657 -0
  129. package/src/admin/cors.ts +29 -0
  130. package/src/admin/decofile.ts +72 -0
  131. package/src/admin/index.ts +24 -0
  132. package/src/admin/invoke.ts +163 -0
  133. package/src/admin/liveControls.ts +29 -0
  134. package/src/admin/meta.ts +70 -0
  135. package/src/admin/render.ts +205 -0
  136. package/src/admin/schema.ts +686 -0
  137. package/src/admin/setup.ts +44 -0
  138. package/src/cms/index.ts +59 -0
  139. package/src/cms/loader.ts +180 -0
  140. package/src/cms/registry.ts +162 -0
  141. package/src/cms/resolve.ts +1005 -0
  142. package/src/cms/sectionLoaders.ts +294 -0
  143. package/src/hooks/DecoPageRenderer.tsx +444 -0
  144. package/src/hooks/LazySection.tsx +109 -0
  145. package/src/hooks/LiveControls.tsx +108 -0
  146. package/src/hooks/SectionErrorFallback.tsx +85 -0
  147. package/src/hooks/index.ts +8 -0
  148. package/src/index.ts +5 -0
  149. package/src/matchers/builtins.ts +184 -0
  150. package/src/matchers/posthog.ts +154 -0
  151. package/src/middleware/decoState.ts +55 -0
  152. package/src/middleware/healthMetrics.ts +131 -0
  153. package/src/middleware/index.ts +80 -0
  154. package/src/middleware/liveness.ts +21 -0
  155. package/src/middleware/observability.ts +205 -0
  156. package/src/routes/adminRoutes.ts +83 -0
  157. package/src/routes/cmsRoute.ts +302 -0
  158. package/src/routes/components.tsx +34 -0
  159. package/src/routes/index.ts +15 -0
  160. package/src/sdk/analytics.ts +72 -0
  161. package/src/sdk/cacheHeaders.ts +268 -0
  162. package/src/sdk/cachedLoader.ts +206 -0
  163. package/src/sdk/clx.ts +3 -0
  164. package/src/sdk/cookie.ts +39 -0
  165. package/src/sdk/createInvoke.ts +57 -0
  166. package/src/sdk/csp.ts +59 -0
  167. package/src/sdk/env.ts +27 -0
  168. package/src/sdk/index.ts +63 -0
  169. package/src/sdk/instrumentedFetch.ts +137 -0
  170. package/src/sdk/invoke.ts +133 -0
  171. package/src/sdk/mergeCacheControl.ts +150 -0
  172. package/src/sdk/redirects.ts +217 -0
  173. package/src/sdk/requestContext.ts +184 -0
  174. package/src/sdk/serverTimings.ts +68 -0
  175. package/src/sdk/signal.ts +41 -0
  176. package/src/sdk/sitemap.ts +143 -0
  177. package/src/sdk/urlUtils.ts +117 -0
  178. package/src/sdk/useDevice.ts +82 -0
  179. package/src/sdk/useId.ts +7 -0
  180. package/src/sdk/useScript.ts +101 -0
  181. package/src/sdk/workerEntry.ts +703 -0
  182. package/src/sdk/wrapCaughtErrors.ts +107 -0
  183. package/src/types/index.ts +39 -0
  184. package/src/types/widgets.ts +13 -0
  185. package/tsconfig.json +13 -0
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: deco-site-patterns
3
+ description: Pattern reference for building Deco storefronts. Covers how a site uses the framework (@deco/deco) and apps (deco-cx/apps) together — CMS wiring via __resolveType, section patterns (loaders, LoadingFallback, JSDoc annotations for admin), client-side patterns (invoke proxy, signals, islands, analytics), and app composition (site.ts factory, AppContext, theme, images). Based on analysis of production sites like osklenbr. Use when building new sections, wiring CMS data, creating islands, setting up analytics, composing apps, or understanding how sites connect to the Deco ecosystem.
4
+ globs:
5
+ - "**/apps/site.ts"
6
+ - "**/manifest.gen.ts"
7
+ - "**/runtime.ts"
8
+ - "**/fresh.config.ts"
9
+ - "**/.deco/blocks/*.json"
10
+ - "**/sections/**/*.tsx"
11
+ - "**/islands/**/*.tsx"
12
+ - "**/sdk/**/*.ts"
13
+ ---
14
+
15
+ ## Sub-documents
16
+
17
+ | Document | Topic |
18
+ |----------|-------|
19
+ | [cms-wiring.md](./cms-wiring.md) | CMS block system, __resolveType, decofile, pages, redirects, dependency resolution |
20
+ | [section-patterns.md](./section-patterns.md) | Section conventions, loaders, LoadingFallback, JSDoc for admin, widget types |
21
+ | [client-patterns.md](./client-patterns.md) | Invoke proxy, islands, signals, analytics, cart/wishlist/user hooks, SDK utilities |
22
+ | [app-composition.md](./app-composition.md) | App factory, AppContext, theme, images, routes, matchers, global layout |
23
+
24
+ # Deco Site Patterns
25
+
26
+ Pattern reference for building Deco storefronts. Documents how a site uses the Deco framework and apps ecosystem.
27
+
28
+ ## Three-Layer Architecture
29
+
30
+ ```
31
+ @deco/deco (framework)
32
+ Resolution engine, block system, plugins, hooks, runtime
33
+ |
34
+ deco-cx/apps (integrations)
35
+ Commerce types, VTEX/Shopify loaders, website handlers, matchers, analytics
36
+ |
37
+ Site repo (storefront)
38
+ Sections, islands, components, SDK, routes, .deco/blocks
39
+ ```
40
+
41
+ The framework resolves blocks. Apps provide commerce and website capabilities. The site wires them together via CMS configuration and custom code.
42
+
43
+ ## Site File Structure
44
+
45
+ ```
46
+ my-store/
47
+ |-- deno.json # Imports, tasks, compiler options
48
+ |-- fresh.config.ts # Fresh + Deco plugin registration
49
+ |-- manifest.gen.ts # Auto-generated block registry
50
+ |-- fresh.gen.ts # Auto-generated Fresh manifest (routes + islands)
51
+ |-- runtime.ts # Typed invoke proxy for client-side calls
52
+ |-- main.ts # Production entry point
53
+ |-- dev.ts # Dev entry (tailwind + HMR)
54
+ |
55
+ |-- apps/ # App registrations
56
+ | |-- site.ts # Main app: manifest + dependencies (std, commerce)
57
+ | |-- decohub.ts # Admin hub re-export
58
+ |
59
+ |-- .deco/blocks/ # CMS content (decofile)
60
+ | |-- site.json # Root config: global sections, routes, SEO, theme
61
+ | |-- everyone.json # Flag with route definitions
62
+ | |-- pages-*.json # Page blocks with sections and variants
63
+ | |-- redirects-*.json # Individual redirect definitions
64
+ | |-- vtex.json # VTEX app configuration
65
+ |
66
+ |-- sections/ # CMS-renderable UI sections
67
+ | |-- ProductRetrofit/ # Product sections (PDP, shelf, search)
68
+ | |-- HeaderRetrofit/ # Header section
69
+ | |-- FooterRetrofit/ # Footer section
70
+ | |-- ImagesRetrofit/ # Banner, carousel, gallery sections
71
+ | |-- Theme/ # Theme section (colors, fonts, CSS vars)
72
+ |
73
+ |-- islands/ # Client-side interactive components (hydrated)
74
+ | |-- HeaderRetrofit/ # Header islands (search, drawers)
75
+ | |-- DetailsRetrofit/ # PDP islands (product actions, size selector)
76
+ | |-- CartRetrofit/ # Cart island
77
+ |
78
+ |-- components/ # Shared Preact components (used by sections + islands)
79
+ | |-- productRetrofit/ # Product card, gallery, details
80
+ | |-- searchRetrofit/ # Search result, filters, sort
81
+ | |-- uiRetrofit/ # Base UI (image, slider, modal, button)
82
+ | |-- minicartRetrofit/ # Cart, cart item, coupon
83
+ |
84
+ |-- sdk/ # Client-side utilities
85
+ | |-- useUIRetrofit.ts # Global UI state (signals)
86
+ | |-- formatRetrofit.ts # Price formatting
87
+ | |-- analyticsRetrofit.ts # Analytics event dispatch
88
+ | |-- useAddToCart*.ts # Add to cart logic
89
+ | |-- useLazyLoad.tsx # IntersectionObserver lazy loading
90
+ |
91
+ |-- loaders/ # Site-specific data loaders
92
+ |-- actions/ # Site-specific mutations
93
+ |-- matchers/ # Site-specific audience matchers
94
+ |-- routes/ # Fresh routes (_app.tsx, proxy.ts)
95
+ |-- static/ # Static assets
96
+ ```
97
+
98
+ ## Key Concepts
99
+
100
+ ### 1. Everything is a Block
101
+
102
+ Sections, loaders, actions, handlers, matchers, and flags are all "blocks" registered in `manifest.gen.ts`. The CMS references them by key (e.g., `site/sections/ProductRetrofit/ProductDetails.tsx`).
103
+
104
+ ### 2. CMS Wires Data to Sections
105
+
106
+ The CMS admin creates page configurations stored in `.deco/blocks/pages-*.json`. Each section in a page can have props that reference loaders via `__resolveType`. The framework resolves these before rendering.
107
+
108
+ ### 3. Islands Bridge Server and Client
109
+
110
+ Sections render on the server. Islands are the client-side boundary -- they hydrate and run in the browser. Islands use `invoke` to call server loaders/actions and `@preact/signals` for reactive state.
111
+
112
+ ### 4. Apps Compose Capabilities
113
+
114
+ The site's `apps/site.ts` composes the `std` (compatibility) and `commerce` (VTEX/Shopify) apps as dependencies. Each app contributes loaders, actions, and handlers to the manifest.
115
+
116
+ ## Related Skills
117
+
118
+ | Skill | Focus |
119
+ |-------|-------|
120
+ | `deco-core-architecture` | Framework internals (engine, blocks, runtime) |
121
+ | `deco-apps-architecture` | Apps monorepo structure (VTEX, Shopify, website) |
122
+ | `deco-start-architecture` | TanStack Start version of the framework |
123
+ | `deco-to-tanstack-migration` | Fresh/Preact to TanStack/React migration |
124
+ | `deco-apps-vtex-porting` | VTEX-specific porting guide |
@@ -0,0 +1,337 @@
1
+ # App Composition
2
+
3
+ How a Deco site registers apps, configures global layout, handles routes, themes, images, and matchers.
4
+
5
+ ## App Factory (`apps/site.ts`)
6
+
7
+ The main app combines the site's manifest with commerce dependencies:
8
+
9
+ ```typescript
10
+ import manifest, { Manifest } from "../manifest.gen.ts";
11
+ import { type App, type AppContext as AC } from "@deco/deco";
12
+ import commerce from "apps/commerce/mod.ts";
13
+ import std from "apps/compat/std/mod.ts";
14
+
15
+ export type AppContext = AC<ReturnType<typeof Site>>;
16
+
17
+ interface Props {
18
+ trafficToDeco: number;
19
+ decoHostToRedirect: string;
20
+ }
21
+
22
+ export default function Site(
23
+ state: Props,
24
+ ): App<Manifest, Props, [typeof std, ReturnType<typeof commerce>]> {
25
+ return {
26
+ state,
27
+ manifest,
28
+ dependencies: [std(state), commerce(state)],
29
+ };
30
+ }
31
+
32
+ export { onBeforeResolveProps, Preview } from "apps/website/mod.ts";
33
+ ```
34
+
35
+ Key elements:
36
+ - **`manifest`** -- auto-generated from `manifest.gen.ts`, registers all site blocks
37
+ - **`state`** -- props configurable in the admin (traffic percentage, redirect host)
38
+ - **`dependencies`** -- `std` (compatibility layer) and `commerce` (VTEX/Shopify depending on config)
39
+ - **`AppContext`** -- typed context for loaders/actions: `AC<ReturnType<typeof Site>>`
40
+
41
+ ### Decohub (`apps/decohub.ts`)
42
+
43
+ One-line re-export that enables the admin panel:
44
+
45
+ ```typescript
46
+ export { default, Preview } from "apps/decohub/mod.ts";
47
+ ```
48
+
49
+ ### How Commerce Composes
50
+
51
+ `apps/commerce/mod.ts` reads the `platform` field from `site.json` and selects the right integration:
52
+
53
+ ```json
54
+ { "commerce": { "platform": "vtex" } }
55
+ ```
56
+
57
+ This loads `apps/vtex/mod.ts` which contributes all VTEX loaders, actions, and handlers to the manifest. The admin then shows VTEX-specific loader options in section prop selectors.
58
+
59
+ ## AppContext
60
+
61
+ `AppContext` gives loaders and actions typed access to the entire app ecosystem:
62
+
63
+ ```typescript
64
+ import { AppContext } from "site/apps/site.ts";
65
+
66
+ export const loader = async (props: Props, req: Request, ctx: AppContext) => {
67
+ // Invoke another loader
68
+ const user = await ctx.invoke("site/actions/checkUser.ts");
69
+
70
+ // Resolve a block by __resolveType
71
+ const { credentials } = await ctx.get({ "__resolveType": "Tokens" });
72
+
73
+ // Access request
74
+ const cookies = req.headers.get("cookie");
75
+
76
+ return { ...props, user };
77
+ };
78
+ ```
79
+
80
+ | Method | Purpose |
81
+ |--------|---------|
82
+ | `ctx.invoke(key, props?)` | Call another loader/action by manifest key |
83
+ | `ctx.get(resolvable)` | Resolve a block (Secrets, config, etc.) |
84
+ | `ctx.state` | Access app state (props from `site.ts`) |
85
+
86
+ ## Loader and Action Signatures
87
+
88
+ ### Loader
89
+
90
+ ```typescript
91
+ export default async function loader(
92
+ props: Props, // CMS-configured props (with resolved __resolveType)
93
+ req: Request, // HTTP request (headers, cookies, URL)
94
+ ctx: AppContext, // App context (invoke, get, state)
95
+ ): Promise<ReturnType> {
96
+ // ...
97
+ }
98
+ ```
99
+
100
+ ### Action
101
+
102
+ ```typescript
103
+ export default async function action(
104
+ props: Props,
105
+ req: Request,
106
+ ctx: AppContext,
107
+ ): Promise<ReturnType> {
108
+ // Mutations (create/update/delete)
109
+ }
110
+ ```
111
+
112
+ Actions are called via `ctx.invoke()` or the client-side `invoke` proxy. They're not cached (unlike loaders).
113
+
114
+ ## Global Layout (`routes/_app.tsx`)
115
+
116
+ The global layout wraps every page:
117
+
118
+ ```tsx
119
+ import { AppProps } from "$fresh/server.ts";
120
+ import Theme from "site/sections/Theme/Theme.tsx";
121
+ import GlobalTags from "site/components/GlobalTags.tsx";
122
+ import ThirdPartyScripts from "site/components/ThirdPartyScripts.tsx";
123
+ import Promotion from "site/components/scriptRetrofit/promotion/promotion.tsx";
124
+
125
+ function App(props: AppProps) {
126
+ return (
127
+ <html>
128
+ <head>
129
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
130
+ </head>
131
+ <Theme />
132
+ <GlobalTags />
133
+ <ThirdPartyScripts />
134
+ <props.Component />
135
+ <Promotion rootId="promotion-monitor" />
136
+ </html>
137
+ );
138
+ }
139
+
140
+ export default App;
141
+ ```
142
+
143
+ | Component | Purpose |
144
+ |-----------|---------|
145
+ | `Theme` | CSS variables for colors, fonts, button styles |
146
+ | `GlobalTags` | Meta tags, CSS, manifest.json, tracking pixels (Meta, Hotjar, RetailRocket) |
147
+ | `ThirdPartyScripts` | External scripts (chat, accessibility) |
148
+ | `<props.Component />` | Page content (sections from CMS) |
149
+ | `Promotion` | Promotion flow monitoring script |
150
+
151
+ ## Proxy Routes
152
+
153
+ Sites proxy external scripts through their own domain to avoid CSP issues:
154
+
155
+ ```typescript
156
+ // routes/proxy.ts
157
+ const ALLOWLIST_URLS = [
158
+ "https://mcdn.retailrocket.net/content/javascript/trackingm.js",
159
+ "https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js?v=1",
160
+ "https://static.hotjar.com/c/hotjar-2214037.js?sv=6",
161
+ ];
162
+
163
+ export const handler: Handlers = {
164
+ GET: async (req) => {
165
+ const url = new URL(req.url).searchParams.get("url");
166
+ if (!url || !ALLOWLIST_URLS.includes(url)) {
167
+ return new Response(url, { status: 404 });
168
+ }
169
+ const response = await fetch(url);
170
+ return new Response(response.body, {
171
+ headers: {
172
+ ...Object.fromEntries(response.headers),
173
+ "access-control-allow-origin": "*",
174
+ "access-control-allow-headers": "*",
175
+ },
176
+ });
177
+ },
178
+ };
179
+ ```
180
+
181
+ URL is passed via `?url=...` query parameter. Only allowlisted URLs are proxied. CORS headers are added.
182
+
183
+ ## Theme Section
184
+
185
+ The Theme section defines the site's design tokens as CSS variables:
186
+
187
+ ```typescript
188
+ // sections/Theme/Theme.tsx
189
+ export interface MainColors {
190
+ /** @format color @title Base @default #FFFFFF */
191
+ "base-100": string;
192
+ /** @format color @title Primary @default #003232 */
193
+ primary: string;
194
+ /** @format color @title Secondary @default #000000 */
195
+ secondary: string;
196
+ /** @format color @title Tertiary @default #8C8C8C */
197
+ tertiary: string;
198
+ }
199
+
200
+ export interface Props {
201
+ mainColors: MainColors;
202
+ fontFamily?: GoogleFont;
203
+ customFont?: string;
204
+ buttonStyle?: { borderRadius?: string };
205
+ }
206
+ ```
207
+
208
+ Renders as:
209
+
210
+ ```tsx
211
+ <style>
212
+ :root {
213
+ --p: 165 100% 10%; /* primary HSL */
214
+ --pf: 165 100% 8%; /* primary focus */
215
+ --b1: 0 0% 100%; /* base-100 */
216
+ --b2: 0 0% 95%; /* base-200 */
217
+ --rounded-btn: 0;
218
+ }
219
+ </style>
220
+ ```
221
+
222
+ Uses DaisyUI variable convention (`--p`, `--s`, `--b1`, etc.).
223
+
224
+ ## Image Patterns
225
+
226
+ Sites use components from `apps/website/components/` for optimized images:
227
+
228
+ ```tsx
229
+ import { Picture, Source } from "apps/website/components/Picture.tsx";
230
+ import Image from "apps/website/components/Image.tsx";
231
+
232
+ function Banner({ srcMobile, srcDesktop, alt }: Props) {
233
+ return (
234
+ <Picture class="w-full h-full">
235
+ <Source
236
+ media="(max-width: 768px)"
237
+ src={srcMobile}
238
+ width={375}
239
+ height={500}
240
+ />
241
+ <Source
242
+ media="(min-width: 769px)"
243
+ src={srcDesktop}
244
+ width={1440}
245
+ height={600}
246
+ />
247
+ <Image
248
+ class="w-full h-full object-cover"
249
+ src={srcDesktop}
250
+ alt={alt}
251
+ width={1440}
252
+ height={600}
253
+ loading="lazy"
254
+ decoding="async"
255
+ />
256
+ </Picture>
257
+ );
258
+ }
259
+ ```
260
+
261
+ Key practices:
262
+ - Always set `width` and `height` to prevent CLS
263
+ - Use `loading="lazy"` for below-fold images, `loading="eager"` for above-fold
264
+ - Use `decoding="async"` for non-blocking decode
265
+ - Use `Picture + Source` for responsive images (mobile/desktop)
266
+ - `ImageWidget` type in props enables the admin CDN uploader
267
+
268
+ ## Site-Level Matchers
269
+
270
+ Sites can define custom matchers beyond the built-in ones:
271
+
272
+ ```typescript
273
+ // matchers/MatchBirthdayMonth.ts
274
+ import { AppContext } from "site/apps/site.ts";
275
+
276
+ export interface Props {
277
+ birthdate: { month: number; day: number } | null;
278
+ }
279
+
280
+ export default function MatchBirthdayMonth(
281
+ props: Props,
282
+ _req: Request,
283
+ _ctx: AppContext,
284
+ ): boolean {
285
+ if (!props.birthdate) return false;
286
+ return props.birthdate.month === new Date().getMonth() + 1;
287
+ }
288
+ ```
289
+
290
+ Custom matchers are registered in `manifest.gen.ts` and can be used in CMS multivariate flags:
291
+
292
+ ```json
293
+ {
294
+ "rule": { "__resolveType": "site/matchers/MatchBirthdayMonth.ts", "birthdate": { "__resolveType": "site/loaders/birthdate.ts" } },
295
+ "value": [/* birthday-themed sections */]
296
+ }
297
+ ```
298
+
299
+ ## Configuration Files
300
+
301
+ ### `deno.json`
302
+
303
+ ```json
304
+ {
305
+ "imports": {
306
+ "$fresh/": "https://fresh.deno.dev@1.7.3/",
307
+ "@deco/deco": "jsr:@deco/deco@1.174.2",
308
+ "apps/": "https://cdn.jsdelivr.net/gh/deco-cx/apps@0.139.0/",
309
+ "$store/": "./",
310
+ "site/": "./",
311
+ "preact": "npm:preact@10.23.1"
312
+ },
313
+ "tasks": {
314
+ "start": "deno eval 'import \"https://deco.cx/run\"'",
315
+ "dev": "deno task gen && deno eval 'import \"$fresh/src/dev/mod.ts\"'",
316
+ "gen": "deno run -A dev.ts --gen-only",
317
+ "build": "DECO_SITE_NAME=mystore deno run -A dev.ts build"
318
+ },
319
+ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" }
320
+ }
321
+ ```
322
+
323
+ Key aliases: `$store/` and `site/` both point to the project root, enabling both `$store/components/...` and `site/sections/...` import styles.
324
+
325
+ ### `fresh.config.ts`
326
+
327
+ ```typescript
328
+ import { defineConfig } from "$fresh/server.ts";
329
+ import { plugins } from "deco/plugins/deco.ts";
330
+ import manifest from "./manifest.gen.ts";
331
+
332
+ export default defineConfig({
333
+ plugins: plugins({ manifest, htmx: false }),
334
+ });
335
+ ```
336
+
337
+ The Deco plugin takes over Fresh's routing, injecting the CMS page handler as the catch-all route.