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

Server: Initial support for @storybook/server #9722

Merged
merged 28 commits into from
Feb 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
422bc3a
Initial support for @storybook/server
jonspalmer Jan 2, 2020
65a8886
Cleanup and add example app
jonspalmer Jan 2, 2020
1bbc7cf
Add Options to configure signature
jonspalmer Jan 2, 2020
7099e18
Wire up the knobs
jonspalmer Jan 2, 2020
d4c2faa
Refactor to use parameters
jonspalmer Jan 2, 2020
a685fc4
Support Parameters and StoryFn as a way to pass params to the server
jonspalmer Jan 2, 2020
a06694d
fetchStoryHtml now optional
jonspalmer Jan 2, 2020
d066a06
Update Readme
jonspalmer Jan 2, 2020
507002e
Storybook Docs work in progress
shilman Dec 30, 2019
d4820e0
Docs WIP with wepack not Parcel
Dec 30, 2019
c8faee0
Workaround for docs linking CORS error
shilman Dec 31, 2019
3791af2
Update to rc.6
jonspalmer Jan 2, 2020
614ddcd
.storybook example app with CSF compiler
jonspalmer Jan 2, 2020
11b7d9d
Sever: Add snapshot compiler test
shilman Jan 2, 2020
f70294d
Feedback from PR
jonspalmer Jan 2, 2020
4a9366e
Cleanup
jonspalmer Jan 2, 2020
9987b50
Update to new main.js format
jonspalmer Jan 2, 2020
0510b17
Update README.md
shilman Jan 2, 2020
3838f66
Rename kitchen sink app
jonspalmer Jan 2, 2020
d61bbe5
rc.7
jonspalmer Jan 2, 2020
be4d06c
Merge branch 'next' into pr/9250
shilman Jan 8, 2020
a0f51c8
Merge branch 'storybook_server' of https://github.com/jonspalmer/stor…
tmeasday Feb 3, 2020
0a65a5a
Fix typo
tmeasday Feb 3, 2020
c15feb6
Rename `id` to `path` to be a bit more general
tmeasday Feb 3, 2020
f0c71e0
Merge remote-tracking branch 'origin/next' into jonspalmer-storybook_…
tmeasday Feb 4, 2020
d12beea
Update package.json
shilman Feb 4, 2020
c7532e2
Update package.json
shilman Feb 4, 2020
3007fe5
Update yarn.lock
shilman Feb 4, 2020
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
25 changes: 25 additions & 0 deletions app/server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Storybook for Server

---

Storybook for Server is a UI development environment for your plain HTML snippets rendered by your server backend.
With it, you can visualize different states of your UI components and develop them interactively.

