@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,96 @@
1
+ # router.tsx Template
2
+
3
+ ```typescript
4
+ import { createRouter as createTanStackRouter } from "@tanstack/react-router";
5
+ import { routeTree } from "./routeTree.gen";
6
+
7
+ export function createRouter() {
8
+ const router = createTanStackRouter({
9
+ routeTree,
10
+ scrollRestoration: true,
11
+ });
12
+
13
+ // Scroll to top on forward navigation (PUSH/REPLACE), skip on back/forward (GO)
14
+ router.subscribe("onResolved", (evt) => {
15
+ if (evt.type === "GO") return;
16
+ window.scrollTo({ top: 0 });
17
+ });
18
+
19
+ return router;
20
+ }
21
+
22
+ declare module "@tanstack/react-router" {
23
+ interface Register {
24
+ router: ReturnType<typeof createRouter>;
25
+ }
26
+ }
27
+ ```
28
+
29
+ ## Route Files
30
+
31
+ ### src/routes/index.tsx (Homepage)
32
+
33
+ ```typescript
34
+ import { createFileRoute } from "@tanstack/react-router";
35
+ import { cmsHomeRouteConfig } from "@decocms/start/routes";
36
+ import { DecoPageRenderer } from "@decocms/start/hooks";
37
+ import { loadDeferredSection } from "@decocms/start/routes/cmsRoute";
38
+
39
+ const { loader, head } = cmsHomeRouteConfig({
40
+ defaultTitle: "My Store",
41
+ });
42
+
43
+ export const Route = createFileRoute("/")({
44
+ loader,
45
+ head,
46
+ component: HomePage,
47
+ });
48
+
49
+ function HomePage() {
50
+ const { resolvedSections, deferredSections, pagePath } = Route.useLoaderData();
51
+ return (
52
+ <DecoPageRenderer
53
+ sections={resolvedSections}
54
+ deferredSections={deferredSections}
55
+ pagePath={pagePath}
56
+ loadDeferredSectionFn={loadDeferredSection}
57
+ />
58
+ );
59
+ }
60
+ ```
61
+
62
+ ### src/routes/$.tsx (Catch-All CMS Route)
63
+
64
+ ```typescript
65
+ import { createFileRoute, notFound } from "@tanstack/react-router";
66
+ import { cmsRouteConfig } from "@decocms/start/routes";
67
+ import { DecoPageRenderer } from "@decocms/start/hooks";
68
+ import { loadDeferredSection } from "@decocms/start/routes/cmsRoute";
69
+
70
+ const { loader, head } = cmsRouteConfig({
71
+ siteName: "My Store",
72
+ ignoreSearchParams: ["skuId"],
73
+ });
74
+
75
+ export const Route = createFileRoute("/$")({
76
+ loader: async (ctx) => {
77
+ const data = await loader(ctx);
78
+ if (!data) throw notFound();
79
+ return data;
80
+ },
81
+ head,
82
+ component: CmsPage,
83
+ });
84
+
85
+ function CmsPage() {
86
+ const { resolvedSections, deferredSections, pagePath } = Route.useLoaderData();
87
+ return (
88
+ <DecoPageRenderer
89
+ sections={resolvedSections}
90
+ deferredSections={deferredSections}
91
+ pagePath={pagePath}
92
+ loadDeferredSectionFn={loadDeferredSection}
93
+ />
94
+ );
95
+ }
96
+ ```
@@ -0,0 +1,167 @@
1
+ # setup.ts Template
2
+
3
+ Annotated template based on espacosmart-storefront (100+ sections, VTEX, async rendering).
4
+
5
+ ```typescript
6
+ // ==========================================================================
7
+ // 1. CMS BLOCKS & META
8
+ // ==========================================================================
9
+
10
+ import blocksJson from "./server/cms/blocks.gen.ts";
11
+ import metaData from "./server/admin/meta.gen.json";
12
+ import { setBlocks } from "@decocms/start/cms/loader";
13
+ import { setMetaData, setInvokeLoaders, setRenderShell } from "@decocms/start/admin";
14
+ import { registerSections, registerSectionsSync, setResolvedComponent } from "@decocms/start/cms/registry";
15
+ import { registerSectionLoaders, registerLayoutSections } from "@decocms/start/cms/sectionLoaders";
16
+ import { registerCommerceLoaders, setAsyncRenderingConfig, onBeforeResolve } from "@decocms/start/cms/resolve";
17
+ import { createCachedLoader } from "@decocms/start/sdk/cachedLoader";
18
+ import appCss from "./styles/app.css?url";
19
+
20
+ // Load CMS blocks (pages, sections, configs) from generated JSON
21
+ setBlocks(blocksJson);
22
+
23
+ // Set admin schema for /live/_meta endpoint
24
+ setMetaData(metaData);
25
+
26
+ // Configure admin preview HTML shell
27
+ setRenderShell({
28
+ css: appCss,
29
+ fonts: ["https://fonts.googleapis.com/css2?family=YourFont:wght@400;500;600;700&display=swap"],
30
+ theme: "light", // data-theme="light" on <html> for DaisyUI
31
+ bodyClass: "bg-base-100 text-base-content",
32
+ lang: "pt-BR",
33
+ });
34
+
35
+ // ==========================================================================
36
+ // 2. SECTION REGISTRATION
37
+ // ==========================================================================
38
+
39
+ // Critical sections — above-the-fold, bundled synchronously
40
+ import HeaderSection from "./components/header/Header";
41
+ import FooterSection from "./sections/Footer/Footer";
42
+
43
+ const criticalSections: Record<string, any> = {
44
+ "site/sections/Header/Header.tsx": HeaderSection,
45
+ "site/sections/Footer/Footer.tsx": FooterSection,
46
+ };
47
+
48
+ // Register sync components for instant SSR (no Suspense boundary)
49
+ for (const [key, mod] of Object.entries(criticalSections)) {
50
+ setResolvedComponent(key, mod.default || mod);
51
+ }
52
+ registerSectionsSync(criticalSections);
53
+
54
+ // All sections — lazy-loaded via dynamic import
55
+ registerSections({
56
+ "site/sections/Header/Header.tsx": () => import("./sections/Header/Header"),
57
+ "site/sections/Footer/Footer.tsx": () => import("./sections/Footer/Footer"),
58
+ "site/sections/Theme/Theme.tsx": () => import("./sections/Theme/Theme"),
59
+ // ... register ALL sections from src/sections/ here
60
+ // Pattern: "site/sections/Path/Name.tsx": () => import("./sections/Path/Name")
61
+ });
62
+
63
+ // ==========================================================================
64
+ // 3. LAYOUT SECTIONS
65
+ // ==========================================================================
66
+
67
+ // Layout sections are always rendered eagerly (never lazy/deferred),
68
+ // even if wrapped in Lazy.tsx in the CMS.
69
+ registerLayoutSections([
70
+ "site/sections/Header/Header.tsx",
71
+ "site/sections/Footer/Footer.tsx",
72
+ "site/sections/Theme/Theme.tsx",
73
+ "site/sections/Social/WhatsApp.tsx",
74
+ ]);
75
+
76
+ // ==========================================================================
77
+ // 4. SECTION LOADERS
78
+ // ==========================================================================
79
+
80
+ // Section loaders enrich CMS props with server-side data (e.g., VTEX API calls).
81
+ // Only needed for sections that export `const loader`.
82
+ registerSectionLoaders({
83
+ "site/sections/Product/ProductShelf.tsx": (props: any, req: Request) =>
84
+ import("./components/product/ProductShelf").then((m) => m.loader(props, req)),
85
+ "site/sections/Product/SearchResult.tsx": (props: any, req: Request) =>
86
+ import("./components/search/SearchResult").then((m) => m.loader(props, req)),
87
+ // ... add for each section that has `export const loader`
88
+ });
89
+
90
+ // ==========================================================================
91
+ // 5. COMMERCE LOADERS (VTEX)
92
+ // ==========================================================================
93
+
94
+ import { vtexProductList } from "@decocms/apps/vtex/loaders/productList";
95
+ import { vtexProductDetailsPage } from "@decocms/apps/vtex/loaders/productDetailsPage";
96
+ import { vtexProductListingPage } from "@decocms/apps/vtex/loaders/productListingPage";
97
+ import { vtexSuggestions } from "@decocms/apps/vtex/loaders/suggestions";
98
+ import { initVtexFromBlocks } from "@decocms/apps/vtex/setup";
99
+
100
+ // SWR-cached commerce loaders — avoids re-fetching on every page navigation
101
+ const cachedProductList = createCachedLoader("vtex/productList", vtexProductList, {
102
+ policy: "stale-while-revalidate", maxAge: 60_000,
103
+ });
104
+ const cachedPDP = createCachedLoader("vtex/pdp", vtexProductDetailsPage, {
105
+ policy: "stale-while-revalidate", maxAge: 30_000,
106
+ });
107
+ const cachedPLP = createCachedLoader("vtex/plp", vtexProductListingPage, {
108
+ policy: "stale-while-revalidate", maxAge: 60_000,
109
+ });
110
+ const cachedSuggestions = createCachedLoader("vtex/suggestions", vtexSuggestions, {
111
+ policy: "stale-while-revalidate", maxAge: 120_000,
112
+ });
113
+
114
+ // Map CMS __resolveType strings to actual loader functions
115
+ registerCommerceLoaders({
116
+ "vtex/loaders/intelligentSearch/productList.ts": cachedProductList,
117
+ "vtex/loaders/intelligentSearch/productListingPage.ts": cachedPLP,
118
+ "vtex/loaders/intelligentSearch/productDetailsPage.ts": cachedPDP,
119
+ "vtex/loaders/intelligentSearch/suggestions.ts": cachedSuggestions,
120
+ // Add passthrough loaders for types that don't need caching:
121
+ // "vtex/loaders/config.ts": (props) => props,
122
+ });
123
+
124
+ // ==========================================================================
125
+ // 6. VTEX INITIALIZATION
126
+ // ==========================================================================
127
+
128
+ // onBeforeResolve runs once before the first CMS page resolution.
129
+ // initVtexFromBlocks reads VTEX config (account, publicUrl) from CMS blocks.
130
+ onBeforeResolve(() => {
131
+ initVtexFromBlocks();
132
+ });
133
+
134
+ // ==========================================================================
135
+ // 7. ASYNC RENDERING
136
+ // ==========================================================================
137
+
138
+ // Enable deferred section loading (scroll-triggered).
139
+ // Respects CMS Lazy wrappers. Layout sections and alwaysEager are never deferred.
140
+ setAsyncRenderingConfig({
141
+ alwaysEager: [
142
+ "site/sections/Header/Header.tsx",
143
+ "site/sections/Footer/Footer.tsx",
144
+ "site/sections/Theme/Theme.tsx",
145
+ "site/sections/Images/Carousel.tsx",
146
+ // Add above-the-fold sections here
147
+ ],
148
+ });
149
+
150
+ // ==========================================================================
151
+ // 8. INVOKE LOADERS (for /deco/invoke endpoint)
152
+ // ==========================================================================
153
+
154
+ setInvokeLoaders({
155
+ "vtex/loaders/intelligentSearch/productList.ts": cachedProductList,
156
+ "vtex/loaders/intelligentSearch/suggestions.ts": cachedSuggestions,
157
+ // Used by the admin to preview loader results
158
+ });
159
+ ```
160
+
161
+ ## Key Patterns
162
+
163
+ 1. **Order matters**: blocks → meta → sections → loaders → commerce → async config
164
+ 2. **Critical sections**: Import synchronously for instant SSR, also register as lazy for client code-splitting
165
+ 3. **SWR caching**: `createCachedLoader` wraps commerce loaders with stale-while-revalidate
166
+ 4. **onBeforeResolve**: Deferred initialization — VTEX config is read from CMS blocks at first request
167
+ 5. **alwaysEager**: Sections that must render on first paint (no deferred loading)
@@ -0,0 +1,122 @@
1
+ # vite.config.ts Template
2
+
3
+ Battle-tested configuration from espacosmart-storefront.
4
+
5
+ ```typescript
6
+ import { cloudflare } from "@cloudflare/vite-plugin";
7
+ import { tanstackStart } from "@tanstack/react-start/plugin/vite";
8
+ import react from "@vitejs/plugin-react";
9
+ import tailwindcss from "@tailwindcss/vite";
10
+ import { defineConfig } from "vite";
11
+ import path from "path";
12
+
13
+ const srcDir = path.resolve(__dirname, "src");
14
+
15
+ export default defineConfig({
16
+ plugins: [
17
+ cloudflare({ viteEnvironment: { name: "ssr" } }),
18
+ tanstackStart({ server: { entry: "server" } }),
19
+ react({
20
+ babel: {
21
+ plugins: [
22
+ ["babel-plugin-react-compiler", { target: "19" }],
23
+ ],
24
+ },
25
+ }),
26
+ tailwindcss(),
27
+ // CRITICAL: Stubs for client bundles that transitively import server modules.
28
+ // Without this, client build crashes on node:async_hooks, react-dom/server, etc.
29
+ {
30
+ name: "deco-server-only-stubs",
31
+ enforce: "pre" as const,
32
+ resolveId(id, _importer, options) {
33
+ if (options?.ssr) return undefined;
34
+ const CLIENT_STUBS: Record<string, string> = {
35
+ "react-dom/server": "\0stub:react-dom-server",
36
+ "react-dom/server.browser": "\0stub:react-dom-server",
37
+ "node:stream": "\0stub:node-stream",
38
+ "node:stream/web": "\0stub:node-stream-web",
39
+ "node:async_hooks": "\0stub:node-async-hooks",
40
+ "tanstack-start-injected-head-scripts:v": "\0stub:tanstack-head-scripts",
41
+ };
42
+ return CLIENT_STUBS[id];
43
+ },
44
+ configEnvironment(name: string, env: any) {
45
+ if (name === "ssr" || name === "client") {
46
+ env.optimizeDeps = env.optimizeDeps || {};
47
+ env.optimizeDeps.esbuildOptions = env.optimizeDeps.esbuildOptions || {};
48
+ env.optimizeDeps.esbuildOptions.jsx = "automatic";
49
+ env.optimizeDeps.esbuildOptions.jsxImportSource = "react";
50
+ }
51
+ },
52
+ load(id) {
53
+ if (id === "\0stub:react-dom-server") {
54
+ return [
55
+ "const noop = () => '';",
56
+ "export const renderToString = noop;",
57
+ "export const renderToStaticMarkup = noop;",
58
+ "export const renderToReadableStream = noop;",
59
+ "export const resume = noop;",
60
+ "export const version = '19.0.0';",
61
+ "export default { renderToString: noop, renderToStaticMarkup: noop, renderToReadableStream: noop, resume: noop, version: '19.0.0' };",
62
+ ].join("\n");
63
+ }
64
+ if (id === "\0stub:node-stream") {
65
+ return "export class PassThrough {}; export class Readable {}; export class Writable {}; export default { PassThrough, Readable, Writable };";
66
+ }
67
+ if (id === "\0stub:node-stream-web") {
68
+ return "export const ReadableStream = globalThis.ReadableStream; export const WritableStream = globalThis.WritableStream; export const TransformStream = globalThis.TransformStream; export default { ReadableStream, WritableStream, TransformStream };";
69
+ }
70
+ if (id === "\0stub:node-async-hooks") {
71
+ return [
72
+ "class _ALS { getStore() { return undefined; } run(_store, fn, ...args) { return fn(...args); } enterWith() {} disable() {} }",
73
+ "export const AsyncLocalStorage = _ALS;",
74
+ "export const AsyncResource = class {};",
75
+ "export function executionAsyncId() { return 0; }",
76
+ "export function createHook() { return { enable() {}, disable() {} }; }",
77
+ "export default { AsyncLocalStorage: _ALS, AsyncResource, executionAsyncId, createHook };",
78
+ ].join("\n");
79
+ }
80
+ if (id === "\0stub:tanstack-head-scripts") {
81
+ return "export const injectedHeadScripts = undefined;";
82
+ }
83
+ },
84
+ },
85
+ ],
86
+ // Inject site name at build time (not runtime)
87
+ define: {
88
+ "process.env.DECO_SITE_NAME": JSON.stringify(
89
+ process.env.DECO_SITE_NAME || "my-store"
90
+ ),
91
+ },
92
+ esbuild: {
93
+ jsx: "automatic",
94
+ jsxImportSource: "react",
95
+ },
96
+ resolve: {
97
+ // CRITICAL: Without dedupe, multiple React/TanStack instances cause hook errors
98
+ dedupe: [
99
+ "@tanstack/react-start",
100
+ "@tanstack/react-router",
101
+ "@tanstack/react-start-server",
102
+ "@tanstack/start-server-core",
103
+ "@tanstack/start-client-core",
104
+ "@tanstack/start-plugin-core",
105
+ "@tanstack/start-storage-context",
106
+ "react",
107
+ "react-dom",
108
+ ],
109
+ alias: {
110
+ "~": srcDir,
111
+ },
112
+ },
113
+ });
114
+ ```
115
+
116
+ ## Key Points
117
+
118
+ 1. **deco-server-only-stubs plugin** — Required. Client bundles transitively import `node:async_hooks`, `react-dom/server`, etc. Without stubs, build crashes.
119
+ 2. **resolve.dedupe** — Required. Without it, multiple React instances cause "Invalid hook call" errors.
120
+ 3. **process.env.DECO_SITE_NAME via define** — Must be injected at build time, not read at runtime.
121
+ 4. **React Compiler** — `babel-plugin-react-compiler` with target 19 for automatic memoization.
122
+ 5. **esbuild.jsx** — Must be `"automatic"` with `jsxImportSource: "react"` for proper JSX transform.
@@ -0,0 +1,67 @@
1
+ # Worker Entry Templates
2
+
3
+ ## src/server.ts
4
+
5
+ ```typescript
6
+ // CRITICAL: import "./setup" MUST be the first import.
7
+ // Without it, server functions in Vite split modules have empty state
8
+ // (blocks, registry, commerce loaders) causing 404 on client-side navigation.
9
+ import "./setup";
10
+ import { createStartHandler, defaultStreamHandler } from "@tanstack/react-start/server";
11
+
12
+ export default createStartHandler(defaultStreamHandler);
13
+ ```
14
+
15
+ ## src/worker-entry.ts
16
+
17
+ ```typescript
18
+ // CRITICAL: import "./setup" MUST be the first import.
19
+ import "./setup";
20
+ import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
21
+ import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
22
+ import {
23
+ handleMeta,
24
+ handleDecofileRead,
25
+ handleDecofileReload,
26
+ handleRender,
27
+ corsHeaders,
28
+ } from "@decocms/start/admin";
29
+ // Only if using VTEX:
30
+ import { shouldProxyToVtex, proxyToVtex } from "@decocms/apps/vtex/utils/proxy";
31
+
32
+ const serverEntry = createServerEntry({
33
+ async fetch(request) {
34
+ return await handler.fetch(request);
35
+ },
36
+ });
37
+
38
+ export default createDecoWorkerEntry(serverEntry, {
39
+ admin: {
40
+ handleMeta,
41
+ handleDecofileRead,
42
+ handleDecofileReload,
43
+ handleRender,
44
+ corsHeaders,
45
+ },
46
+ // VTEX proxy — routes like /api/*, /checkout/*, /arquivos/* go to VTEX
47
+ proxyHandler: (request, url) => {
48
+ if (shouldProxyToVtex(url.pathname)) {
49
+ return proxyToVtex(request);
50
+ }
51
+ return null;
52
+ },
53
+ });
54
+ ```
55
+
56
+ ## Key Rules
57
+
58
+ 1. **`import "./setup"` is ALWAYS the first line** — both files. This registers sections, loaders, blocks, and commerce config before any server function executes.
59
+ 2. **Admin handlers go in `createDecoWorkerEntry`** — NOT inside `createServerEntry`. TanStack Start's build strips custom fetch logic from `createServerEntry` in production.
60
+ 3. **Proxy handler** — Optional. Only needed for platforms (VTEX, Shopify) that require server-side proxying.
61
+ 4. **Request flow**: `createDecoWorkerEntry` → admin routes (first) → cache check → proxy check → `serverEntry.fetch()` (TanStack Start).
62
+
63
+ ## Why `import "./setup"` Must Be First
64
+
65
+ TanStack Start compiles `createServerFn()` calls into "split modules" — separate Vite module instances. Module-level state (blockData, commerceLoaders, sectionRegistry) initialized in `setup.ts` only exists in the original module instance. Without importing setup first, these split modules execute with empty state.
66
+
67
+ The fix in `@decocms/start` uses `globalThis.__deco` to share state across all module instances. But `setup.ts` must run BEFORE any server function is called — which means it must be imported before `createStartHandler` or `createServerEntry`.
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: deco-typescript-fixes
3
+ description: Strategies and patterns for fixing TypeScript errors in deco.cx storefronts, especially after migrations or dependency updates.
4
+ ---
5
+
6
+ # Deco TypeScript Fixes
7
+
8
+ This skill provides strategies for systematically fixing TypeScript errors in deco.cx storefronts. It's especially useful after:
9
+ - Migrating from forked apps to official `deco-cx/apps`
10
+ - Updating `@deco/deco` or `@deco/dev` versions
11
+ - Adding stricter TypeScript settings
12
+
13
+ ## When to Use This Skill
14
+
15
+ - User asks to "fix all type errors" or "make deno check pass"
16
+ - After a migration that introduces many TypeScript errors
17
+ - When enabling stricter type checking in a deco project
18
+
19
+ ## Critical: Use Fast Type Checker
20
+
21
+ Standard `deno check` takes 30-60+ seconds. With 200+ errors, iterating is painful.
22
+
23
+ **Always use the fast TSGo checker (Deno 2.1+, ideally 2.6+):**
24
+
25
+ ```bash
26
+ # FAST (~3-5s) - ALWAYS use this
27
+ deno check --unstable-tsgo --allow-import main.ts
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ 1. Run `deno check --unstable-tsgo --allow-import main.ts` to get the full error list
33
+ 2. Count errors: `deno check --unstable-tsgo --allow-import main.ts 2>&1 | grep -c "error:"`
34
+ 3. Categorize errors (see Common Error Categories below)
35
+ 4. Fix in batches by category, committing after each batch
36
+ 5. Repeat until zero errors
37
+
38
+ ## Files in This Skill
39
+
40
+ | File | Purpose |
41
+ |------|---------|
42
+ | `SKILL.md` | This overview and quick reference |
43
+ | `common-fixes.md` | Detailed patterns and code examples |
44
+ | `strategy.md` | The incremental fixing strategy |
45
+
46
+ ## Common Error Categories
47
+
48
+ ### 1. Missing Props Exports (Deco Compatibility)
49
+
50
+ **Symptom**: Deco admin can't load the component/section properly
51
+
52
+ **Pattern**: All components used as deco blocks need an exported `Props` type/interface
53
+
54
+ ```typescript
55
+ // BEFORE - Props not exported
56
+ interface Props {
57
+ title: string;
58
+ }
59
+
60
+ // AFTER - Export the Props
61
+ export interface Props {
62
+ title: string;
63
+ }
64
+ ```
65
+
66
+ ### 2. Global Type Declarations (Third-Party Scripts)
67
+
68
+ **Symptom**: `Cannot find name 'AnalyticsQueue'` or similar for injected globals
69
+
70
+ **Pattern**: Declare globals in `types/global.d.ts`
71
+
72
+ ```typescript
73
+ // types/global.d.ts
74
+ declare global {
75
+ // deno-lint-ignore no-var
76
+ var AnalyticsQueue: AnalyticsCommand[];
77
+ // deno-lint-ignore no-var
78
+ var dataLayer: unknown[];
79
+ // deno-lint-ignore no-var
80
+ var thirdPartyTracker: TrackerFn;
81
+ }
82
+ ```
83
+
84
+ ### 3. Possibly Undefined Values
85
+
86
+ **Symptom**: `Object is possibly 'undefined'`
87
+
88
+ **Pattern**: Use optional chaining or nullish coalescing
89
+
90
+ ```typescript
91
+ // BEFORE
92
+ const name = product.name.toLowerCase();
93
+
94
+ // AFTER - optional chaining + fallback
95
+ const name = product?.name?.toLowerCase() ?? "";
96
+
97
+ // AFTER - nullish coalescing for defaults
98
+ const quantity = item.quantity ?? 1;
99
+ ```
100
+
101
+ ### 4. External API Type Mismatches
102
+
103
+ **Symptom**: VTEX/external API returns different shape than expected types
104
+
105
+ **Pattern**: Create custom types for API responses, use type assertions with comments
106
+
107
+ ```typescript
108
+ // Create specific types for GraphQL responses
109
+ // types/myorders.ts
110
+ export interface LogisticsInfo {
111
+ deliveryChannel?: string;
112
+ shippingEstimateDate?: string;
113
+ }
114
+
115
+ // Use type assertion when SDK types don't match reality
116
+ const order = data as unknown as VtexOrderData;
117
+ ```
118
+
119
+ ### 5. Platform Import Cleanup
120
+
121
+ **Symptom**: Imports from removed platforms (Linx, Wake, etc.) fail
122
+
123
+ **Pattern**: Search and remove unused platform code entirely
124
+
125
+ ```bash
126
+ # Find all platform-specific files
127
+ find . -name "*linx*" -o -name "*wake*" -o -name "*vnda*"
128
+
129
+ # Remove them if not using those platforms
130
+ ```
131
+
132
+ ### 6. Optional Props Without Defaults
133
+
134
+ **Symptom**: `Type 'undefined' is not assignable to type 'string'`
135
+
136
+ **Pattern**: Make props explicitly optional or provide defaults
137
+
138
+ ```typescript
139
+ // BEFORE
140
+ interface Props {
141
+ href: string;
142
+ }
143
+
144
+ // AFTER - make optional with fallback in usage
145
+ export interface Props {
146
+ href?: string;
147
+ }
148
+
149
+ // In component:
150
+ const link = href ?? "#";
151
+ ```
152
+
153
+ ## Strategy Summary
154
+
155
+ 1. **Batch by category** - Fix all "possibly undefined" errors together, all "Props exports" together
156
+ 2. **Commit frequently** - Small commits let you track progress and rollback if needed
157
+ 3. **Document type assertions** - When using `as unknown as X`, add a comment explaining why
158
+ 4. **Create custom types** - Better to have explicit custom types than to silence errors
159
+ 5. **Check deco admin** - After fixes, verify blocks still load in the deco admin
160
+
161
+ ## Related Commands
162
+
163
+ ```bash
164
+ # Fast type check (use this for iteration)
165
+ deno check --unstable-tsgo --allow-import main.ts
166
+
167
+ # Count errors
168
+ deno check --unstable-tsgo --allow-import main.ts 2>&1 | grep -c "error:"
169
+
170
+ # Find errors by category
171
+ deno check --unstable-tsgo --allow-import main.ts 2>&1 | grep "possibly 'undefined'"
172
+ deno check --unstable-tsgo --allow-import main.ts 2>&1 | grep "Cannot find name"
173
+ deno check --unstable-tsgo --allow-import main.ts 2>&1 | grep "not assignable"
174
+
175
+ # Find files with most errors
176
+ deno check --unstable-tsgo --allow-import main.ts 2>&1 | grep "error:" | \
177
+ sed 's/:.*//g' | sort | uniq -c | sort -rn | head -20
178
+ ```