Skip to content

Commit 429ed60

Browse files
authored
refactor: [M3-8184] - Improve local Storybook performance (#10762)
## Description 📝 Performance optimizations for running Storybook locally The main culprit is using `react-docgen-typescript`; it's parsing every file for docgen info. The package is also [no longer being maintained](styleguidist/react-docgen-typescript#494) (the last release was in [end of 2021](https://github.com/styleguidist/react-docgen-typescript/releases)). - There's a faster docgen library that Storybook 8 uses, `react-docgen`, however we're missing a lot of typing by using that since it's using a shallower analysis. - The solution I ended up at was to keep `react-docgen-typescript`, but tighten the scope on what files are parsed for the docgen (Components and Features only). And to also disable `allowSyntheticDefaultImports` and `esModuleInterop` per the [Storybook MUI docs ](https://storybook.js.org/recipes/@mui/material#4-use-material-ui-prop-types-for-better-controls-and-docs) The time from first paint to Intro loaded on my Intel i7 2019 MBP went from `over 1 minute` to `30s` 🎉 ## How to test 🧪 ### Reproduction steps (How to reproduce the issue, if applicable) - On the develop branch, run Storybook locally and time the time it takes from first paint to Intro loaded ### Verification steps (How to verify changes) - Pull down this branch, run Storybook locally and the time from first paint to Intro loaded should be shorter than develop - The should be no regressions in the typing and loading of stories compared to https://design.linode.com/
1 parent 218b009 commit 429ed60

File tree

4 files changed

+72
-1
lines changed

4 files changed

+72
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Tech Stories
3+
---
4+
5+
Improve local Storybook performance ([#10762](https://github.com/linode/manager/pull/10762))

packages/manager/.storybook/main.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import type { StorybookConfig } from '@storybook/react-vite';
22
import { mergeConfig } from 'vite';
3+
import { getReactDocgenTSFileGlobs } from './utils';
4+
5+
const typeScriptFileGlobs = getReactDocgenTSFileGlobs();
36

47
const config: StorybookConfig = {
58
stories: [
@@ -22,6 +25,11 @@ const config: StorybookConfig = {
2225
},
2326
typescript: {
2427
reactDocgenTypescriptOptions: {
28+
// Speeds up Storybook build time
29+
compilerOptions: {
30+
allowSyntheticDefaultImports: false,
31+
esModuleInterop: false,
32+
},
2533
// makes union prop types like variant and size appear as select controls
2634
shouldExtractLiteralValuesFromEnum: true,
2735
// makes string and boolean types that can be undefined appear as inputs and switches
@@ -31,8 +39,11 @@ const config: StorybookConfig = {
3139
prop.parent
3240
? !/node_modules\/(?!@mui)/.test(prop.parent.fileName)
3341
: true,
42+
// Only compile files that have stories for faster local development performance
43+
include: /(development|test)/i.test(process.env.NODE_ENV ?? '')
44+
? typeScriptFileGlobs
45+
: undefined,
3446
},
35-
3647
reactDocgen: 'react-docgen-typescript',
3748
},
3849
docs: {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { getReactDocgenTSFileGlobs } from './utils';
2+
3+
describe('getReactDocgenTSFileGlobs', () => {
4+
const typeScriptFileGlobs = getReactDocgenTSFileGlobs();
5+
it('should return component and feature globs for storybook files', () => {
6+
expect(
7+
typeScriptFileGlobs.some(
8+
(file) => file === 'src/components/Button/**/*.{ts,tsx}'
9+
)
10+
).toBe(true);
11+
expect(
12+
typeScriptFileGlobs.some(
13+
(file) => file === 'src/components/Paper.{ts,tsx}'
14+
)
15+
).toBe(true);
16+
expect(
17+
typeScriptFileGlobs.some(
18+
(file) => file === 'src/features/TopMenu/**/*.{ts,tsx}'
19+
)
20+
).toBe(true);
21+
expect(
22+
typeScriptFileGlobs.some(
23+
(file) => file === 'src/features/Longview/**/*.{ts,tsx}'
24+
)
25+
).toBe(false);
26+
});
27+
});

packages/manager/.storybook/utils.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import globby from 'globby';
2+
3+
const PATTERN = 'src/**/*.stories.tsx';
4+
5+
/**
6+
* Find all storybook files, then return the glob containing the parent component/feature.
7+
* To be used in main.ts to tell react-docgen-typescript which files to compile.
8+
* https://github.com/linode/manager/pull/10762
9+
*
10+
* Example: src/components/Button/Button.stories.tsx -> src/components/Button/**\/*.{ts,tsx}
11+
*/
12+
export const getReactDocgenTSFileGlobs = () => {
13+
const filesWithStories = globby.sync(PATTERN);
14+
const files: string[] = [];
15+
16+
filesWithStories.forEach((file) => {
17+
const execArr = /(src\/(components|features)\/[a-zA-Z]*(.|\/))/.exec(file);
18+
if (execArr) {
19+
const isDirectory = execArr[3] === '/';
20+
const fileBlob = `${execArr[0]}${isDirectory ? '**/*.' : ''}{ts,tsx}`;
21+
if (!files.includes(fileBlob)) {
22+
files.push(fileBlob);
23+
}
24+
}
25+
});
26+
27+
return files;
28+
};

0 commit comments

Comments
 (0)