diff --git a/tsconfig.node.json b/tsconfig.node.json index f3edef58..4c78e2b0 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -15,6 +15,7 @@ "eslint.config.ts", "vitest.config.ts", "postcss.config.ts", - "tailwind.config.ts" + "tailwind.config.ts", + "src/utils/*.ts" ] } diff --git a/vite.config.ts b/vite.config.ts index b2fc9f97..e40e9342 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,6 @@ import { defineConfig, Plugin, version as viteVersion } from "vite"; -import type { PluginContext, ViteDevServer } from "vite"; +import type { ViteDevServer } from "vite"; +import type { PluginContext } from "rollup"; import react from "@vitejs/plugin-react"; import { simpleGit } from "simple-git"; import os from "os"; @@ -77,7 +78,7 @@ const getGitInfo = async (): Promise<{ // Fallback to environment variables or defaults return { sha: getEnv("VITE_GIT_SHA", "unknown"), - isClean: getEnv("VITE_GIT_CLEAN", "unknown"), + isClean: getEnv("VITE_GIT_CLEAN", "false") === "true", branch: getEnv("VITE_GIT_BRANCH", "unknown"), }; } @@ -128,8 +129,8 @@ function buildInfoPlugin(): Plugin { function dataValidationPlugin(dir: string = "src/data") { return { name: "data-validation", - apply: "build", - enforce: "pre", + apply: "build" as const, + enforce: "pre" as const, async buildStart(this: PluginContext) { const names = (await fs.readdir(dir)).filter((f) => f.endsWith(".json")); const entries: FileEntry[] = []; @@ -184,12 +185,52 @@ function dataValidationPlugin(dir: string = "src/data") { }; } +// Create a new plugin for serving schema files +// Used to access the schema files with the dev server +function schemaServePlugin(): Plugin { + return { + name: "schema-serve", + configureServer(server: ViteDevServer) { + server.middlewares.use( + "/schema", + ( + req: IncomingMessage, + res: ServerResponse, + next: (err?: unknown) => void, + ): void => { + try { + const baseDir = resolve("src/schema"); + const relPath = decodeURIComponent( + (req.url || "").replace(/^\/schema\/?/, ""), + ); + if (!relPath) return next(); // no file requested, let Vite handle + const absPath = resolve(baseDir, relPath); + // prevent path traversal + if (!absPath.startsWith(baseDir)) return next(); + // only serve JSON files + if (!absPath.endsWith(".json")) return next(); + readFile(absPath, "utf8") + .then((json) => { + res.setHeader("Content-Type", "application/json"); + res.end(json); + }) + .catch(next); + } catch (err) { + next(err); + } + }, + ); + }, + }; +} + // https://vitejs.dev/config/ export default defineConfig({ plugins: [ react(), buildInfoPlugin(), dataValidationPlugin("src/data"), + schemaServePlugin(), viteStaticCopy({ // Copy the entire schema dir to /schema in the built output targets: [{ src: "src/schema/**/*", dest: "schema" }], @@ -199,36 +240,4 @@ export default defineConfig({ open: true, port: 3000, }, - configureServer(server: ViteDevServer) { - // Serve any file under src/schema at /schema/* during dev - server.middlewares.use( - "/schema", - ( - req: IncomingMessage, - res: ServerResponse, - next: (err?: unknown) => void, - ): void => { - try { - const baseDir = resolve("src/schema"); - const relPath = decodeURIComponent( - (req.url || "").replace(/^\/schema\/?/, ""), - ); - if (!relPath) return next(); // no file requested, let Vite handle - const absPath = resolve(baseDir, relPath); - // prevent path traversal - if (!absPath.startsWith(baseDir)) return next(); - // only serve JSON files - if (!absPath.endsWith(".json")) return next(); - readFile(absPath, "utf8") - .then((json) => { - res.setHeader("Content-Type", "application/json"); - res.end(json); - }) - .catch(next); - } catch (err) { - next(err); - } - }, - ); - }, });