@decocms/start 2.4.2 → 2.6.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 (48) hide show
  1. package/.agents/skills/deco-to-tanstack-migration/SKILL.md +1 -0
  2. package/.agents/skills/deco-to-tanstack-migration/references/post-migration-cleanup.md +163 -0
  3. package/.agents/skills/deco-to-tanstack-migration/references/vite-config/README.md +27 -2
  4. package/.agents/skills/deco-to-tanstack-migration/templates/vite-config.md +143 -68
  5. package/.cursor/skills/deco-to-tanstack-migration/SKILL.md +1 -0
  6. package/.cursor/skills/deco-to-tanstack-migration/references/post-migration-cleanup.md +163 -0
  7. package/.cursor/skills/deco-to-tanstack-migration/references/vite-config/README.md +27 -2
  8. package/.cursor/skills/deco-to-tanstack-migration/templates/vite-config.md +143 -68
  9. package/package.json +1 -1
  10. package/scripts/deco-migrate-cli.ts +1 -1
  11. package/scripts/migrate/analyzers/island-classifier.ts +2 -2
  12. package/scripts/migrate/analyzers/loader-inventory.ts +2 -2
  13. package/scripts/migrate/analyzers/section-metadata.ts +2 -2
  14. package/scripts/migrate/analyzers/theme-extractor.ts +2 -2
  15. package/scripts/migrate/phase-analyze.ts +6 -6
  16. package/scripts/migrate/phase-cleanup.test.ts +141 -0
  17. package/scripts/migrate/phase-cleanup.ts +134 -35
  18. package/scripts/migrate/phase-report.ts +2 -2
  19. package/scripts/migrate/phase-scaffold.ts +26 -22
  20. package/scripts/migrate/phase-transform.ts +9 -9
  21. package/scripts/migrate/phase-verify.ts +2 -2
  22. package/scripts/migrate/templates/app-css.ts +2 -2
  23. package/scripts/migrate/templates/cache-config.ts +1 -1
  24. package/scripts/migrate/templates/commerce-loaders.ts +1 -1
  25. package/scripts/migrate/templates/hooks.ts +1 -1
  26. package/scripts/migrate/templates/lib-utils.test.ts +91 -0
  27. package/scripts/migrate/templates/lib-utils.ts +51 -19
  28. package/scripts/migrate/templates/package-json.ts +1 -1
  29. package/scripts/migrate/templates/routes.ts +1 -1
  30. package/scripts/migrate/templates/sdk-gen.ts +1 -1
  31. package/scripts/migrate/templates/section-loaders.ts +1 -1
  32. package/scripts/migrate/templates/server-entry.ts +1 -1
  33. package/scripts/migrate/templates/setup.ts +1 -1
  34. package/scripts/migrate/templates/types-gen.ts +1 -1
  35. package/scripts/migrate/templates/ui-components.ts +1 -1
  36. package/scripts/migrate/templates/vite-config.ts +1 -1
  37. package/scripts/migrate/templates/wrangler.ts +1 -1
  38. package/scripts/migrate/transforms/dead-code.ts +1 -1
  39. package/scripts/migrate/transforms/deno-isms.ts +1 -1
  40. package/scripts/migrate/transforms/fresh-apis.ts +1 -1
  41. package/scripts/migrate/transforms/imports.ts +1 -1
  42. package/scripts/migrate/transforms/jsx.ts +1 -1
  43. package/scripts/migrate/transforms/section-conventions.ts +1 -1
  44. package/scripts/migrate/transforms/tailwind.ts +1 -1
  45. package/scripts/migrate.ts +8 -8
  46. package/src/cms/sectionLoaders.test.ts +4 -1
  47. package/src/vite/plugin.js +47 -10
  48. package/vitest.config.ts +11 -1
@@ -368,6 +368,7 @@ For sites with 100+ sections:
368
368
  | Runtime storefront patterns | `references/storefront-patterns.md` |
369
369
  | Admin / CMS integration | `references/admin-cms.md` |
370
370
  | Gotchas index | `references/gotchas.md` |
371
+ | Post-migration cleanup checklist | `references/post-migration-cleanup.md` |
371
372
  | React hooks patterns | `references/react-hooks-patterns.md` |
