From 777e4e7a9174d919886ee40b93e1e24d877cc0fc Mon Sep 17 00:00:00 2001 From: Jonas Jesus Date: Mon, 13 Apr 2026 16:41:08 -0300 Subject: [PATCH 1/3] fix: add website/sections exports to package.json Vite requires subpath exports to be declared explicitly. Without these entries, `import("@decocms/apps/website/sections/Seo/SeoV2")` fails with "Missing specifier" during dependency scanning. Co-Authored-By: Claude Opus 4.6 --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index aec54c1..b22a1b3 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,9 @@ "./website/matchers/*": "./website/matchers/*.ts", "./website/flags/*": "./website/flags/*.ts", "./website/flags/multivariate/*": "./website/flags/multivariate/*.ts", - "./website/utils/*": "./website/utils/*.ts" + "./website/utils/*": "./website/utils/*.ts", + "./website/sections/*": "./website/sections/*.tsx", + "./website/sections/Seo/*": "./website/sections/Seo/*.tsx" }, "scripts": { "generate:manifests": "tsx scripts/generate-manifests.ts", From 7f925f8f2d2ccdba2f53bf0037f74c21d9fb6633 Mon Sep 17 00:00:00 2001 From: Jonas Jesus Date: Mon, 13 Apr 2026 17:04:58 -0300 Subject: [PATCH 2/3] fix: globalThis singleton and SeoV2 loader fallback - website/client.ts: Use globalThis.__decoWebsiteConfig instead of module-level variable to survive Vite module duplication (optimized deps vs raw source imports create separate module instances). - SeoV2.tsx: Fall back to getWebsiteConfig() singleton when the seo argument is not provided, enabling standalone use from the asJson handler without requiring the full app resolution pipeline. Co-Authored-By: Claude Opus 4.6 --- website/client.ts | 11 ++++++----- website/sections/Seo/SeoV2.tsx | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/website/client.ts b/website/client.ts index 312fa0e..5065095 100644 --- a/website/client.ts +++ b/website/client.ts @@ -1,20 +1,21 @@ /** * Website app singleton configuration. * - * Follows the same pattern as vtex/client.ts and resend/client.ts. + * Uses globalThis to survive Vite module duplication (optimized deps + * vs raw source imports can create separate module instances). */ import type { WebsiteConfig } from "./types"; -let _config: WebsiteConfig | null = null; +const G = globalThis as unknown as { __decoWebsiteConfig?: WebsiteConfig }; export function configureWebsite(config: WebsiteConfig): void { - _config = config; + G.__decoWebsiteConfig = config; } export function getWebsiteConfig(): WebsiteConfig { - if (!_config) { + if (!G.__decoWebsiteConfig) { throw new Error("Website app not configured. Call configureWebsite() first."); } - return _config; + return G.__decoWebsiteConfig; } diff --git a/website/sections/Seo/SeoV2.tsx b/website/sections/Seo/SeoV2.tsx index ef964ef..f8a2b09 100644 --- a/website/sections/Seo/SeoV2.tsx +++ b/website/sections/Seo/SeoV2.tsx @@ -3,6 +3,7 @@ import SeoComponent, { type SEOSection, type Props as SeoProps, } from "../../components/Seo"; +import { getWebsiteConfig } from "../../client"; import type { WebsiteConfig } from "../../types"; type Props = Pick< @@ -12,16 +13,26 @@ type Props = Pick< /** * Loader that merges page-level SEO props with app-level defaults. - * The framework calls this with the WebsiteConfig from the app state. + * When called by the framework, `seo` comes from the app state. + * When called standalone (e.g. asJson handler), falls back to the + * globalThis-backed singleton set by `configureWebsite()`. */ export function loader(props: Props, seo?: WebsiteConfig["seo"]) { + const resolvedSeo = seo ?? (() => { + try { + return getWebsiteConfig().seo; + } catch { + return undefined; + } + })(); + const { titleTemplate = "", descriptionTemplate = "", title: appTitle = "", description: appDescription = "", ...seoSiteProps - } = seo ?? {}; + } = resolvedSeo ?? {}; const { title: _title, description: _description, ...seoProps } = props; From 555da88c21749545d7c2730d6bb9d399ad5ea527 Mon Sep 17 00:00:00 2001 From: Jonas Jesus Date: Mon, 13 Apr 2026 17:17:29 -0300 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20biome=20lint=20=E2=80=94=20import=20?= =?UTF-8?q?order=20and=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- website/sections/Seo/SeoV2.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/website/sections/Seo/SeoV2.tsx b/website/sections/Seo/SeoV2.tsx index f8a2b09..f7cf41a 100644 --- a/website/sections/Seo/SeoV2.tsx +++ b/website/sections/Seo/SeoV2.tsx @@ -1,9 +1,9 @@ +import { getWebsiteConfig } from "../../client"; import SeoComponent, { renderTemplateString, type SEOSection, type Props as SeoProps, } from "../../components/Seo"; -import { getWebsiteConfig } from "../../client"; import type { WebsiteConfig } from "../../types"; type Props = Pick< @@ -18,13 +18,15 @@ type Props = Pick< * globalThis-backed singleton set by `configureWebsite()`. */ export function loader(props: Props, seo?: WebsiteConfig["seo"]) { - const resolvedSeo = seo ?? (() => { - try { - return getWebsiteConfig().seo; - } catch { - return undefined; - } - })(); + const resolvedSeo = + seo ?? + (() => { + try { + return getWebsiteConfig().seo; + } catch { + return undefined; + } + })(); const { titleTemplate = "",