diff --git a/.storybook/main.ts b/.storybook/main.ts index f592219f..9314279e 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,5 +1,84 @@ +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + import type { StorybookConfig } from '@storybook/react-vite'; +const storybookDir = path.dirname(fileURLToPath(import.meta.url)); +const workspaceRoot = path.resolve(storybookDir, '..'); +const rootNodeModulesDir = path.join(workspaceRoot, 'node_modules'); +const pnpmVirtualNodeModulesDir = path.join(rootNodeModulesDir, '.pnpm/node_modules'); + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function readDependencyNames(packageDirName: 'datavis' | 'wcdatavis'): string[] { + const packageJsonPath = path.join(rootNodeModulesDir, packageDirName, 'package.json'); + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { + dependencies?: Record; + }; + + return Object.keys(packageJson.dependencies ?? {}); +} + +const datavisDependencyNames = Array.from( + new Set([...readDependencyNames('datavis'), ...readDependencyNames('wcdatavis')]), +); + +const missingRootDependencies = datavisDependencyNames.filter( + (dependencyName) => !existsSync(path.join(rootNodeModulesDir, dependencyName)), +); + +const datavisDependencyAliases = missingRootDependencies + .filter((dependencyName) => existsSync(path.join(pnpmVirtualNodeModulesDir, dependencyName))) + .map((dependencyName) => ({ + find: new RegExp(`^${escapeRegExp(dependencyName)}(\/.*)?$`), + replacement: `${path.join(pnpmVirtualNodeModulesDir, dependencyName)}$1`, + })); + +const localUiAliases = [ + { + find: /^@mieweb\/ui\/components\/(.+)$/, + replacement: `${path.join(workspaceRoot, 'src/components')}/$1`, + }, + { + find: /^@mieweb\/ui\/styles\.css$/, + replacement: path.join(workspaceRoot, 'src/styles/base.css'), + }, + { + find: /^@mieweb\/ui$/, + replacement: path.join(workspaceRoot, 'src/index.ts'), + }, +] as const; + +const datavisCjsInteropDependencies = [ + 'underscore', + 'sprintf-js', + 'jquery', + 'bignumber.js', + 'numeral', + 'moment', + 'json-formatter-js', + 'papaparse', + 'handlebars', +] as const; + +const datavisLegacySubpathDependencies = [ + 'core-js/es/string/replace-all', + 'chart.js/auto', + 'squirrelly/dist/browser/squirrelly.min.js', +] as const; + +const datavisSourceEntries = [ + 'datavis/src/components/DataGrid.tsx', + 'datavis/src/adapters/colconfig-adapter.ts', + 'datavis/src/adapters/group-adapter.ts', + 'datavis/src/adapters/wcdatavis-interop.ts', + 'datavis/src/adapters/use-data.ts', + 'datavis/src/components/table/TableRenderer.tsx', +] as const; + const config: StorybookConfig = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ @@ -16,6 +95,44 @@ const config: StorybookConfig = { reactDocgen: 'react-docgen-typescript', }, staticDirs: ['./public'], + async viteFinal(config) { + config.resolve ??= {}; + config.resolve.alias = [ + ...(Array.isArray(config.resolve.alias) + ? config.resolve.alias + : config.resolve.alias + ? [config.resolve.alias] + : []), + ...localUiAliases, + ...datavisDependencyAliases, + ]; + + config.esbuild = { + ...config.esbuild, + jsx: 'automatic', + jsxImportSource: 'react', + }; + + config.optimizeDeps ??= {}; + config.optimizeDeps.force = true; + config.optimizeDeps.include = Array.from( + new Set([ + ...(config.optimizeDeps.include ?? []), + ...datavisSourceEntries, + ...datavisDependencyNames, + ...datavisCjsInteropDependencies, + ...datavisLegacySubpathDependencies, + ...missingRootDependencies, + ]), + ); + config.optimizeDeps.esbuildOptions = { + ...config.optimizeDeps.esbuildOptions, + jsx: 'automatic', + jsxImportSource: 'react', + }; + + return config; + }, }; export default config; diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index a98e03b2..c38ba863 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -1,3 +1,8 @@ + +