Skip to content

Commit

Permalink
Merge pull request #16412 from storybookjs/lazy-load-docs
Browse files Browse the repository at this point in the history
Addon-docs: Lazy load docs to reduce bundle size
  • Loading branch information
shilman committed Oct 21, 2021
2 parents 05b93be + 3eaac50 commit 0dcd17c
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 33 deletions.
3 changes: 2 additions & 1 deletion addons/a11y/src/a11yRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ const run = async (storyId: string) => {

/** Returns story parameters or default ones. */
const getParams = async (storyId: string): Promise<A11yParameters> => {
const { parameters } = (await globalWindow.__STORYBOOK_STORY_STORE__.loadStory({ storyId })) || {};
const { parameters } =
(await globalWindow.__STORYBOOK_STORY_STORE__.loadStory({ storyId })) || {};
return (
parameters.a11y || {
config: {},
Expand Down
1 change: 0 additions & 1 deletion addons/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
"@storybook/addons": "6.4.0-beta.16",
"@storybook/api": "6.4.0-beta.16",
"@storybook/builder-webpack4": "6.4.0-beta.16",
"@storybook/client-api": "6.4.0-beta.16",
"@storybook/client-logger": "6.4.0-beta.16",
"@storybook/components": "6.4.0-beta.16",
"@storybook/core": "6.4.0-beta.16",
Expand Down
3 changes: 1 addition & 2 deletions addons/docs/src/blocks/enhanceSource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { combineParameters } from '@storybook/client-api';
import { Parameters } from '@storybook/addons';
import { Story } from '@storybook/store';
import { Story, combineParameters } from '@storybook/store';

// ============================================================
// START @storybook/source-loader/extract-source
Expand Down
5 changes: 2 additions & 3 deletions addons/docs/src/frameworks/common/config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { DocsContainer, DocsPage } from '../../blocks';
import { enhanceArgTypes } from './enhanceArgTypes';

export const parameters = {
docs: {
inlineStories: false,
container: DocsContainer,
page: DocsPage,
getContainer: async () => (await import('../../blocks')).DocsContainer,
getPage: async () => (await import('../../blocks')).DocsPage,
iframeHeight: 100,
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import mapValues from 'lodash/mapValues';
import { storiesOf, StoryContext } from '@storybook/react';
import { ArgsTable } from '@storybook/components';
import { Args } from '@storybook/api';
import { inferControls } from '@storybook/client-api';
import { inferControls } from '@storybook/store';

import { extractArgTypes } from './extractArgTypes';
import { Component } from '../../blocks';
Expand Down
30 changes: 6 additions & 24 deletions lib/preview-web/src/PreviewWeb.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import React, { ComponentType } from 'react';
import ReactDOM from 'react-dom';
import deprecate from 'util-deprecate';
import dedent from 'ts-dedent';
import Events, { IGNORED_EXCEPTION } from '@storybook/core-events';
Expand Down Expand Up @@ -27,11 +25,10 @@ import {
StoryIndex,
} from '@storybook/store';

import { WebProjectAnnotations, DocsContextProps } from './types';
import { WebProjectAnnotations } from './types';

import { UrlStore } from './UrlStore';
import { WebView } from './WebView';
import { NoDocs } from './NoDocs';
import { StoryIndexClient } from './StoryIndexClient';

const { window: globalWindow, AbortController, FEATURES } = global;
Expand Down Expand Up @@ -371,7 +368,7 @@ export class PreviewWeb<TFramework extends AnyFramework> {
}

async renderDocs({ story }: { story: Story<TFramework> }) {
const { id, title, name, componentId } = story;
const { id, title, name } = story;
const element = this.view.prepareForDocs();
const csfFile: CSFFile<TFramework> = await this.storyStore.loadCSFFileByStoryId(id, {
sync: false,
Expand All @@ -392,31 +389,16 @@ export class PreviewWeb<TFramework extends AnyFramework> {
} as StoryContextForLoaders<TFramework>),
};

const { docs } = story.parameters;
if (docs?.page && !docs?.container) {
throw new Error('No `docs.container` set, did you run `addon-docs/preset`?');
}

const DocsContainer: ComponentType<{ context: DocsContextProps<TFramework> }> =
docs.container || (({ children }: { children: Element }) => <>{children}</>);
const Page: ComponentType = docs.page || NoDocs;

const render = () => {
const render = async () => {
const fullDocsContext = {
...docsContext,
// Put all the storyContext fields onto the docs context for back-compat
...(!FEATURES.breakingChangesV7 && this.storyStore.getStoryContext(story)),
};

// Use `componentId` as a key so that we force a re-render every time
// we switch components
const docsElement = (
<DocsContainer key={componentId} context={fullDocsContext}>
<Page />
</DocsContainer>
(await import('./renderDocs')).renderDocs(story, fullDocsContext, element, () =>
this.channel.emit(Events.DOCS_RENDERED, id)
);

ReactDOM.render(docsElement, element, () => this.channel.emit(Events.DOCS_RENDERED, id));
};

// Initially render right away
Expand Down Expand Up @@ -633,7 +615,7 @@ export class PreviewWeb<TFramework extends AnyFramework> {
: this.previousSelection?.viewMode;

if (unmountDocs && previousViewMode === 'docs') {
ReactDOM.unmountComponentAtNode(this.view.docsRoot());
(await import('./renderDocs')).unmountDocs(this.view.docsRoot());
}

if (this.previousCleanup) {
Expand Down
50 changes: 50 additions & 0 deletions lib/preview-web/src/renderDocs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { ComponentType } from 'react';
import ReactDOM from 'react-dom';
import { AnyFramework } from '@storybook/csf';
import { Story } from '@storybook/store';

import { DocsContextProps } from './types';
import { NoDocs } from './NoDocs';

export function renderDocs<TFramework extends AnyFramework>(
story: Story<TFramework>,
docsContext: DocsContextProps<TFramework>,
element: HTMLElement,
callback: () => void
) {
return renderDocsAsync(story, docsContext, element).then(callback);
}

async function renderDocsAsync<TFramework extends AnyFramework>(
story: Story<TFramework>,
docsContext: DocsContextProps<TFramework>,
element: HTMLElement
) {
const { docs } = story.parameters;
if ((docs?.getPage || docs?.page) && !(docs?.getContainer || docs?.container)) {
throw new Error('No `docs.container` set, did you run `addon-docs/preset`?');
}

const DocsContainer: ComponentType<{ context: DocsContextProps<TFramework> }> =
docs.container ||
(await docs.getContainer?.()) ||
(({ children }: { children: Element }) => <>{children}</>);

const Page: ComponentType = docs.page || (await docs.getPage?.()) || NoDocs;

// Use `componentId` as a key so that we force a re-render every time
// we switch components
const docsElement = (
<DocsContainer key={story.componentId} context={docsContext}>
<Page />
</DocsContainer>
);

await new Promise<void>((resolve) => {
ReactDOM.render(docsElement, element, resolve);
});
}

export function unmountDocs(element: HTMLElement) {
ReactDOM.unmountComponentAtNode(element);
}
1 change: 0 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6944,7 +6944,6 @@ __metadata:
"@storybook/angular": 6.4.0-beta.16
"@storybook/api": 6.4.0-beta.16
"@storybook/builder-webpack4": 6.4.0-beta.16
"@storybook/client-api": 6.4.0-beta.16
"@storybook/client-logger": 6.4.0-beta.16
"@storybook/components": 6.4.0-beta.16
"@storybook/core": 6.4.0-beta.16
Expand Down

0 comments on commit 0dcd17c

Please sign in to comment.