A single message once a month containing the latest mixtape, insights, and observations.

Setting up Storybook & NextJS

As part of redoing my personal website, I integrated NextJs with the latest version of Storybook. Recently there has been a fair amount of changes with both, so here are a couple of the quirks I ran into.

NextJS publicRuntimeConfig

I didn't want to mock any API calls in Storybook, so I had to access the keys in my .env, which in NextJS is common to use the publicRuntimeConfig. I didn't see this in the documentation, but you can use setConfig to achieve this.

.storybook/main.js
const path = require('path');
const Dotenv = require('dotenv-webpack');

module.exports = {
  webpackFinal: async (config) => {
    config.plugins.push(
      new Dotenv({
        path: path.resolve(__dirname, '../.env'),
      })
    );

    return config;
  }
},

Then update the Storybook preview config.

.storybook/preview.js
import { setConfig } from 'next/config';

const {
  WEATHER_API_KEY,
} = process.env;

// set NextJS Config
setConfig({
  publicRuntimeConfig: {
    WEATHER_API_KEY,
  },
});

As of NextJS version 9.4, you no longer have to use publicRuntimeConfig. Instead, you can add an env object to your next.config.js and access any process.env.* variable.

NextJS 'No router instance found.'

If you are using next/link, you will encounter this error in the console.

Uncaught Error: No router instance found.

The simplest solution is adding a decorator using the storybook-addon-next-router package.

.storybook/preview.js
import { addDecorator } from '@storybook/react';
import { withNextRouter } from 'storybook-addon-next-router';

addDecorator(withNextRouter());

Storybook a11y add-on

As of writing this post, the documentation for this is incorrect in a few places. I had to piece together a couple of GitHub issues to figure out the proper implementation. You must both add the plugin to the add-on list and use a decorator.

.storybook/main.js
addons: [..., '@storybook/addon-a11y'],
.storybook/preview.js
import { addDecorator } from '@storybook/react';
import { withA11y } from '@storybook/addon-a11y';

addDecorator(withA11y);

Adding emotion Global styles

The solution is the same, whether you are using styled-components or emotion.

.storybook/preview.js
import { addDecorator } from '@storybook/react';
import { Global } from '@emotion/core';
// your global stylesheet may be named different
import { Styles } from 'styles/global'; 

addDecorator((storyFn) => (
  <div style={{
    margin: '0',
    height: '100vh',
  }}>
    <Global styles={Styles} />

    {storyFn()}
  </div>
));

References

Published on 2020-05-19

Word count 366

Read time 2 minutes

#dev, #nextjs, #storybook,