Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ skill, not the row.

| Skill | What it covers |
|---|---|
| [`deco-v7-to-v8-migration/`](deco-v7-to-v8-migration/SKILL.md) | @decocms/blocks 8 (the next major): moves a v7 Deco site (@decocms/blocks 7.x with @decocms/tanstack or @decocms/nextjs, @decocms/blocks-admin, @decocms/blocks-cli, v7 @decocms/apps-*) onto @decocms/blocks 8 and the thin @decocms/apps-* clients. Runs the one-time migration script (scripts/main.ts: block map with legacy aliases, vendored app loaders, content in .deco/blocks, secret re-encryption, import report), then guides the manual work it reports. Use when a site's package.json depends on @decocms/blocks ^7, @decocms/tanstack, @decocms/nextjs or @decocms/blocks-admin and should move to v8; when the report lists /deco/invoke calls, createDecoWorkerEntry, RequestContext, useCart or other v7 imports to replace; when deco check rejects migrated content; or when a migrated page, draft preview, editor form or parity run differs from v7. Replaces the unpublished @decocms/blocks-migrate package. |
| [`deco-v7-to-v8-migration/`](deco-v7-to-v8-migration/SKILL.md) | @decocms/blocks 8 (the next major): moves a v7 Deco site (@decocms/blocks 7.x with @decocms/tanstack or @decocms/nextjs, @decocms/blocks-admin, @decocms/blocks-cli, v7 @decocms/apps-*) onto @decocms/blocks 8, the v8 bindings (@decocms/tanstack 8, @decocms/nextjs 8) and the thin @decocms/apps-* clients. Runs the one-time migration script (scripts/main.ts: block map with legacy aliases, vendored app loaders, content in .deco/blocks, secret re-encryption, import report), then guides the manual work it reports. Use when a site's package.json depends on @decocms/blocks ^7, @decocms/tanstack, @decocms/nextjs or @decocms/blocks-admin and should move to v8; when the report lists /deco/invoke calls, createDecoWorkerEntry, RequestContext, useCart or other v7 imports to replace; when deco check rejects migrated content; or when a migrated page, draft preview, editor form or parity run differs from v7. Replaces the unpublished @decocms/blocks-migrate package. |

_1 skill(s). This table is generated by `scripts/skills-readme.ts` — edit the skill, not the row._
<!-- skills:end -->
29 changes: 15 additions & 14 deletions .agents/skills/deco-v7-to-v8-migration/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
name: deco-v7-to-v8-migration
description: "@decocms/blocks 8 (the next major): moves a v7 Deco site (@decocms/blocks 7.x with @decocms/tanstack or @decocms/nextjs, @decocms/blocks-admin, @decocms/blocks-cli, v7 @decocms/apps-*) onto @decocms/blocks 8 and the thin @decocms/apps-* clients. Runs the one-time migration script (scripts/main.ts: block map with legacy aliases, vendored app loaders, content in .deco/blocks, secret re-encryption, import report), then guides the manual work it reports. Use when a site's package.json depends on @decocms/blocks ^7, @decocms/tanstack, @decocms/nextjs or @decocms/blocks-admin and should move to v8; when the report lists /deco/invoke calls, createDecoWorkerEntry, RequestContext, useCart or other v7 imports to replace; when deco check rejects migrated content; or when a migrated page, draft preview, editor form or parity run differs from v7. Replaces the unpublished @decocms/blocks-migrate package."
description: "@decocms/blocks 8 (the next major): moves a v7 Deco site (@decocms/blocks 7.x with @decocms/tanstack or @decocms/nextjs, @decocms/blocks-admin, @decocms/blocks-cli, v7 @decocms/apps-*) onto @decocms/blocks 8, the v8 bindings (@decocms/tanstack 8, @decocms/nextjs 8) and the thin @decocms/apps-* clients. Runs the one-time migration script (scripts/main.ts: block map with legacy aliases, vendored app loaders, content in .deco/blocks, secret re-encryption, import report), then guides the manual work it reports. Use when a site's package.json depends on @decocms/blocks ^7, @decocms/tanstack, @decocms/nextjs or @decocms/blocks-admin and should move to v8; when the report lists /deco/invoke calls, createDecoWorkerEntry, RequestContext, useCart or other v7 imports to replace; when deco check rejects migrated content; or when a migrated page, draft preview, editor form or parity run differs from v7. Replaces the unpublished @decocms/blocks-migrate package."
---

