@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,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.
|