import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import tailwindcss from "@tailwindcss/vite"; import type { StorybookConfig } from "@storybook/react-vite"; import { mergeConfig } from "vite"; const storybookConfigDir = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(storybookConfigDir, "../../.."); const docsSourceDir = path.resolve(storybookConfigDir, "../src"); const storybookRootCacheDir = path.resolve( storybookConfigDir, "../../../.artifacts/cache/storybook" ); const storyFilePattern = /\.stories\.(ts|tsx)$/; function collectStoryPaths(directory: string): string[] { const entries = fs.readdirSync(directory, { withFileTypes: true }); const storyPaths: string[] = []; for (const entry of entries) { const entryPath = path.join(directory, entry.name); if (entry.isDirectory()) { storyPaths.push(...collectStoryPaths(entryPath)); continue; } if (storyFilePattern.test(entry.name)) { storyPaths.push(path.relative(docsSourceDir, entryPath).split(path.sep).join("/")); } } return storyPaths; } function createStorybookCacheKey() { const storyPaths = collectStoryPaths(docsSourceDir).sort(); return crypto .createHash("sha1") .update(JSON.stringify(storyPaths)) .digest("hex") .slice(0, 8); } const storybookCacheDir = path.resolve( storybookRootCacheDir, `vite-${createStorybookCacheKey()}` ); const uiSourceEntry = path.resolve(storybookConfigDir, "../../../packages/ui/src/index.ts"); const tokensSourceEntry = path.resolve( storybookConfigDir, "../../../packages/tokens/src/index.ts" ); const config: StorybookConfig = { stories: ["../src/**/*.stories.@(ts|tsx)"], addons: [ "@storybook/addon-a11y", "@storybook/addon-essentials", "@storybook/addon-interactions" ], framework: { name: "@storybook/react-vite", options: {} }, async viteFinal(config) { return mergeConfig(config, { cacheDir: storybookCacheDir, plugins: [tailwindcss()], optimizeDeps: { exclude: ["@ai-ui/ui", "@ai-ui/tokens"] }, resolve: { alias: [ { find: /^@ai-ui\/ui$/, replacement: uiSourceEntry }, { find: /^@ai-ui\/tokens$/, replacement: tokensSourceEntry } ] }, server: { fs: { allow: [repoRoot] }, watch: { usePolling: true, interval: 120, awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 40 } } } }); } }; export default config;