diff --git a/packages/manager/.changeset/pr-10762-tech-stories-1723134446106.md b/packages/manager/.changeset/pr-10762-tech-stories-1723134446106.md new file mode 100644 index 00000000000..665493fde8a --- /dev/null +++ b/packages/manager/.changeset/pr-10762-tech-stories-1723134446106.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tech Stories +--- + +Improve local Storybook performance ([#10762](https://github.com/linode/manager/pull/10762)) diff --git a/packages/manager/.storybook/main.ts b/packages/manager/.storybook/main.ts index d5e56868cfe..3592d630db9 100644 --- a/packages/manager/.storybook/main.ts +++ b/packages/manager/.storybook/main.ts @@ -1,5 +1,8 @@ import type { StorybookConfig } from '@storybook/react-vite'; import { mergeConfig } from 'vite'; +import { getReactDocgenTSFileGlobs } from './utils'; + +const typeScriptFileGlobs = getReactDocgenTSFileGlobs(); const config: StorybookConfig = { stories: [ @@ -22,6 +25,11 @@ const config: StorybookConfig = { }, typescript: { reactDocgenTypescriptOptions: { + // Speeds up Storybook build time + compilerOptions: { + allowSyntheticDefaultImports: false, + esModuleInterop: false, + }, // makes union prop types like variant and size appear as select controls shouldExtractLiteralValuesFromEnum: true, // makes string and boolean types that can be undefined appear as inputs and switches @@ -31,8 +39,11 @@ const config: StorybookConfig = { prop.parent ? !/node_modules\/(?!@mui)/.test(prop.parent.fileName) : true, + // Only compile files that have stories for faster local development performance + include: /(development|test)/i.test(process.env.NODE_ENV ?? '') + ? typeScriptFileGlobs + : undefined, }, - reactDocgen: 'react-docgen-typescript', }, docs: { diff --git a/packages/manager/.storybook/utils.test.ts b/packages/manager/.storybook/utils.test.ts new file mode 100644 index 00000000000..7d87d853c66 --- /dev/null +++ b/packages/manager/.storybook/utils.test.ts @@ -0,0 +1,27 @@ +import { getReactDocgenTSFileGlobs } from './utils'; + +describe('getReactDocgenTSFileGlobs', () => { + const typeScriptFileGlobs = getReactDocgenTSFileGlobs(); + it('should return component and feature globs for storybook files', () => { + expect( + typeScriptFileGlobs.some( + (file) => file === 'src/components/Button/**/*.{ts,tsx}' + ) + ).toBe(true); + expect( + typeScriptFileGlobs.some( + (file) => file === 'src/components/Paper.{ts,tsx}' + ) + ).toBe(true); + expect( + typeScriptFileGlobs.some( + (file) => file === 'src/features/TopMenu/**/*.{ts,tsx}' + ) + ).toBe(true); + expect( + typeScriptFileGlobs.some( + (file) => file === 'src/features/Longview/**/*.{ts,tsx}' + ) + ).toBe(false); + }); +}); diff --git a/packages/manager/.storybook/utils.ts b/packages/manager/.storybook/utils.ts new file mode 100644 index 00000000000..f6a75ea62ee --- /dev/null +++ b/packages/manager/.storybook/utils.ts @@ -0,0 +1,28 @@ +import globby from 'globby'; + +const PATTERN = 'src/**/*.stories.tsx'; + +/** + * Find all storybook files, then return the glob containing the parent component/feature. + * To be used in main.ts to tell react-docgen-typescript which files to compile. + * https://github.com/linode/manager/pull/10762 + * + * Example: src/components/Button/Button.stories.tsx -> src/components/Button/**\/*.{ts,tsx} + */ +export const getReactDocgenTSFileGlobs = () => { + const filesWithStories = globby.sync(PATTERN); + const files: string[] = []; + + filesWithStories.forEach((file) => { + const execArr = /(src\/(components|features)\/[a-zA-Z]*(.|\/))/.exec(file); + if (execArr) { + const isDirectory = execArr[3] === '/'; + const fileBlob = `${execArr[0]}${isDirectory ? '**/*.' : ''}{ts,tsx}`; + if (!files.includes(fileBlob)) { + files.push(fileBlob); + } + } + }); + + return files; +};