![Storybook Screenshot](https://github.com/storybookjs/storybook/blob/master/media/storybook-intro.gif)

Storybook runs outside of your app.
So you can develop UI components in isolation without worrying about app specific dependencies and requirements.

## Getting Started

```sh
cd my-app
npx -p @storybook/cli sb init -t server
```

For more information visit: [storybook.js.org](https://storybook.js.org)

---

Storybook also comes with a lot of [addons](https://storybook.js.org/addons/introduction) and a great API to customize as you wish.
You can also build a [static version](https://storybook.js.org/basics/exporting-storybook) of your storybook and deploy it anywhere you want.
4 changes: 4 additions & 0 deletions app/server/bin/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env node

process.env.NODE_ENV = process.env.NODE_ENV || 'production';
require('../dist/server/build');
3 changes: 3 additions & 0 deletions app/server/bin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node

require('../dist/server');
59 changes: 59 additions & 0 deletions app/server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"name": "@storybook/server",
"version": "6.0.0-alpha.4",
"description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybookjs/storybook/tree/master/app/server",
"bugs": {
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybookjs/storybook.git",
"directory": "app/html"
},
"license": "MIT",
"files": [
"bin/**/*",
"dist/**/*",
"README.md",
"*.js",
"*.d.ts"
],
"main": "dist/client/index.js",
"types": "dist/client/index.d.ts",
"bin": {
"build-storybook": "./bin/build.js",
"start-storybook": "./bin/index.js",
"storybook-server": "./bin/index.js"
},
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "6.0.0-alpha.4",
"@storybook/core": "6.0.0-alpha.4",
"@storybook/node-logger": "^5.2.8",
"@types/webpack-env": "^1.13.9",
"core-js": "^3.0.1",
"global": "^4.3.2",
"regenerator-runtime": "^0.13.3",
"safe-identifier": "^0.3.1",
"ts-dedent": "^1.1.0"
},
"devDependencies": {
"fs-extra": "^8.0.1"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0"
},
"engines": {
"node": ">=8.0.0"
},
"publishConfig": {
"access": "public"
},
"gitHead": "6ad2664adf18b50ea3ce015cbae2ff3e9a60cc4a"
}
14 changes: 14 additions & 0 deletions app/server/src/client/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export {
storiesOf,
setAddon,
addDecorator,
addParameters,
configure,
getStorybook,
forceReRender,
raw,
} from './preview';

if (module && module.hot && module.hot.decline) {
module.hot.decline();
}
3 changes: 3 additions & 0 deletions app/server/src/client/preview/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { window } from 'global';

window.STORYBOOK_ENV = 'SERVER';
43 changes: 43 additions & 0 deletions app/server/src/client/preview/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { start } from '@storybook/core/client';
import { ClientStoryApi, Loadable } from '@storybook/addons';

import './globals';
import { renderMain as render, setFetchStoryHtml } from './render';
import { StoryFnServerReturnType, IStorybookSection, ConfigureOptionsArgs } from './types';

const framework = 'server';

interface ClientApi extends ClientStoryApi<StoryFnServerReturnType> {
setAddon(addon: any): void;
configure(loader: Loadable, module: NodeModule, options?: ConfigureOptionsArgs): void;
getStorybook(): IStorybookSection[];
clearDecorators(): void;
forceReRender(): void;
raw: () => any; // todo add type
}

const api = start(render);

export const storiesOf: ClientApi['storiesOf'] = (kind, m) => {
return (api.clientApi.storiesOf(kind, m) as ReturnType<ClientApi['storiesOf']>).addParameters({
framework,
});
};

const setRenderFetchAndConfigure: ClientApi['configure'] = (loader, module, options) => {
if (options && options.fetchStoryHtml) {
setFetchStoryHtml(options.fetchStoryHtml);
}
api.configure(loader, module, framework);
};

export const configure: ClientApi['configure'] = setRenderFetchAndConfigure;
export const {
addDecorator,
addParameters,
clearDecorators,
setAddon,
forceReRender,
getStorybook,
raw,
} = api.clientApi;
61 changes: 61 additions & 0 deletions app/server/src/client/preview/render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { document, fetch, Node } from 'global';
import dedent from 'ts-dedent';
import { RenderMainArgs, FetchStoryHtmlType } from './types';

const rootElement = document.getElementById('root');

let fetchStoryHtml: FetchStoryHtmlType = async (url, path, params) => {
const fetchUrl = new URL(`${url}/${path}`);
fetchUrl.search = new URLSearchParams(params).toString();

const response = await fetch(fetchUrl);
return response.text();
};

export async function renderMain({
storyFn,
id,
selectedKind,
selectedStory,
showMain,
showError,
forceRender,
parameters,
}: RenderMainArgs) {
const storyParams = storyFn();

const {
server: { url, id: storyId, params },
} = parameters;

const fetchId = storyId || id;
const fetchParams = { ...params, ...storyParams };
const element = await fetchStoryHtml(url, fetchId, fetchParams);

showMain();
if (typeof element === 'string') {
rootElement.innerHTML = element;
} else if (element instanceof Node) {
// Don't re-mount the element if it didn't change and neither did the story
if (rootElement.firstChild === element && forceRender === true) {
return;
}

rootElement.innerHTML = '';
rootElement.appendChild(element);
} else {
showError({
title: `Expecting an HTML snippet or DOM node from the story: "${selectedStory}" of "${selectedKind}".`,
description: dedent`
Did you forget to return the HTML snippet from the story?
Use "() => <your snippet or node>" or when defining the story.
`,
});
}
}

export const setFetchStoryHtml: any = (fetchHtml: FetchStoryHtmlType) => {
if (fetchHtml !== undefined) {
fetchStoryHtml = fetchHtml;
}
};
35 changes: 35 additions & 0 deletions app/server/src/client/preview/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { StoryFn } from '@storybook/addons';

export type StoryFnServerReturnType = any;

export type FetchStoryHtmlType = (url: string, id: string, params: any) => Promise<string | Node>;

export interface IStorybookStory {
name: string;
render: () => any;
}

export interface IStorybookSection {
kind: string;
stories: IStorybookStory[];
}

export interface ShowErrorArgs {
title: string;
description: string;
}

export interface ConfigureOptionsArgs {
fetchStoryHtml: FetchStoryHtmlType;
}

export interface RenderMainArgs {
storyFn: () => StoryFn<StoryFnServerReturnType>;
id: string;
selectedKind: string;
selectedStory: string;
showMain: () => void;
showError: (args: ShowErrorArgs) => void;
forceRender: boolean;
parameters: any;
}
15 changes: 15 additions & 0 deletions app/server/src/lib/compiler/__testfixtures__/a11y.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"title": "Addons/a11y",
"addons": ["a11y"],
"parameters": {
"options": { "selectedPanel": "storybook/a11y/panel" }
},
"stories": [
{
"name": "Label",
"parameters": {
"server": { "id": "addons/a11y/label" }
}
}
]
}
28 changes: 28 additions & 0 deletions app/server/src/lib/compiler/__testfixtures__/a11y.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`json-to-csf-compiler a11y.json 1`] = `
"import { withA11y } from '@storybook/addon-a11y';

export default {
title: 'Addons/a11y',
decorators: [
withA11y
],
parameters: {
options: {
selectedPanel: 'storybook/a11y/panel'
}
}
};

export const Label = () => {};
Label.story = {
name: 'Label',
parameters: {
server: {
id: 'addons/a11y/label'
}
}
};
"
`;
16 changes: 16 additions & 0 deletions app/server/src/lib/compiler/__testfixtures__/actions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"title": "Addons/Actions",
"addons": ["actions"],
"parameters": {
"options": { "selectedPanel": "storybook/actions/panel" }
},
"stories": [
{
"name": "Multiple actions + config",
"parameters": {
"server": { "id": "addons/actions/story3" }
},
"actions": ["click", "contextmenu", { "clearOnStoryChange": false }]
}
]
}
34 changes: 34 additions & 0 deletions app/server/src/lib/compiler/__testfixtures__/actions.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`json-to-csf-compiler actions.json 1`] = `
"import { withActions } from '@storybook/addon-actions';

export default {
title: 'Addons/Actions',
parameters: {
options: {
selectedPanel: 'storybook/actions/panel'
}
}
};

export const Multiple_actions_config = () => {};
Multiple_actions_config.story = {
decorators: [
withActions(
'click',
'contextmenu',
{
clearOnStoryChange: false
}
)
],
name: 'Multiple actions + config',
parameters: {
server: {
id: 'addons/actions/story3'
}
}
};
"
`;
17 changes: 17 additions & 0 deletions app/server/src/lib/compiler/__testfixtures__/backgrounds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"title": "Addons/Backgrounds",
"parameters": {
"backgrounds": [
{ "name": "light", "value": "#eeeeee" },
{ "name": "dark", "value": "#222222", "default": true }
]
},
"stories": [
{
"name": "Story 1",
"parameters": {
"server": { "id": "addons/backgrounds/story1" }
}
}
]
}
Loading