Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storybook: Fix Circular Dependencies and fast refresh #11161

Merged
merged 17 commits into from
Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .storybook/main.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
const path = require('path');
const webpack = require('webpack');
const CircularDependencyPlugin = require('circular-dependency-plugin');

/**
* Storybook Workaround: https://github.com/storybookjs/storybook/issues/14877#issuecomment-1000441696
Expand Down Expand Up @@ -51,15 +52,10 @@ module.exports = {
'@storybook/addon-essentials',
'@storybook/addon-storysource/register',
],
framework: '@storybook/react',
core: {
builder: 'webpack5',
},
reactOptions: {
// Disabled due to compatibility issues with webpack 5.
// See https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/308
fastRefresh: false,
strictMode: true,
},
//eslint-disable-next-line require-await -- Negligible.
webpackFinal: async (config) => {
// webpack < 5 used to include polyfills for node.js core modules by default.
Expand Down Expand Up @@ -123,6 +119,20 @@ module.exports = {
})
);

config.plugins.push(
new CircularDependencyPlugin({
// exclude detection of files based on a RegExp
exclude: /a\.js|node_modules/,
// add errors to webpack instead of warnings
failOnError: true,
// allow import cycles that include an asyncronous import,
// e.g. via import(/* webpackMode: "weak" */ 'file.js')
allowAsyncCycles: false,
// set the current working directory for displaying module paths
cwd: process.cwd(),
})
);

// Ensure SVGR is the only loader used for files with .svg extension.
const assetRule = config.module.rules.find(({ test }) => test.test('.svg'));
assetRule.exclude = /\.svg/;
Expand Down
142 changes: 72 additions & 70 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,29 @@
/**
* External dependencies
*/
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { addDecorator, addParameters } from '@storybook/react';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import {
theme as designSystemTheme,
lightMode,
ThemeGlobals,
ModalGlobalStyle,
} from '@googleforcreators/design-system';
import {
theme,
GlobalStyle,
EditorConfigProvider,
} from '@googleforcreators/story-editor';
import { CropMoveableGlobalStyle } from '@googleforcreators/moveable';
import {
DashboardGlobalStyle,
DashboardKeyboardOnlyOutline,
ConfigProvider as DashboardConfigProvider,
ApiProvider,
} from '@googleforcreators/dashboard';

/**
* Internal dependencies
*/
// Disable reason:
// Importing from the dashboard and story editor roots break fast refresh in storybook.
// Prevented by importing the necessary providers and configs directly.
/* eslint-disable import/no-relative-packages */
import { GlobalStyle as DashboardGlobalStyle } from '../packages/dashboard/src/theme';
import DashboardKeyboardOnlyOutline from '../packages/dashboard/src/utils/keyboardOnlyOutline';
import DashboardConfigProvider from '../packages/dashboard/src/app/config/configProvider';
import ApiProvider from '../packages/dashboard/src/app/api/apiProvider';
import EditorConfigProvider from '../packages/story-editor/src/app/config/configProvider';
/* eslint-enable import/no-relative-packages */

Comment on lines +33 to 43
Copy link
Contributor Author

@samwhale samwhale Apr 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The story editor and dashboard stories were not fast refreshing, and were logging warnings like this:

Dashboard Story Editor
image image

Importing directly from the modules here removes these warnings and fixes fast refresh.

Got the idea from this thread

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting 🤔

I guess storybook doesn't like npm workspaces where the packages are referenced from node_modules but actually symlinked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe 🤷 but seems like finding these imports using relative paths seems to fix it. Luckily this change can be scoped to this one file.

// @todo: Find better way to mock these.
const wp = {};
Expand All @@ -55,7 +56,7 @@ window.wp.media = {

const { ipad, ipad10p, ipad12p } = INITIAL_VIEWPORTS;

addParameters({
export const parameters = {
a11y: {
element: '#root',
config: {},
Expand All @@ -76,68 +77,69 @@ addParameters({
{ name: 'Dark', value: 'rgba(0, 0, 0, 0.9)', default: true },
],
},
});
};

addDecorator((story, context) => {
const { id } = context;
// TODO(#10380): Replacement add-on for RTL feature
const isRTL = false;
export const decorators = [
(Story, context) => {
const { id } = context;
// TODO(#10380): Replacement add-on for RTL feature
const isRTL = false;

const isDesignSystemStorybook = id.startsWith('designsystem');
const isDashboardStorybook = id.startsWith('dashboard');
const isDesignSystemStorybook = id.startsWith('designsystem');
const isDashboardStorybook = id.startsWith('dashboard');

if (isDashboardStorybook) {
return (
<ThemeProvider
theme={{
...designSystemTheme,
colors: lightMode,
}}
>
<DashboardConfigProvider
config={{
api: { stories: 'stories' },
apiCallbacks: {
getUser: () => Promise.resolve({ id: 1 }),
},
editStoryURL: 'editStory',
isRTL,
styleConstants: {
topOffset: 0,
},
if (isDashboardStorybook) {
return (
<ThemeProvider
theme={{
...designSystemTheme,
colors: lightMode,
}}
>
<ApiProvider>
<DashboardGlobalStyle />
<ModalGlobalStyle />
<DashboardKeyboardOnlyOutline />
{story()}
</ApiProvider>
</DashboardConfigProvider>
</ThemeProvider>
);
}
<DashboardConfigProvider
config={{
api: { stories: 'stories' },
apiCallbacks: {
getUser: () => Promise.resolve({ id: 1 }),
},
editStoryURL: 'editStory',
isRTL,
styleConstants: {
topOffset: 0,
},
}}
>
<ApiProvider>
<DashboardGlobalStyle />
<ModalGlobalStyle />
<DashboardKeyboardOnlyOutline />
{Story()}
</ApiProvider>
</DashboardConfigProvider>
</ThemeProvider>
);
}

if (isDesignSystemStorybook) {
// override darkMode colors
const dsTheme = { ...designSystemTheme, colors: lightMode };
return (
<ThemeProvider theme={dsTheme}>
<ThemeGlobals.Styles />
<ModalGlobalStyle />
{Story()}
</ThemeProvider>
);
}

if (isDesignSystemStorybook) {
// override darkMode colors
const dsTheme = { ...designSystemTheme, colors: lightMode };
return (
<ThemeProvider theme={dsTheme}>
<ThemeGlobals.Styles />
<ModalGlobalStyle />
{story()}
<ThemeProvider theme={designSystemTheme}>
<EditorConfigProvider config={{ isRTL }}>
<CropMoveableGlobalStyle />
<ModalGlobalStyle />
{Story()}
</EditorConfigProvider>
</ThemeProvider>
);
}

return (
<ThemeProvider theme={theme}>
<EditorConfigProvider config={{ isRTL }}>
<GlobalStyle />
<CropMoveableGlobalStyle />
<ModalGlobalStyle />
{story()}
</EditorConfigProvider>
</ThemeProvider>
);
});
},
];
Loading