diff --git a/layers/marketing/app/pages/developers.vue b/layers/marketing/app/pages/developers.vue index b9470247..6c8b436d 100644 --- a/layers/marketing/app/pages/developers.vue +++ b/layers/marketing/app/pages/developers.vue @@ -5,17 +5,15 @@ import SetupSnippet from '../components/_SetupSnippet.vue' import { API_OPENAPI_PATH, apiSamples, - apiSampleSchema, apiSnippets, cursorInstallUrl, mcpApps, - mcpAppSchema, setupModes, - setupModeSchema, setupSnippets, SKILLD_SKILL_SOURCE, vscodeInstallUrl, } from '../utils/developer-setup' +import { apiSampleSchema, mcpAppSchema, setupModeSchema } from '../utils/developer-setup-query' import { pageRobots } from '../utils/page-admissions' definePageMeta({ layout: 'account' }) diff --git a/layers/marketing/app/utils/developer-setup-query.ts b/layers/marketing/app/utils/developer-setup-query.ts new file mode 100644 index 00000000..8a495570 --- /dev/null +++ b/layers/marketing/app/utils/developer-setup-query.ts @@ -0,0 +1,12 @@ +import { z } from 'zod' + +/** + * The `/developers` query parsers. They live apart from `developer-setup.ts` + * because `/cli` imports that file for its snippets, and zod there put about + * 90 kB raw of JavaScript in the `/cli` preloads. + */ +export const setupModeSchema = z.enum(['cli', 'mcp', 'api']) + +export const mcpAppSchema = z.enum(['chatgpt', 'claude', 'claude-code', 'codex', 'cursor', 'vscode', 'other']) + +export const apiSampleSchema = z.enum(['typescript', 'curl']) diff --git a/layers/marketing/app/utils/developer-setup.ts b/layers/marketing/app/utils/developer-setup.ts index ce4f7316..ab48fc42 100644 --- a/layers/marketing/app/utils/developer-setup.ts +++ b/layers/marketing/app/utils/developer-setup.ts @@ -1,4 +1,3 @@ -import { z } from 'zod' import { REGISTRY_MCP_URL } from '#shared/agent-setup' import { accountCmds, skilldSelfInstallCmd } from '#shared/skill-commands' @@ -26,8 +25,6 @@ export const setupModes = { }, } as const -export const setupModeSchema = z.enum(['cli', 'mcp', 'api']) - /** Alphabetical, so no vendor leads (VISION principle 6). */ export const mcpApps = { 'chatgpt': { label: 'ChatGPT' }, @@ -39,8 +36,6 @@ export const mcpApps = { 'other': { label: 'Other apps' }, } as const -export const mcpAppSchema = z.enum(['chatgpt', 'claude', 'claude-code', 'codex', 'cursor', 'vscode', 'other']) - /** Cursor's install link carries the server config as base64 JSON, without the name. */ export function cursorInstallUrl(url: string = REGISTRY_MCP_URL): string { const config = btoa(JSON.stringify({ url })) @@ -79,8 +74,6 @@ export const apiSamples = { curl: { label: 'cURL' }, } as const -export const apiSampleSchema = z.enum(['typescript', 'curl']) - /** * One call the page prints, in both the SDK form and the cURL form. A unit * test sends each through the SDK and checks it against the contract, so a diff --git a/nuxt.config.ts b/nuxt.config.ts index 1237c113..3e0ce157 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -28,8 +28,12 @@ function discoveredComparisonRoutes(): string[] { const iconCollections = iconifyCollections(pkg) -/** Vendor packages only lazy chunks import; see `vendor-shared` below. */ -const LAZY_ONLY_VENDOR = /[\\/]node_modules[\\/](?:zod|rangi)[\\/]/ +/** + * Vendor packages only lazy chunks import; see `vendor-shared` below. The + * last alternative also matches Nuxt's `comark-content%2Fcomponents.mjs` + * template, whose id carries no path separators. + */ +const LAZY_ONLY_VENDOR = /[\\/]node_modules[\\/](?:zod|rangi)[\\/]|comark-content(?:[\\/]|%2F)/ const hasSentryAuthToken = Boolean(process.env.SENTRY_AUTH_TOKEN) || existsSync('.env.sentry-build-plugin') @@ -745,12 +749,6 @@ export default defineNuxtConfig({ viteEnvironmentApi: false, }, - features: { - // Nuxt 4.6 emits unresolved inline-style chunks with this Rolldown graph. - // Load emitted CSS stylesheets instead. - inlineStyles: false, - }, - vite: { plugins: [dependencyPluginCompat()], $client: { @@ -761,35 +759,44 @@ export default defineNuxtConfig({ // sampled traces. Vitest runs server code through this config too, so // tests keep tracing. define: process.env.NODE_ENV === 'test' ? {} : { __SENTRY_TRACING__: false }, - }, - build: { - rolldownOptions: { - output: { - codeSplitting: { - // Googlebot spends 58% of its requests on JavaScript and renders - // each page with its own fetches, so the number of files a page - // needs is a crawl cost. Rolldown's default split made one chunk per - // set of importers, so a `/gh` page preloaded 75 files, 38 of them - // under 3 KB. This gathers the small `node_modules` modules that - // two or more chunks share into one chunk. Larger vendor modules - // keep their own lazy chunks. - // - // App code is left out on purpose. A shared app module in a group - // becomes a hub every importer names by hash, so one edit rehashed - // 44 chunks in a measured build. The vendor chunk only changes - // when a dependency does. Numbers: docs/ops/crawl-efficiency-2026-09-30.md. - // - // zod and rangi stay out. Only lazy pages use them (WebMCP, make-skill, - // developers, /me, admin; mdxg docs), but grouped they rode in the one - // vendor chunk every page preloads. - groups: [ - { - name: 'vendor-shared', - test: (id: string) => id.includes('node_modules') && !LAZY_ONLY_VENDOR.test(id), - minShareCount: 2, - maxModuleSize: 8 * 1024, - }, - ], + // Client build only. Applied to the server build too, the group left an + // unresolved chunk placeholder (`!~{002}~`) in Nuxt 4.6's inline-style + // chunks, and the Nitro bundle failed. That forced `inlineStyles: false`, + // which linked up to nine render-blocking stylesheets per page. + build: { + rolldownOptions: { + output: { + codeSplitting: { + // Googlebot spends 58% of its requests on JavaScript and renders + // each page with its own fetches, so the number of files a page + // needs is a crawl cost. Rolldown's default split made one chunk per + // set of importers, so a `/gh` page preloaded 75 files, 38 of them + // under 3 KB. This gathers the small `node_modules` modules that + // two or more chunks share into one chunk. Larger vendor modules + // keep their own lazy chunks. + // + // App code is left out on purpose. A shared app module in a group + // becomes a hub every importer names by hash, so one edit rehashed + // 44 chunks in a measured build. The vendor chunk only changes + // when a dependency does. Numbers: docs/ops/crawl-efficiency-2026-09-30.md. + // + // zod and rangi stay out. Only lazy pages use them (WebMCP, make-skill, + // developers, /me, admin; mdxg docs), but grouped they rode in the one + // vendor chunk every page preloads. + // + // comark-content stays out too. A group takes a module's static + // imports with it, and its ContentRenderer imports every content + // component, so the Skill card, the package setup form and zod + // (through that form) rode in this chunk on every page. + groups: [ + { + name: 'vendor-shared', + test: (id: string) => id.includes('node_modules') && !LAZY_ONLY_VENDOR.test(id), + minShareCount: 2, + maxModuleSize: 8 * 1024, + }, + ], + }, }, }, },