diff --git a/CLAUDE.md b/CLAUDE.md index a9474cdb..8fd73643 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -670,6 +670,15 @@ Two pieces make the current arrangement, and they have to stay in step: `main`. Deploy hooks are unaffected by `deploymentEnabled: false` — that setting gates the Git integration, not the hook. +**Vercel installs from `apps/docs`, and CI does not.** An `npm install` run inside a workspace +brings only what that workspace depends on, directly or through another workspace it names. CI +runs `npm ci` at the root, which brings everything, so a package the docs build needs and +`apps/docs` never declared is present in CI and missing on Vercel. The first deploy of the web +collection failed this way, on `tailwind-variants`, with every check green. The docs app +therefore depends on `panelui-web` by name, because its pages import that source by path, and a +contract test holds it there. To see what Vercel will see, clone the repository fresh, then +`cd apps/docs && npm install && npm run build`. + **A documentation change that is not part of a release does not reach panelui.dev on its own.** New previews, a corrected props table and a typo fix all sit on `main` until the next release. To publish them now, run the **Deploy docs** workflow by hand from the Actions tab — that is what the diff --git a/apps/docs/package.json b/apps/docs/package.json index df91899a..2854557d 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -34,6 +34,7 @@ "lucide-react": "^1.25.0", "next": "^16.3.0", "next-themes": "^0.4.6", + "panelui-web": "*", "react": "^19.2.3", "react-day-picker": "^10.0.1", "react-dom": "^19.2.3", diff --git a/apps/docs/test/web-registry.test.mjs b/apps/docs/test/web-registry.test.mjs index 5d22ed6b..357073b5 100644 --- a/apps/docs/test/web-registry.test.mjs +++ b/apps/docs/test/web-registry.test.mjs @@ -114,3 +114,39 @@ test('every component has a thumb for the index, and the index shows the gallery } assert.match(read('content/docs/web/components/index.mdx'), //); }); + +/* + * The site is built on Vercel from `apps/docs`, and an install run from there + * brings only what the docs app depends on, directly or through a workspace + * it names. The pages import the web components' source by path, so that + * source's own imports have to arrive the same way. CI installs every + * workspace from the root and cannot see one that is missing: the first + * deploy of the web collection failed on exactly this, with every check green. + */ +test('the docs app can install what the web components import', () => { + const web = path.resolve(docs, '../../packages/web'); + const webPackage = JSON.parse(fs.readFileSync(path.join(web, 'package.json'), 'utf8')); + const docsPackage = JSON.parse(read('package.json')); + + assert.ok( + docsPackage.dependencies?.['panelui-web'], + 'apps/docs must depend on panelui-web: its pages import that source, and Vercel installs from apps/docs' + ); + + // And the package says everything its source reaches for, so naming the package is enough. + const declared = new Set([ + ...Object.keys(webPackage.dependencies ?? {}), + ...Object.keys(webPackage.peerDependencies ?? {}), + ]); + const sources = fs + .readdirSync(path.join(web, 'src'), { recursive: true }) + .filter((file) => /\.tsx?$/.test(String(file))); + for (const file of sources) { + const source = fs.readFileSync(path.join(web, 'src', String(file)), 'utf8'); + for (const [, specifier] of source.matchAll(/from\s+['"]([^'".][^'"]*)['"]/g)) { + // `@scope/name/sub/path` and `name/sub/path` both belong to the package before the sub path. + const name = specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0]; + assert.ok(declared.has(name), `${file} imports ${specifier}, which packages/web/package.json does not declare`); + } + } +}); diff --git a/package-lock.json b/package-lock.json index 09001f56..b75e7c9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "lucide-react": "^1.25.0", "next": "^16.3.0", "next-themes": "^0.4.6", + "panelui-web": "*", "react": "^19.2.3", "react-day-picker": "^10.0.1", "react-dom": "^19.2.3",