From 88c99a2d2444e1bd1b650246f5cd26c5b98e66f0 Mon Sep 17 00:00:00 2001 From: Hypnosphi Date: Sun, 8 Apr 2018 22:00:34 +0300 Subject: [PATCH] Enforce addons store being a singleton by storing it in global variable --- addons/a11y/package.json | 2 +- addons/actions/package.json | 2 +- addons/background/package.json | 2 +- addons/events/package.json | 2 +- addons/jest/package.json | 2 +- addons/knobs/package.json | 2 +- addons/links/package.json | 2 +- addons/notes/package.json | 2 +- addons/options/package.json | 2 +- addons/storyshots/package.json | 3 +-- addons/storyshots/src/index.js | 5 ++--- addons/storysource/package.json | 2 +- addons/viewport/package.json | 2 +- docs/src/pages/basics/faq/index.md | 8 +++++++- lib/addons/package.json | 4 ++++ lib/addons/src/index.js | 19 ++++++++++++++++--- .../addons}/src/storybook-channel-mock.js | 0 17 files changed, 41 insertions(+), 20 deletions(-) rename {addons/storyshots => lib/addons}/src/storybook-channel-mock.js (100%) diff --git a/addons/a11y/package.json b/addons/a11y/package.json index fe39828cf1fc..20dac2db4aa4 100644 --- a/addons/a11y/package.json +++ b/addons/a11y/package.json @@ -25,6 +25,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/client-logger": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "axe-core": "^3.0.1", @@ -38,7 +39,6 @@ "faker": "^4.1.0" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*", "react-dom": "*" } diff --git a/addons/actions/package.json b/addons/actions/package.json index ebeda4feceb5..8f7364ed34b5 100644 --- a/addons/actions/package.json +++ b/addons/actions/package.json @@ -20,6 +20,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "deep-equal": "^1.0.1", @@ -32,7 +33,6 @@ "uuid": "^3.2.1" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*", "react-dom": "*" } diff --git a/addons/background/package.json b/addons/background/package.json index 17c33476be8f..8f3b785b3ba9 100644 --- a/addons/background/package.json +++ b/addons/background/package.json @@ -24,13 +24,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "global": "^4.3.2", "prop-types": "^15.6.1", "react-lifecycles-compat": "^1.1.4" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*" } } diff --git a/addons/events/package.json b/addons/events/package.json index bb0cd95a803c..d9487a7f3e1c 100644 --- a/addons/events/package.json +++ b/addons/events/package.json @@ -21,6 +21,7 @@ "storybook": "start-storybook -p 6006" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "format-json": "^1.0.3", "prop-types": "^15.6.1", @@ -28,7 +29,6 @@ "react-textarea-autosize": "^6.1.0" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*" } } diff --git a/addons/jest/package.json b/addons/jest/package.json index 315827e6269f..8b509d0b4456 100644 --- a/addons/jest/package.json +++ b/addons/jest/package.json @@ -25,6 +25,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "glamor": "^2.20.40", @@ -33,7 +34,6 @@ "prop-types": "^15.6.1" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*", "react-dom": "*" } diff --git a/addons/knobs/package.json b/addons/knobs/package.json index a4d43c70e691..675d6b47dda4 100644 --- a/addons/knobs/package.json +++ b/addons/knobs/package.json @@ -15,6 +15,7 @@ "storybook": "start-storybook -p 9010" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "deep-equal": "^1.0.1", @@ -36,7 +37,6 @@ "vue": "^2.5.16" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*", "react-dom": "*" } diff --git a/addons/links/package.json b/addons/links/package.json index bed8a0ca1c76..0a78fb57d929 100644 --- a/addons/links/package.json +++ b/addons/links/package.json @@ -22,6 +22,7 @@ "storybook": "start-storybook -p 9001" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "global": "^4.3.2", @@ -34,7 +35,6 @@ "react-dom": "^16.3.1" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "16.3.1", "react-dom": "16.3.1" } diff --git a/addons/notes/package.json b/addons/notes/package.json index cfa375da1459..ce9bd3ad45b0 100644 --- a/addons/notes/package.json +++ b/addons/notes/package.json @@ -20,6 +20,7 @@ "storybook": "start-storybook -p 9010" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "marked": "^0.3.19", "prop-types": "^15.6.1", @@ -30,7 +31,6 @@ "@types/react": "^16.3.5" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*" } } diff --git a/addons/options/package.json b/addons/options/package.json index 0fabe8b76ffd..08f8a2680806 100644 --- a/addons/options/package.json +++ b/addons/options/package.json @@ -20,13 +20,13 @@ "storybook": "start-storybook -p 9001" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "babel-runtime": "^6.26.0" }, "devDependencies": { "@storybook/react": "4.0.0-alpha.1" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*", "react-dom": "*" } diff --git a/addons/storyshots/package.json b/addons/storyshots/package.json index a6b3245d00e2..6f01995c1f24 100644 --- a/addons/storyshots/package.json +++ b/addons/storyshots/package.json @@ -16,7 +16,7 @@ "storybook": "start-storybook -p 6006" }, "dependencies": { - "@storybook/channels": "4.0.0-alpha.1", + "@storybook/addons": "4.0.0-alpha.1", "@storybook/core": "4.0.0-alpha.1", "@storybook/node-logger": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", @@ -37,7 +37,6 @@ "react-dom": "^16.3.1" }, "peerDependencies": { - "@storybook/addons": "4.0.0-alpha.1", "babel-core": "^6.26.0 || ^7.0.0-0" } } diff --git a/addons/storyshots/src/index.js b/addons/storyshots/src/index.js index 302492d62b1c..81dd3a362d86 100644 --- a/addons/storyshots/src/index.js +++ b/addons/storyshots/src/index.js @@ -1,9 +1,8 @@ import fs from 'fs'; import glob from 'glob'; import global, { describe, it } from 'global'; -import addons from '@storybook/addons'; +import addons, { mockChannel } from '@storybook/addons'; import loadFramework from './frameworkLoader'; -import createChannel from './storybook-channel-mock'; import { getPossibleStoriesFiles, getSnapshotFileName } from './utils'; import { imageSnapshot } from './test-body-image-snapshot'; @@ -34,7 +33,7 @@ export default function testStorySnapshots(options = {}) { throw new Error('testStorySnapshots is intended only to be used inside jest'); } - addons.setChannel(createChannel()); + addons.setChannel(mockChannel()); const { storybook, framework, renderTree, renderShallowTree } = loadFramework(options); const stories = storybook.getStorybook(); diff --git a/addons/storysource/package.json b/addons/storysource/package.json index 96796a59534a..ef62e38b87df 100644 --- a/addons/storysource/package.json +++ b/addons/storysource/package.json @@ -20,6 +20,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "estraverse": "^4.2.0", @@ -29,7 +30,6 @@ "react-syntax-highlighter": "^7.0.2" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*", "react-dom": "*" } diff --git a/addons/viewport/package.json b/addons/viewport/package.json index f9fc153ea3ad..e2ad3456a507 100644 --- a/addons/viewport/package.json +++ b/addons/viewport/package.json @@ -11,6 +11,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@storybook/addons": "4.0.0-alpha.1", "@storybook/components": "4.0.0-alpha.1", "babel-runtime": "^6.26.0", "global": "^4.3.2", @@ -18,7 +19,6 @@ "prop-types": "^15.6.1" }, "peerDependencies": { - "@storybook/addons": "^3.3.0", "react": "*" } } diff --git a/docs/src/pages/basics/faq/index.md b/docs/src/pages/basics/faq/index.md index 2b15bafe7c70..fb7bd4c3d8b0 100644 --- a/docs/src/pages/basics/faq/index.md +++ b/docs/src/pages/basics/faq/index.md @@ -29,7 +29,13 @@ You can generally reuse webpack rules fairly easily by placing them in a file th A common error is that an addon tries to access the "channel", but the channel is not set. This can happen in a few different cases: -1. In storybook/addon development, it can be an NPM version problem. If there are two versions of the `@storybook/addons` NPM package, it will cause problems. In this case, make sure there is only a single version of `@storybook/addons` being used by your project. +1. You're trying to access addon channel (e.g. by calling `setOptions`) in a non-browser environment like Jest. You may need to add a channel mock: + ```js + import addons, { mockChannel } from '@storybook/addons'; + + addons.setChannel(mockChannel()); + ``` + 2. In React Native, it's a special case that's documented in [#1192](https://github.com/storybooks/storybook/issues/1192) ### Can I modify React component state in stories? diff --git a/lib/addons/package.json b/lib/addons/package.json index 7e65779bdf7e..cf596e35a4a7 100644 --- a/lib/addons/package.json +++ b/lib/addons/package.json @@ -18,5 +18,9 @@ }, "scripts": { "prepare": "node ../../scripts/prepare.js" + }, + "dependencies": { + "@storybook/channels": "4.0.0-alpha.1", + "global": "^4.3.2" } } diff --git a/lib/addons/src/index.js b/lib/addons/src/index.js index 548103c170c8..161a58ed0067 100644 --- a/lib/addons/src/index.js +++ b/lib/addons/src/index.js @@ -1,3 +1,8 @@ +// Resolves to window in browser and to global in node +import global from 'global'; + +export mockChannel from './storybook-channel-mock'; + export class AddonStore { constructor() { this.loaders = {}; @@ -8,8 +13,7 @@ export class AddonStore { } getChannel() { - // this.channel should get overwritten by setChannel if package versions are - // correct and AddonStore is a proper singleton. If not, throw. + // this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), throw. if (!this.channel) { throw new Error( 'Accessing nonexistent addons channel, see https://storybook.js.org/basics/faq/#why-is-there-no-addons-channel' @@ -57,4 +61,13 @@ export class AddonStore { } } -export default new AddonStore(); +// Enforce addons store to be a singleton +const KEY = '__STORYBOOK_ADDONS'; +function getAddonsStore() { + if (!global[KEY]) { + global[KEY] = new AddonStore(); + } + return global[KEY]; +} + +export default getAddonsStore(); diff --git a/addons/storyshots/src/storybook-channel-mock.js b/lib/addons/src/storybook-channel-mock.js similarity index 100% rename from addons/storyshots/src/storybook-channel-mock.js rename to lib/addons/src/storybook-channel-mock.js