I've been trying to integrate Vulcan.js, a Meteor framework, with Storybook. The difficulty comes from the differences in build system. Currently, we are able to load some specific Meteor packages in Storybook using Webpack.

So, now we need to mimick some additional Meteor features in Storybook. We rely on a Meteor.startup() callback to initialize a specific React component that is a registry of other components. However I can't find any equivalent pattern in Storybook.

The characteristic of a callback registered with Meteor.startup() are as following:

  • it is run after the app is build. So it is not possible to just write a "startup" file and import it, because it will run too soon, the registry will still be empty
  • it is run before stories are actually rendered or loaded. Basically Meteor.startup callbacks are guaranteed to be the first function to be run. So calling relevant function in a decorator may be too late.
  • it is called only once. This is not a strong requirement as we can bypass it by writing callbacks as pure function but it's better to avoid multiple calls.

I've tried writing an addon, but it does not work as addons have their own build system. Therefore they can't access our Meteor packages and yet they need them to work correctly.

I've tried writing a decorator. That's an okay solution but I have strange behaviour, because it runs the startup function on every component mount (that's the only way to run them after import but before render). That's my best bet currently but it seems suboptimal.

Last solution is running the code at the top of relevant stories. It works but it's error prone and affects the developer experience

So, here is the question: how would you define a callback in Storybook so that it is run during startup, like Meteor.startup callbacks do?

2 Answers

Fred Stark On Best Solutions

If you dig into it, on the client Meteor.startup is just a wrapper around document.addEventListener('DOMContentLoaded', func)

So it should be easy to replicate by listening for the event

Mikkel On

Ideally any React components that you are writing stories for should be pure render components, and should not reference anything Meteor specific, like Meteor....

The usual approach is to write a container component, which does things like loading data (eg using withTracker()), and calling any Meteor functions needed. It should pass utility functions as props to the component.

Storybook merely needs to provide these functions as props - you can use the actions add-on: https://www.npmjs.com/package/@storybook/addon-actions

Storybook Addon Actions

Storybook Addon Actions can be used to display data received by event handlers in Storybook.

At first this will seem difficult, but it's actually good practice in any environment to keep components pure. Their job is to provide rendering, and pass events to the logic and apis (which live elsewhere). It also means that the components can be re-used (even in non-meteor projects), and are easier to test, because you don't need to mockup your meteor environment)