372
373
  | React signals & state | `references/react-signals-state.md` |
373
374
  | JSX migration differences | `references/jsx-migration.md` |
@@ -0,0 +1,163 @@
1
+ # Post-Migration Cleanup
2
+
3
+ After the migration script runs and the site builds + boots, there's a
4
+ recurring set of dead-code and boilerplate cleanup that every migrated
5
+ site benefits from. Run this checklist before the first PR review, not
6
+ after the site has been shipping for weeks.
7
+
8
+ ## 1. Delete unused `src/lib/*` shims
9
+
10
+ The migration script's `templates/lib-utils.ts` generates 11 shim files
11
+ under `src/lib/`. Most of them are NO-OP stubs intended as defensive
12
+ bridges for signature mismatches. In practice many sites use zero of them
13
+ because their loaders import directly from `@decocms/apps/vtex/utils/*`.
14
+
15
+ ### How to detect
16
+
17
+ ```bash
18
+ # From repo root.
19
+ for f in src/lib/*.ts; do
20
+ base=$(basename "$f" .ts)
21
+ symbols=$(grep -oE "^export (function|const|interface|type|class) [A-Za-z_][A-Za-z0-9_]*" "$f" | awk '{print $NF}')
22
+ for s in $symbols; do
23
+ # Search for the symbol anywhere in src/ outside src/lib/
24
+ hits=$(rg -l "\\b$s\\b" src/ --type ts --type tsx -g '!src/lib/**')
25
+ if [ -z "$hits" ]; then
26
+ echo "DEAD: $f exports $s with zero external imports"
27
+ fi
28
+ done
29
+ done
30
+ ```
31
+
32
+ If every export in a file is dead, delete the file. If `src/lib/` ends
33
+ up empty, delete the directory too.
34
+
35
+ ### Real-world data
36
+
37
+ | Site | Files generated | Files used |
38
+ |------|-----------------|-----------|
39
+ | baggagio-tanstack | 11 | 0 (all dead) |
40
+ | casaevideo-storefront | 11 | 1 (wrapped manually) |
41
+
42
+ The files that tend to be dead in every site:
43
+
44
+ - `vtex-client.ts` — type-only export, sites usually grab it from `@decocms/apps`
45
+ - `vtex-fetch.ts` — `fetchSafe` wrapper, supplanted by `@decocms/apps/vtex/utils/fetch`
46
+ - `vtex-id.ts` — manual `parseCookie`, usually shadowed by `~/sdk/orderForm`'s real one
47
+ - `vtex-segment.ts` — NO-OP stubs returning empty; never useful
48
+ - `vtex-intelligent-search.ts` — stubs returning `{}`; supplanted by apps
49
+ - `vtex-transform.ts` — re-exports from `@decocms/apps/vtex/utils/transform` directly
50
+ - `vtex-send-event.ts` — claims to mirror an unreleased apps export; almost never imported
51
+
52
+ The files that occasionally stay used:
53
+
54
+ - `http-utils.ts` — `createHttpClient` proxy bridge for sites with custom
55
+ HTTP clients
56
+ - `graphql-utils.ts` — same shape for GraphQL
57
+ - `fetch-utils.ts` — single `STALE` cache header constant (very small)
58
+ - `filter-navigate.ts` — VTEX filter URL string transformer
59
+
60
+ If `apps/utils/*` imports never appear in your Fresh source, ALL FOUR of
61
+ the latter are also dead.
62
+
63
+ ## 2. Drop inline vite plugins that are now framework-provided
64
+
65
+ Two plugins that older site templates inline are obsolete on
66
+ `@decocms/start >= 2.5.0`:
67
+
68
+ ```ts
69
+ // site-manual-chunks — overrides framework default chunking
70
+ { name: "site-manual-chunks", config(_cfg, { command }) { ... ~25 lines ... } }
71
+
72
+ // deco-stub-meta-gen — stubs admin schema on client
73
+ { name: "deco-stub-meta-gen", enforce: "pre", resolveId(...), load(...) }
74
+ ```
75
+
76
+ The framework's `decoVitePlugin()` now handles both:
77
+ - `manualChunks` no longer splits `@decocms/start` / `@decocms/apps` (the
78
+ old split caused circular-dep load-order crashes — every site overrode it)
79
+ - `meta.gen.{json,ts}` is stubbed on the client by default
80
+
81
+ Delete both inline plugins from the site's `vite.config.ts`. Verify the
82
+ production build still succeeds (`vite build` in the site repo).
83
+
84
+ ## 3. Drop the `runtime.ts` `invoke` shim
85
+
86
+ Older migrations create `src/runtime.ts` with a manual `createNestedInvokeProxy`
87
+ implementation (~45 lines). The framework's `@decocms/start/sdk` now exports
88
+ both `invoke` (default singleton) and `createAppInvoke` (for typed app-scoped
89
+ proxies). Replace the file with a re-export, or delete it and update import
90
+ sites:
91
+
92
+ ```diff
93
+ - import { invoke } from "~/runtime";
94
+ + import { invoke } from "@decocms/start/sdk";
95
+ ```
96
+
97
+ If `~/runtime` was only used for `invoke`, delete the file entirely. If
98
+ it had additional helpers, keep it but trim it down to those.
99
+
100
+ ## 4. Drop site-local `withSiteGlobals` workaround
101
+
102
+ If your site's `cmsRouteConfig` has a `cmsRouteWithGlobals` wrapper that
103
+ manually merges `site.global` sections into the page sections list,
104
+ delete it and use `@decocms/start/routes`'s opt-in helper:
105
+
106
+ ```ts
107
+ import { cmsRouteConfig, withSiteGlobals } from "@decocms/start/routes";
108
+
109
+ export const Route = createFileRoute(...)({
110
+ ...cmsRouteConfig({
111
+ ...withSiteGlobals,
112
+ // your route options
113
+ }),
114
+ });
115
+ ```
116
+
117
+ The site-side wrapper is typically ~390 LOC; the framework helper is
118
+ opt-in and tested.
119
+
120
+ ## 5. Verify `vtex-* shim regression` is not still happening
121
+
122
+ Older versions of the migration script's `phase-cleanup` had a bug where
123
+ it actively rewrote valid `@decocms/apps/vtex/utils/*` and
124
+ `@decocms/apps/vtex/client` imports back to the dead `~/lib/vtex-*` shims.
125
+ Confirm your loaders import direct from `@decocms/apps`:
126
+
127
+ ```bash
128
+ rg "from ['\"]~/lib/vtex-" src/
129
+ # Expected: 0 hits (or only site-specific reasons you can articulate)
130
+ ```
131
+
132
+ If you see hits, update the imports to point at `@decocms/apps/vtex/...`
133
+ directly (or the corresponding `commerce/utils/*` if it's a generic
134
+ utility). Your runtime behavior gets MUCH better — segment cookies, IS
135
+ cookies, VTEX session auth all start working again instead of being
136
+ silently stubbed to `{}` / `null`.
137
+
138
+ ## 6. Search for orphan `TODO: move into framework` comments
139
+
140
+ Real sites accumulate `TODO` comments like `// TODO: move into decoVitePlugin
141
+ in next @decocms/start release`. These are roadmap items the framework
142
+ team should pick up, but they often go stale.
143
+
144
+ ```bash
145
+ rg -n "TODO.*deco|TODO.*framework|TODO.*move into" src/ vite.config.ts
146
+ ```
147
+
148
+ For each hit, decide:
149
+ - Has the framework feature shipped? → migrate to it now and delete the comment
150
+ - Is it deferred indefinitely? → file a tracking issue and link from the comment
151
+ - Is it obsolete? → delete the comment
152
+
153
+ ## Verification checklist
154
+
155
+ After completing 1-6:
156
+
157
+ - [ ] `npm run typecheck` baseline matches pre-cleanup count (no new errors)
158
+ - [ ] `npm run dev` starts and `/`, `/some-pdp/p`, `/s?q=foo` all render
159
+ - [ ] `npm run build` succeeds with no chunk-load crashes
160
+ - [ ] Smoke a logged-in PDP to confirm session cookies and segment auth
161
+ work (this is what the `~/lib/vtex-*` regression silently broke)
162
+ - [ ] `git diff --stat` shows only deletions or framework-helper substitutions
163
+ — no new site-local logic added
@@ -1,12 +1,18 @@
1
1
  # Vite Configuration
