fix(docs): make the build self-contained for Vercel
Vercel's "Root Directory" setting limits the upload to docs/api/, so the build cannot read sibling paths like ../../server/openapi.json or ../api-content/. A small prebuild script copies both into a vendored folder inside the project tree (gitignored). ## Changes - Add scripts/sync-sources.mjs to copy /docs/api-content/ and /server/openapi.json into docs/api/src/vendored/ before dev/build - Wire predev/prebuild npm scripts so the sync runs automatically - Update astro.config.mjs and src/content.config.ts to read from the vendored paths - Gitignore src/vendored/ — contributors still edit the originals
This commit is contained in:
1 parent
0d25973efb
commit
8e4e9dd87c
5 files changed
+72
-4
No files matched your search
@@ -2,6 +2,10 @@
|
||||
dist/
|
||||
.astro/
|
||||
|
||||
# Sources copied in at build time by scripts/sync-sources.mjs.
|
||||
# Edit /docs/api-content/ and /server/openapi.json instead.
|
||||
src/vendored/
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
@@ -14,3 +18,4 @@ pnpm-debug.log*
|
||||
# Env
|
||||
.env
|
||||
.env.production
|
||||
.vercel
|
||||
@@ -2,9 +2,12 @@ import { defineConfig } from "astro/config";
|
||||
import starlight from "@astrojs/starlight";
|
||||
import starlightOpenAPI, { openAPISidebarGroups } from "starlight-openapi";
|
||||
|
||||
// The OpenAPI spec lives in the server package. The Starlight integration
|
||||
// reads it at build time and generates the full /api/reference/* tree.
|
||||
const OPENAPI_PATH = "../../server/openapi.json";
|
||||
// The OpenAPI spec is vendored from server/openapi.json by
|
||||
// scripts/sync-sources.mjs (runs as predev/prebuild). We point at the
|
||||
// vendored copy so the build is self-contained — Vercel only uploads
|
||||
// the docs/api/ subtree, so paths outside this directory are not
|
||||
// available at build time.
|
||||
const OPENAPI_PATH = "./src/vendored/openapi.json";
|
||||
|
||||
export default defineConfig({
|
||||
// Served at https://checkmate.so/docs — the leading slash is included so
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
"private": true,
|
||||
"description": "Public API documentation for Checkmate. Built with Astro Starlight.",
|
||||
"scripts": {
|
||||
"prebuild": "node ./scripts/sync-sources.mjs",
|
||||
"predev": "node ./scripts/sync-sources.mjs",
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copies external sources into the Astro project tree so the build is
|
||||
// self-contained. Required because Vercel's "Root Directory" setting
|
||||
// only uploads the docs/api/ subtree, leaving sibling/parent paths
|
||||
// (server/openapi.json, docs/api-content/) outside the build context.
|
||||
//
|
||||
// Run automatically by predev / prebuild via package.json. If the
|
||||
// external paths exist, they win; otherwise we assume the files were
|
||||
// already vendored (e.g. by a previous run) and continue.
|
||||
|
||||
import { existsSync, mkdirSync, cpSync, copyFileSync, statSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PROJECT_ROOT = join(__dirname, "..");
|
||||
const REPO_ROOT = join(PROJECT_ROOT, "..", "..");
|
||||
|
||||
const SOURCES = [
|
||||
{
|
||||
// Markdown prose (the public docs content).
|
||||
from: join(REPO_ROOT, "docs", "api-content"),
|
||||
to: join(PROJECT_ROOT, "src", "vendored", "api-content"),
|
||||
kind: "dir",
|
||||
},
|
||||
{
|
||||
// OpenAPI spec — read at build time by starlight-openapi.
|
||||
from: join(REPO_ROOT, "server", "openapi.json"),
|
||||
to: join(PROJECT_ROOT, "src", "vendored", "openapi.json"),
|
||||
kind: "file",
|
||||
},
|
||||
];
|
||||
|
||||
let synced = 0;
|
||||
for (const src of SOURCES) {
|
||||
if (!existsSync(src.from)) {
|
||||
if (existsSync(src.to)) {
|
||||
console.log(`[sync-sources] ${src.from} not present; using existing vendored copy.`);
|
||||
continue;
|
||||
}
|
||||
console.error(`[sync-sources] ERROR: source missing and no vendored copy: ${src.from}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
mkdirSync(dirname(src.to), { recursive: true });
|
||||
if (src.kind === "dir") {
|
||||
cpSync(src.from, src.to, { recursive: true });
|
||||
} else {
|
||||
copyFileSync(src.from, src.to);
|
||||
}
|
||||
const stat = statSync(src.from);
|
||||
console.log(`[sync-sources] ${src.from} → ${src.to} (${stat.isDirectory() ? "dir" : `${stat.size} bytes`})`);
|
||||
synced++;
|
||||
}
|
||||
|
||||
console.log(`[sync-sources] OK (${synced} sources copied)`);
|
||||
@@ -13,7 +13,10 @@ import { docsSchema } from "@astrojs/starlight/schema";
|
||||
export const collections = {
|
||||
docs: defineCollection({
|
||||
loader: glob({
|
||||
base: "../api-content",
|
||||
// Vendored from /docs/api-content/ by scripts/sync-sources.mjs.
|
||||
// This indirection keeps the build self-contained for Vercel
|
||||
// (whose Root Directory setting limits the upload to docs/api/).
|
||||
base: "./src/vendored/api-content",
|
||||
// README is contributor-facing docs (how to build the site),
|
||||
// not part of the published content.
|
||||
pattern: ["**/[^_]*.{md,mdx}", "!README.md"],
|
||||
|
||||
Reference in new issue
Block a user