@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.
- package/.agents/skills/deco-to-tanstack-migration/SKILL.md +1 -0
- package/.agents/skills/deco-to-tanstack-migration/references/post-migration-cleanup.md +163 -0
- package/.agents/skills/deco-to-tanstack-migration/references/vite-config/README.md +27 -2
- package/.agents/skills/deco-to-tanstack-migration/templates/vite-config.md +143 -68
- package/.cursor/skills/deco-to-tanstack-migration/SKILL.md +1 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/post-migration-cleanup.md +163 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/vite-config/README.md +27 -2
- package/.cursor/skills/deco-to-tanstack-migration/templates/vite-config.md +143 -68
- package/package.json +1 -1
- package/scripts/deco-migrate-cli.ts +1 -1
- package/scripts/migrate/analyzers/island-classifier.ts +2 -2
- package/scripts/migrate/analyzers/loader-inventory.ts +2 -2
- package/scripts/migrate/analyzers/section-metadata.ts +2 -2
- package/scripts/migrate/analyzers/theme-extractor.ts +2 -2
- package/scripts/migrate/phase-analyze.ts +6 -6
- package/scripts/migrate/phase-cleanup.test.ts +141 -0
- package/scripts/migrate/phase-cleanup.ts +134 -35
- package/scripts/migrate/phase-report.ts +2 -2
- package/scripts/migrate/phase-scaffold.ts +26 -22
- package/scripts/migrate/phase-transform.ts +9 -9
- package/scripts/migrate/phase-verify.ts +2 -2
- package/scripts/migrate/templates/app-css.ts +2 -2
- package/scripts/migrate/templates/cache-config.ts +1 -1
- package/scripts/migrate/templates/commerce-loaders.ts +1 -1
- package/scripts/migrate/templates/hooks.ts +1 -1
- package/scripts/migrate/templates/lib-utils.test.ts +91 -0
- package/scripts/migrate/templates/lib-utils.ts +51 -19
- package/scripts/migrate/templates/package-json.ts +1 -1
- package/scripts/migrate/templates/routes.ts +1 -1
- package/scripts/migrate/templates/sdk-gen.ts +1 -1
- package/scripts/migrate/templates/section-loaders.ts +1 -1
- package/scripts/migrate/templates/server-entry.ts +1 -1
- package/scripts/migrate/templates/setup.ts +1 -1
- package/scripts/migrate/templates/types-gen.ts +1 -1
- package/scripts/migrate/templates/ui-components.ts +1 -1
- package/scripts/migrate/templates/vite-config.ts +1 -1
- package/scripts/migrate/templates/wrangler.ts +1 -1
- package/scripts/migrate/transforms/dead-code.ts +1 -1
- package/scripts/migrate/transforms/deno-isms.ts +1 -1
- package/scripts/migrate/transforms/fresh-apis.ts +1 -1
- package/scripts/migrate/transforms/imports.ts +1 -1
- package/scripts/migrate/transforms/jsx.ts +1 -1
- package/scripts/migrate/transforms/section-conventions.ts +1 -1
- package/scripts/migrate/transforms/tailwind.ts +1 -1
- package/scripts/migrate.ts +8 -8
- package/src/cms/sectionLoaders.test.ts +4 -1
- package/src/vite/plugin.js +47 -10
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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:
|
|
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.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|