Storybook + Meteor packages

I would love to use Storybook for my React components (http://storybook.js.org) but a big issue is that because I use a package-based architecture, all my components rely on Meteor packages. For example:

import { Components, registerComponent, withList, withCurrentUser, Utils } from 'meteor/vulcan:core';
import React from 'react';
import PropTypes from 'prop-types';
import Posts from 'meteor/vulcan:posts';

const MyComponent = ...

export default MyComponent;

Storybook doesn’t know what meteor/vulcan:posts or meteor/vulcan:core are, since they’re not NPM packages, so it can’t handle that component.

Is there any workaround? If not, could something be implemented in an upcoming version of Meteor to make this work? I would love to get @benjamn or @abernix’s feedback on this.

1 Like

This would be such a great thing to make happen. But seems a little tough since Meteor and Webpack dont necessarily play well together. Maybe client bundler can help?

Did you give MDG’s chromatic a try? t had fallen behind for quite some time but has been updated very recently so should work with recent Meteor versions.

I think Chromatic is an awesome product, but to be honest for an open-source app I’d rather use standard libraries like Storybook that people might already be familiar with, and that are part of a larger ecosystem.

1 Like

Someone suggested using this: https://github.com/stphdenis/meteor-webpack-client

I don’t know enough about Webpack and Storybook to know if it would work yet, but it might be worth exploring.

It’s an old thread, but I run into the similar issue. So thought it might help someone. I usually try to make components without any Meteor logic and then wrap it in a separate file, so I could play around with storybook. In some cases there are still some dependences, but then I mock these dependences.

To do that, you need to setup webpack. This is how my .storybook/main.js file looks like:

const webpack = require('webpack');
const path = require('path');

module.exports = {
  stories: ['../stories/**/*.stories.jsx'],
  addons: ['@storybook/addon-actions', '@storybook/addon-knobs'],
  webpackFinal: async (config) => {
    config.plugins.push(new webpack.NormalModuleReplacementPlugin(
      /^meteor/,
      resource => {
        // Gets absolute path to mock `meteor` packages
        const absRootMockPath = path.resolve(
          __dirname,
          "../__mocks__/meteor",
        );

        // Gets relative path from requesting module to our mocked module
        const relativePath = path.relative(
          resource.context,
          absRootMockPath,
        );

        // Updates the `resource.request` to reference our mocked module instead of the real one
        resource.request = resource.request.replace(/meteor/, relativePath);
      },
    ));

    // Return the altered config
    return config;
  },
};

Then it’s up to you to mock your dependences, which should be stored in __mock__/meteor folder.

5 Likes