2
2
 
3
- ## Final Config (Post-Migration)
3
+ For the canonical battle-tested template (with VTEX dev proxy, CSP headers,
4
+ React Compiler, dedupe, framework plugin, and rollup chunk strategy) see
5
+ [`../../templates/vite-config.md`](../../templates/vite-config.md).
4
6
 
5
- After all imports are rewritten, the config should be minimal:
7
+ This page covers the post-migration **minimum viable config** if you've
8
+ stripped everything optional. Real sites should use the full template.
9
+
10
+ ## Minimum Viable Config
6
11
 
7
12
  ```typescript
8
13
  import { cloudflare } from "@cloudflare/vite-plugin";
9
14
  import { tanstackStart } from "@tanstack/react-start/plugin/vite";
15
+ import { decoVitePlugin } from "@decocms/start/vite";
10
16
  import react from "@vitejs/plugin-react";
11
17
  import tailwindcss from "@tailwindcss/vite";
12
18
  import { defineConfig } from "vite";
@@ -24,8 +30,23 @@ export default defineConfig({
24
30
  },
25
31
  }),
26
32
  tailwindcss(),
33
+ // Required — server-only stubs, blocks.gen.ts fast-path, meta.gen
34
+ // client stub, daemon/tunnel for dev mode. Without this, client
35
+ // bundle crashes on node:async_hooks / react-dom/server transitively
36
+ // imported by @decocms/start.
37
+ decoVitePlugin(),
27
38
  ],
28
39
  resolve: {
40
+ // Required — dedupe React/TanStack/Deco packages so there's only one
41
+ // instance of each. Without this you get "Invalid hook call" errors.
42
+ dedupe: [
43
+ "@decocms/start",
44
+ "@decocms/apps",
45
+ "@tanstack/react-start",
46
+ "@tanstack/react-router",
47
+ "react",
48
+ "react-dom",
49
+ ],
29
50
  alias: {
30
51
  "~": srcDir,
31
52
  },
@@ -35,6 +56,10 @@ export default defineConfig({
35
56
 
36
57
  **One alias only**: `~` -> `src/`. Nothing else.
37
58
 
59
+ The `decoVitePlugin()` call is **mandatory** — the older skill examples
60
+ that omitted it (or inlined the stub logic) reflect the pre-2.x state of
61
+ `@decocms/start` and will produce build/runtime failures on current versions.
62
+
38
63
  ## tsconfig.json
39
64
 
40
65
  Must mirror the Vite alias:
@@ -1,10 +1,13 @@
1
1
  # vite.config.ts Template
2
2
 
3
- Battle-tested configuration from espacosmart-storefront.
3
+ Battle-tested configuration. Uses the framework's `decoVitePlugin()` for the
4
+ server-only stub layer (rather than re-implementing it inline like older
5
+ sites did).
4
6
 
5
7
  ```typescript