# Deco v7 → v8 Migration

Moves a v7 site onto the next major in two parts: a script that does the mechanical, content-safe part in one pass, and a list of manual steps it prints. Proven on `deco-sites/storefront-tanstack` (Shopify, TanStack Start), `deco-sites/demo-storefront` (Shopify, TanStack Start, a redesign of storefront-tanstack's v7 tree), `deco-sites/blog-tanstack` (TanStack Start), two Next.js App Router storefronts on VTEX (ejected FastStore), a TanStack Start storefront on VTEX and a non-ejected FastStore storefront on VTEX (hundreds of saved blocks, private).
Moves a v7 site onto the next major in two parts: a script that does the mechanical, content-safe part in one pass, and a list of manual steps it prints. Proven on `deco-sites/storefront-tanstack`, `deco-sites/demo-storefront` (a redesign of storefront-tanstack's v7 tree) and `deco-sites/blog-tanstack` (TanStack Start), plus four private storefronts: two Next.js App Router (ejected FastStore), one TanStack Start and one non-ejected FastStore, all on VTEX.

The spec is the docs page **Migrating from v7** (`/next/renames-and-migrations`). When this skill and the docs disagree, the docs win.

Expand All @@ -22,14 +22,14 @@ Not for sites still on `@decocms/start@6.x` (upgrade to 7.x first with `decocms-

1. A clean working tree: the script edits files in place.
2. `DECO_CRYPTO_KEY` (the v7 secret key) in the environment, and `.deco/secrets.pub` committed (see `/next/secrets`). Without them, v7 secrets are reported, not re-encrypted.
3. **Install `@decocms/blocks@^8.1` before running the script.** Not `^8`: the `8.0.0` on npm is an accidental v7 build with no `/cli`. A v7 site already has `@decocms/blocks@7`, which lacks the `/cli` and `/protocol/keys` subpaths the script imports. Keep the v7 `@decocms/apps-*` packages installed until the script has run: it vendors the app loaders your content calls from `node_modules`.
4. `typescript` resolvable from the site (the import codemod parses `src/` with it). Every TanStack and Next site already has it.
3. **Install `@decocms/blocks@^8.3` before running the script** (not `^8`: `8.0.0` is an accidental v7 build). v7's blocks lacks the `/cli` and `/protocol/keys` the script imports. Keep the v7 `@decocms/apps-*` installed until the script has run: it vendors the app loaders your content calls from `node_modules`.
4. `typescript` resolvable from the site (the import codemod parses `src/` with it).

## Run

The script is `scripts/main.ts` in this skill. It resolves `@decocms/blocks` relative to its own files, so run it where that resolves to v8.

**From a `decocms/blocks` checkout on the v8 line** (clone it and run `bun install` there first; the script resolves `@decocms/blocks` from that checkout's `node_modules`):
**From a `decocms/blocks` checkout on the v8 line** (run `bun install` there first):

```bash
DECO_CRYPTO_KEY=… bun <blocks>/.agents/skills/deco-v7-to-v8-migration/scripts/main.ts --root <site>
Expand All @@ -39,7 +39,7 @@ DECO_CRYPTO_KEY=… bun <blocks>/.agents/skills/deco-v7-to-v8-migration/scripts/
**From an installed copy of the skill** (outside the repo): copy `scripts/` into the site so it resolves the site's `@decocms/blocks@8`, run it, then delete the copy:

```bash
cd <site> && bun add @decocms/blocks@^8.1
cd <site> && bun add @decocms/blocks@^8.3
cp -R <skill>/scripts .deco-migrate
DECO_CRYPTO_KEY=… bun .deco-migrate/main.ts --root .
rm -rf .deco-migrate
Expand All @@ -54,7 +54,7 @@ In order: **content** (and site **settings** folded into `.deco/blocks/CMS.json`

Commit the script's output unedited as its own commit (`chore: run the v7-to-v8 migration`), so reviewers can tell generated changes from hand-written ones.

**A sibling site already migrated?** When the site shares its v7 tree with one that is already on v8 (a fork, a redesign of a template), port the sibling's v8 changes with a three-way merge per file instead of by hand: `git merge-file <site file> <sibling's file after its script run> <sibling's v8 file>`. Most files merge cleanly; conflicts are mostly import lines. Then check what the merge brought that isn't the migration ([`reference/sibling-port.md`](reference/sibling-port.md)).
**A sibling site already migrated?** When the site shares its v7 tree with one that is already on v8 (a fork, a redesign of a template), port the sibling's v8 changes with a three-way merge per file instead of by hand: `git merge-file <site file> <sibling's file after its script run> <sibling's v8 file>`. Conflicts are mostly import lines. Then check what the merge brought that isn't the migration ([`reference/sibling-port.md`](reference/sibling-port.md)).

## Review the report

Expand All @@ -64,9 +64,9 @@ The script prints **Done** and **Left to do**, grouped by step. Every "Left to d

The full text of each step: [`reference/manual-steps.md`](reference/manual-steps.md).

1. **Dependencies**: `@decocms/blocks@^8.1` plus the v8 `@decocms/apps-<platform>` client; remove the v7 packages and codegen once nothing imports them.
2. **Render pages with `createCMS`** (`/next/tanstack-start-descriptors`, `/next/nextjs`); delete the v7 setup files, admin routes, `/deco/*` handlers and v7 CI jobs.
3. **Move framework code into the site** ([`reference/framework-code.md`](reference/framework-code.md)).
1. **Dependencies**: `@decocms/blocks@^8.3`, the v8 binding at the same version (`@decocms/tanstack` or `@decocms/nextjs`) and the v8 `@decocms/apps-<platform>` client; remove the other v7 packages and codegen once nothing imports them.
2. **Render pages with `createCMS` on the binding** (`/next/tanstack-start-descriptors`, `/next/nextjs`); delete the v7 setup files, admin routes, `/deco/*` handlers and v7 CI jobs.
3. **Worker, drafts, Studio and images from the binding (platform image URLs: `@decocms/apps-*/image`); the rest is site code** ([`reference/framework-code.md`](reference/framework-code.md)).
4. **Replace `/deco/invoke`** with one server function per loader or action the browser called ([`reference/server-functions.md`](reference/server-functions.md)).
5. **Fix the content `deco check` rejects** ([`reference/content.md`](reference/content.md)).
6. **Telemetry, analytics and previews** ([`reference/telemetry.md`](reference/telemetry.md)).
Expand All @@ -82,8 +82,9 @@ Then the rest of [`reference/verify.md`](reference/verify.md): `"blocksMajor": 8

## DO NOT

- Add compat shims that re-create v7 APIs (`useCart` from a package, `invoke`, `RequestContext`, a fake `@decocms/tanstack`). What v7's packages did is site code now; copy it in and own it. A site-local `invoke` object with v7's paths, or a `runInvoke("site/loaders/…")` dispatcher, is the same shim.
- Strip `"use client"` from components that need hooks, events or browser APIs to make them render.
- Add compat shims that re-create v7 APIs (`useCart` from a package, `invoke`, `RequestContext`). What v7's packages did and the bindings don't is site code now; copy it in and own it.
- Copy v7's worker entry, draft middleware, Studio bridge, preview badge or `Image` into the site: `@decocms/tanstack` and `@decocms/nextjs` ship them. A site-local `invoke` object with v7's paths, or a `runInvoke("site/loaders/…")` dispatcher, is the same shim.
- Strip `"use client"` from hook, event or browser-API components to render them.
- Rename saved type names. Content stores them; keep the v7 name as an alias (`/next/renames-and-migrations#rename-a-type-with-an-alias`).
- Hand-edit the script's output in the same commit as the run.

Expand All @@ -108,10 +109,10 @@ What the site migrations taught, one subject per file. Commit hashes refer to `d
| [`running-the-script.md`](reference/running-the-script.md) | Before the run (install order, vendoring, stale lockfiles), dependencies after |
| [`sibling-port.md`](reference/sibling-port.md) | What a three-way merge from a sibling site brings along |
| [`rendering.md`](reference/rendering.md) | No async rendering, streaming and hydration, awaited blocks, section wrappers, Tailwind |
| [`framework-code.md`](reference/framework-code.md) | Edge cache, image, SEO, devices, cookies, commerce code, error reporting |
| [`framework-code.md`](reference/framework-code.md) | The bindings (worker, drafts, Studio, images); SEO, devices, cookies, commerce code, error reporting |
| [`server-functions.md`](reference/server-functions.md) | `/deco/invoke` → server functions |
| [`caching-and-privacy.md`](reference/caching-and-privacy.md) | Per-visitor data, QueryClient scope, draft bypass, hydration waits |
| [`nextjs.md`](reference/nextjs.md) | Next.js App Router: transpilePackages, drafts on static pages, the proxy, `list('page')`, head order, Jest |
| [`nextjs.md`](reference/nextjs.md) | Next.js App Router: `@decocms/nextjs` drafts and proxy, `list('page')`, head order, Jest |
| [`hosted-releases.md`](reference/hosted-releases.md) | Hosted CMS instead of fast deploy, bundled content, v7 leftovers to delete |
| [`content.md`](reference/content.md) | `deco check` as a deploy gate, content it rejects, editing locally with `deco serve` |
| [`telemetry.md`](reference/telemetry.md) | Telemetry params, resource attributes, dropped v7 bindings, analytics |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ From the site migrations; the sites and what the commit hashes refer to are list

- **Keep per-visitor data out of the edge cache** (`844ce9f`): cache a GET server function only when its payload is page data; cart, user, wishlist, addresses answer `Cache-Control: private, no-store`, and the cache wrapper never stores such a response. Detect signed-in shoppers by the cookie the sign-in flow actually sets.
- **One QueryClient per router**, never per isolate: a shared one leaks the previous request's cart and user.
- v7's admin paths (`/deco/*`, `/live/*`, `/.decofile`) should answer 404, not a cacheable page.
- Read drafts with `await cms.draftPointer(request)`; it ignores drafts on hosts outside `preview.hosts` (the `CMS` block, capped by `createCMS({ preview })`), so list your staging and dev hosts there.
- **Gate the copied worker entry's draft bypass on the pointer too.** v7's edge cache skipped a request with `?__draft=` or the draft cookie only on an allowed preview host. A copy that checks the raw param or cookie lets anyone skip the edge cache on production (`?__draft=x`), so every such request reaches the worker and the commerce API. Compute `const previewing = (await cms.draftPointer(request)) !== null` once per request and use it wherever the copy checked for a draft.
- v7's admin paths (`/deco/*`, `/live/*`, `/.decofile`) should answer 404, not a cacheable page. `createDecoWorker` does; on Next.js, check them in the parity run (`hosted-releases.md`).
- **The draft decision is the binding's.** v7's edge cache skipped a request with `?__draft=` or the draft cookie only on an allowed preview host; a hand-copied worker that checks the raw param lets anyone skip the cache on production (`?__draft=x`). `createDecoWorker` decides once per request with v7's allowlist, skips the cache only for a draft it accepted, and hands the page that draft (`contentClient(cms)`); on Next.js, `decideDraft` in the proxy does the same. Don't add a second draft check of your own.
- **A signed-in shopper never shares a cached page**: return `"private"` from `createDecoWorker`'s `segment` for the cookie the sign-in flow actually sets; a server function answering per-visitor data calls `markPrivate()` (`@decocms/tanstack/server`).
- **Don't let hydration wait on a cross-origin call.** Prefetching the shopper's profile in the router's `hydrate` so widgets hydrate with it keeps v7's pixels, but `hydrate` is awaited: a slow or hung gateway keeps the page from ever becoming interactive. Cap the wait (a few hundred milliseconds) or don't await it. A parity harness replays upstream calls, so it never shows this cost.
Loading
Loading