6
8
  import { cloudflare } from "@cloudflare/vite-plugin";
7
9
  import { tanstackStart } from "@tanstack/react-start/plugin/vite";
10
+ import { decoVitePlugin } from "@decocms/start/vite";
8
11
  import react from "@vitejs/plugin-react";
9
12
  import tailwindcss from "@tailwindcss/vite";
10
13
  import { defineConfig } from "vite";
@@ -12,90 +15,86 @@ import path from "path";
12
15
 
13
16
  const srcDir = path.resolve(__dirname, "src");
14
17
 
18
+ // VTEX dev proxy — adjust to your account / commerce backend.
19
+ const VTEX_ACCOUNT = process.env.VTEX_ACCOUNT || "mystore";
20
+ const VTEX_ORIGIN = `https://${VTEX_ACCOUNT}.vtexcommercestable.com.br`;
21
+
15
22
  export default defineConfig({
23
+ server: {
24
+ port: parseInt(process.env.PORT ?? "5173", 10),
25
+ // When the deco daemon injects PORT, bind to all interfaces so Deno's
26
+ // TCP connect (127.0.0.1) can reach Vite regardless of IPv4/IPv6.
27
+ host: process.env.PORT ? "0.0.0.0" : undefined,
28
+ headers: {
29
+ // Allow embedding in iframes from trusted admin origins.
30
+ "Content-Security-Policy":
31
+ "frame-ancestors 'self' https://*.deco.studio http://localhost:* https://localhost:* https://admin.deco.cx https://studio.decocms.com",
32
+ },
33
+ proxy: {
34
+ "/api/": {
35
+ target: VTEX_ORIGIN,
36
+ changeOrigin: true,
37
+ cookieDomainRewrite: { "*": "" },
38
+ },
39
+ "/checkout": {
40
+ target: VTEX_ORIGIN,
41
+ changeOrigin: true,
42
+ cookieDomainRewrite: { "*": "" },
43
+ },
44
+ },
45
+ },
16
46
  plugins: [
17
47
  cloudflare({ viteEnvironment: { name: "ssr" } }),
18
48
  tanstackStart({ server: { entry: "server" } }),
19
49
  react({
20
50
  babel: {
21
- plugins: [
22
- ["babel-plugin-react-compiler", { target: "19" }],
23
- ],
51
+ plugins: [["babel-plugin-react-compiler", { target: "19" }]],
24
52
  },
25
53
  }),
26
54
  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;";
55
+ // Framework plugin provides server-only stubs (react-dom/server,
56
+ // node:async_hooks, etc.), blocks.gen.ts JSON-fast-path, meta.gen
57
+ // client stub, daemon/tunnel for dev mode, and correct manualChunks
58
+ // (NOT splitting @decocms/start / @decocms/apps which have circular
59
+ // re-exports). Replaces ~80 lines of boilerplate that older sites
60
+ // had inline.
61
+ decoVitePlugin(),
62
+ ],
63
+ build: {
64
+ sourcemap: "hidden",
65
+ rollupOptions: {
66
+ onLog(level, log, handler) {
67
+ // Silence harmless "dynamic import will not move module" warning
68
+ // emitted when a module is imported both statically and dynamically.
69
+ if (
70
+ log.code === "PLUGIN_WARNING" &&
71
+ log.plugin === "vite:reporter" &&
72
+ log.message?.includes("dynamic import will not move module")
73
+ ) {
74
+ return;
82
75
  }
76
+ handler(level, log);
83
77
  },
84
78
  },
85
- ],
86
- // Inject site name at build time (not runtime)
79
+ },
87
80
  define: {
81
+ // Inject site name at build time, not read at runtime.
88
82
  "process.env.DECO_SITE_NAME": JSON.stringify(
89
- process.env.DECO_SITE_NAME || "my-store"
83
+ process.env.DECO_SITE_NAME || "my-store",
90
84
  ),
91
85
  },
92
86
  esbuild: {
93
87
  jsx: "automatic",
94
88
  jsxImportSource: "react",
89
+ // Strip console.log in production; keep .warn / .error for debugging.
90
+ pure: ["console.log"],
95
91
  },
96
92
  resolve: {
97
- // CRITICAL: Without dedupe, multiple React/TanStack instances cause hook errors
93
+ // CRITICAL: without dedupe, multiple React/TanStack instances cause
94
+ // "Invalid hook call" errors at runtime.
98
95
  dedupe: [
96
+ "@decocms/start",
97
+ "@decocms/apps",
99
98
  "@tanstack/react-start",
100
99
  "@tanstack/react-router",
101
100
  "@tanstack/react-start-server",
@@ -115,8 +114,84 @@ export default defineConfig({
115
114
 
116
115
  ## Key Points
117
116
 
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.
117
+ 1. **`decoVitePlugin()`** — Required. Replaces ~80 lines of inline boilerplate
118
+ that older sites had to copy. Provides:
119
+ - Client stubs for server-only modules (`react-dom/server`,
120
+ `node:async_hooks`, `node:stream`, etc.)
121
+ - `blocks.gen.ts` JSON fast-path (10-100x parse speedup for large registries)
122
+ - `meta.gen.{json,ts}` client stub (cuts admin schema 0.5-5MB out of
123
+ browser bundle)
124
+ - Daemon/tunnel for dev mode (when `DECO_SITE_NAME` env is set)
125
+ - Production `manualChunks` that does NOT split `@decocms/start` or
126
+ `@decocms/apps` (those have circular re-exports and crash when chunked
127
+ separately)
128
+ - `allowedHosts` for tunnel domains (`.deco.host`, `.decocdn.com`,
129
+ `.deco.studio`)
130
+ - JSX automatic / react import-source defaults
131
+
132
+ 2. **`resolve.dedupe`** — Required. Without it, multiple React instances
133
+ cause "Invalid hook call" errors. The list MUST include both
134
+ `@decocms/start` and `@decocms/apps` because they re-export TanStack
135
+ types and registry singletons.
136
+
137
+ 3. **`process.env.DECO_SITE_NAME` via `define`** — Must be injected at
138
+ build time, not read at runtime. Workers don't have a Node-style
139
+ `process.env` at runtime.
140
+
141
+ 4. **React Compiler** — `babel-plugin-react-compiler` with `target: "19"`
142
+ for automatic memoization. Requires `@vitejs/plugin-react`, not the
143
+ default SWC plugin.
144
+
145
+ 5. **`esbuild.jsx: "automatic"` with `jsxImportSource: "react"`** — Without
146
+ it, JSX falls back to `React.createElement` references that may not
147
+ resolve.
148
+
149
+ 6. **CSP `frame-ancestors`** — Required for the admin (`*.deco.studio`,
150
+ `admin.deco.cx`, `studio.decocms.com`) to embed previews in iframes.
151
+
152
+ 7. **VTEX dev proxy** — Local `/api/`, `/checkout` requests proxied to
153
+ the upstream commerce backend so cookie-based session works in dev
154
+ without CORS gymnastics.
155
+
156
+ ## What older site templates inline (and why this template doesn't)
157
+
158
+ Some older guides show two extra inline plugins:
159
+
160
+ ```ts
161
+ // site-manual-chunks — overrides framework default chunking
162
+ { name: "site-manual-chunks", config(_cfg, { command }) { ... } }
163
+
164
+ // deco-stub-meta-gen — stubs admin schema on client
165
+ { name: "deco-stub-meta-gen", enforce: "pre", resolveId(...), load(...) }
166
+ ```
167
+
168
+ Both are obsolete after `@decocms/start` >= 2.5.0:
169
+ - The framework's `manualChunks` no longer splits `@decocms/start` /
170
+ `@decocms/apps` (the old split caused circular-dep load-order crashes —
171
+ every site overrode it).
172
+ - The framework now stubs `meta.gen.{json,ts}` on the client by default.
173
+
174
+ If you're on an older version, keep the inline plugins until you can bump.
175
+
176
+ ## tsconfig.json (matches the Vite alias)
177
+
178
+ ```json
179
+ {
180
+ "compilerOptions": {
181
+ "jsx": "react-jsx",
182
+ "moduleResolution": "bundler",
183
+ "module": "ESNext",
184
+ "target": "ES2022",
185
+ "skipLibCheck": true,
186
+ "strictNullChecks": true,
187
+ "baseUrl": ".",
188
+ "paths": {
189
+ "~/*": ["./src/*"]
190
+ }
191
+ },
192
+ "include": ["src/**/*", "vite.config.ts"]
193
+ }
194
+ ```
195
+
196
+ No `$store/*`, `site/*`, `apps/*`, `preact`, `@preact/signals`,
197
+ `@deco/deco` paths. Those are all dead.
@@ -628,6 +628,7 @@ The conductor approach that worked (836 errors → 0 across 213 files) treated e
628
628
  | Admin schema composition | `src/admin/schema.ts` in `@decocms/start` |
629
629
  | Server functions (`createServerFn`) | `references/server-functions/` |
630
630
  | Common gotchas (45 items) | `references/gotchas.md` |
631
+ | Post-migration cleanup checklist | `references/post-migration-cleanup.md` |
631
632
  | setup.ts template | `templates/setup-ts.md` |
632
633
  | vite.config.ts template | `templates/vite-config.md` |
633
634
  | worker-entry template | `templates/worker-entry.md` |
@@ -0,0 +1,163 @@
1
+ # Post-Migration Cleanup
2
+
3
+ After the migration script runs and the site builds + boots, there's a
4
+ recurring set of dead-code and boilerplate cleanup that every migrated
5
+ site benefits from. Run this checklist before the first PR review, not
6
+ after the site has been shipping for weeks.
7
+
8
+ ## 1. Delete unused `src/lib/*` shims
9
+
10
+ The migration script's `templates/lib-utils.ts` generates 11 shim files
11
+ under `src/lib/`. Most of them are NO-OP stubs intended as defensive
12
+ bridges for signature mismatches. In practice many sites use zero of them
13
+ because their loaders import directly from `@decocms/apps/vtex/utils/*`.
14
+
15
+ ### How to detect
16
+
17
+ ```bash
18
+ # From repo root.
19
+ for f in src/lib/*.ts; do
20
+ base=$(basename "$f" .ts)
21
+ symbols=$(grep -oE "^export (function|const|interface|type|class) [A-Za-z_][A-Za-z0-9_]*" "$f" | awk '{print $NF}')
22
+ for s in $symbols; do
23
+ # Search for the symbol anywhere in src/ outside src/lib/
24
+ hits=$(rg -l "\\b$s\\b" src/ --type ts --type tsx -g '!src/lib/**')
25
+ if [ -z "$hits" ]; then
26
+ echo "DEAD: $f exports $s with zero external imports"
27
+ fi
28
+ done
29
+ done
30
+ ```
31
+
32
+ If every export in a file is dead, delete the file. If `src/lib/` ends
33
+ up empty, delete the directory too.
34
+
35
+ ### Real-world data
36
+
37
+ | Site | Files generated | Files used |
38
+ |------|-----------------|-----------|
39
+ | baggagio-tanstack | 11 | 0 (all dead) |
40
+ | casaevideo-storefront | 11 | 1 (wrapped manually) |
41
+
42
+ The files that tend to be dead in every site:
43
+
44
+ - `vtex-client.ts` — type-only export, sites usually grab it from `@decocms/apps`
45
+ - `vtex-fetch.ts` — `fetchSafe` wrapper, supplanted by `@decocms/apps/vtex/utils/fetch`
46
+ - `vtex-id.ts` — manual `parseCookie`, usually shadowed by `~/sdk/orderForm`'s real one
47
+ - `vtex-segment.ts` — NO-OP stubs returning empty; never useful
48
+ - `vtex-intelligent-search.ts` — stubs returning `{}`; supplanted by apps
49
+ - `vtex-transform.ts` — re-exports from `@decocms/apps/vtex/utils/transform` directly
50
+ - `vtex-send-event.ts` — claims to mirror an unreleased apps export; almost never imported
51
+
52
+ The files that occasionally stay used:
53
+
54
+ - `http-utils.ts` — `createHttpClient` proxy bridge for sites with custom
55
+ HTTP clients
56
+ - `graphql-utils.ts` — same shape for GraphQL
57
+ - `fetch-utils.ts` — single `STALE` cache header constant (very small)
58
+ - `filter-navigate.ts` — VTEX filter URL string transformer
59
+
60
+ If `apps/utils/*` imports never appear in your Fresh source, ALL FOUR of
61
+ the latter are also dead.
62
+
63
+ ## 2. Drop inline vite plugins that are now framework-provided
64
+
65
+ Two plugins that older site templates inline are obsolete on
66
+ `@decocms/start >= 2.5.0`:
67
+
68
+ ```ts
69
+ // site-manual-chunks — overrides framework default chunking
70
+ { name: "site-manual-chunks", config(_cfg, { command }) { ... ~25 lines ... } }
71
+
72
+ // deco-stub-meta-gen — stubs admin schema on client
73
+ { name: "deco-stub-meta-gen", enforce: "pre", resolveId(...), load(...) }
74
+ ```
75
+
76
+ The framework's `decoVitePlugin()` now handles both:
77
+ - `manualChunks` no longer splits `@decocms/start` / `@decocms/apps` (the
78
+ old split caused circular-dep load-order crashes — every site overrode it)
79
+ - `meta.gen.{json,ts}` is stubbed on the client by default
80
+
81
+ Delete both inline plugins from the site's `vite.config.ts`. Verify the
82
+ production build still succeeds (`vite build` in the site repo).
83
+
84
+ ## 3. Drop the `runtime.ts` `invoke` shim
85
+
86
+ Older migrations create `src/runtime.ts` with a manual `createNestedInvokeProxy`
87
+ implementation (~45 lines). The framework's `@decocms/start/sdk` now exports
88
+ both `invoke` (default singleton) and `createAppInvoke` (for typed app-scoped
89
+ proxies). Replace the file with a re-export, or delete it and update import
90
+ sites:
91
+
92
+ ```diff
93
+ - import { invoke } from "~/runtime";
94
+ + import { invoke } from "@decocms/start/sdk";
95
+ ```
96
+
97
+ If `~/runtime` was only used for `invoke`, delete the file entirely. If
98
+ it had additional helpers, keep it but trim it down to those.
99
+
100
+ ## 4. Drop site-local `withSiteGlobals` workaround
101
+
102
+ If your site's `cmsRouteConfig` has a `cmsRouteWithGlobals` wrapper that
103
+ manually merges `site.global` sections into the page sections list,
104
+ delete it and use `@decocms/start/routes`'s opt-in helper:
105
+
106
+ ```ts
107
+ import { cmsRouteConfig, withSiteGlobals } from "@decocms/start/routes";
108
+
109
+ export const Route = createFileRoute(...)({
110
+ ...cmsRouteConfig({
111
+ ...withSiteGlobals,
112
+ // your route options
113
+ }),
114
+ });
115
+ ```
116
+
117
+ The site-side wrapper is typically ~390 LOC; the framework helper is
118
+ opt-in and tested.
119
+
120
+ ## 5. Verify `vtex-* shim regression` is not still happening
121
+
122
+ Older versions of the migration script's `phase-cleanup` had a bug where
123
+ it actively rewrote valid `@decocms/apps/vtex/utils/*` and
124
+ `@decocms/apps/vtex/client` imports back to the dead `~/lib/vtex-*` shims.
125
+ Confirm your loaders import direct from `@decocms/apps`:
126
+
127
+ ```bash
128
+ rg "from ['\"]~/lib/vtex-" src/
129
+ # Expected: 0 hits (or only site-specific reasons you can articulate)
130
+ ```
131
+
132
+ If you see hits, update the imports to point at `@decocms/apps/vtex/...`
133
+ directly (or the corresponding `commerce/utils/*` if it's a generic
134
+ utility). Your runtime behavior gets MUCH better — segment cookies, IS
135
+ cookies, VTEX session auth all start working again instead of being
136
+ silently stubbed to `{}` / `null`.
137
+
138
+ ## 6. Search for orphan `TODO: move into framework` comments
139
+
140
+ Real sites accumulate `TODO` comments like `// TODO: move into decoVitePlugin
141
+ in next @decocms/start release`. These are roadmap items the framework
142
+ team should pick up, but they often go stale.
143
+
144
+ ```bash
145
+ rg -n "TODO.*deco|TODO.*framework|TODO.*move into" src/ vite.config.ts
146
+ ```
147
+
148
+ For each hit, decide:
149
+ - Has the framework feature shipped? → migrate to it now and delete the comment
150
+ - Is it deferred indefinitely? → file a tracking issue and link from the comment
151
+ - Is it obsolete? → delete the comment
152
+
153
+ ## Verification checklist
154
+
155
+ After completing 1-6:
156
+
157
+ - [ ] `npm run typecheck` baseline matches pre-cleanup count (no new errors)
158
+ - [ ] `npm run dev` starts and `/`, `/some-pdp/p`, `/s?q=foo` all render
159
+ - [ ] `npm run build` succeeds with no chunk-load crashes
160
+ - [ ] Smoke a logged-in PDP to confirm session cookies and segment auth
161
+ work (this is what the `~/lib/vtex-*` regression silently broke)
162
+ - [ ] `git diff --stat` shows only deletions or framework-helper substitutions
163
+ — no new site-local logic added