npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tramvai/storybook-addon

v6.82.23

Published

Storybook addon for tramvai apps

Readme

@tramvai/storybook-addon

Storybook addon for tramvai apps

Installation

You need to install @tramvai/storybook-addon:

npm install @tramvai/storybook-addon

And connect addon in the storybook configuration file:

module.exports = {
  addons: ['@tramvai/storybook-addon'],
};

Features

  • Providers for DI container
  • Providers for router
  • Providers for react-query
  • Page actions support
  • tramvai babel configuration
  • tramvai postcss configuration

Webpack plugin only

In some cases, adding the addon may be difficult due to conflicts.

In such situations, you can use only the webpack plugin from the addon:

// .storybook/main.js
import { webpackFinal } from '@tramvai/storybook-addon';

export default {
  webpackFinal,
};

Or if you have your own webpack overrides:

// .storybook/main.js
import { webpackFinal as tramvaiWebpackFinal } from '@tramvai/storybook-addon';

export default {
  webpackFinal: async (config) => {
    const webpackConfig = await tramvaiWebpackFinal(config);

    // Do something with config
    webpackConfig.optimization = {
      minimize: false,
    };

    return webpackConfig;
  },
};

We strongly recommend to use at least tramvai webpack plugin in storybook tests.

Webpack build optimization

We recommend configuring selective transpilation of node_modules for the webpack build that Tramvai performs by default. To do this, use the include option in the addon/webpack config options.

This significantly speeds up the build (up to 2x with Babel).

By default, the value only-modern is used, which, based on certain heuristics, tries to apply transpilation only to modern dependencies.

We recommend using the value none to completely skip node_modules transpilation:

const webpackConfig = await tramvaiWebpackFinal(config, { include: 'none' });

Also, for the storybook addon:

export default = {
  addons: {
    name: '@tramvai/storybook-addon',
    options: {
      include: 'none'
    },
  }
}

If you encounter issues, specify the list of dependencies to transpile as an array:

const webpackConfig = await tramvaiWebpackFinal(config, { include: ['@tramvai/module-dev-tools'] });

Babel configuration

You can also use only the Babel config from the Tramvai plugin, but in that case you must implement all the missing build machinery for Tramvai by yourself:

import { babel } from '@tramvai/storybook-addon';

export default {
  webpackFinal: (config) => {
    // Find babel rule you want to update
    const babelRule = config.module.rules.find(({ use }) =>
      use?.find(({ loader }) => loader.includes('babel-loader'))
    );

    const tramvaiBabelOptions = babel(config);
    Object.assign(babelRule.use[0].options, tramvaiBabelOptions);

    return config;
  },
};

How to

Access to DI container

import { LOGGER_TOKEN } from '@tramvai/tokens-common';

export const Page = () => {
  const logger = useDi(LOGGER_TOKEN);

  logger.info('render');

  return <h1>Page</h1>;
};
import type { TramvaiStoriesParameters } from '@tramvai/storybook-addon';
import { Page } from './page';

// You can pass to DI container any reducers, providers and modules
const parameters: TramvaiStoriesParameters = {
  tramvai: {
    stores: [],
    initialState: {},
    providers: [],
    modules: [],
  },
};

export default {
  title: 'Page',
  component: Page,
  parameters,
};

export const PageStory = () => <Page />;

Router hooks and components

import { Link, useUrl } from '@tramvai/module-router';

export const Page = () => {
  const url = useUrl();

  return (
    <>
      <h1>Page at {url.pathname}</h1>
      <p>
        <Link url="/third/">to third page</Link>
      </p>
    </>
  );
};
import type { TramvaiStoriesParameters } from '@tramvai/storybook-addon';
import { Page } from './page';

// You can pass to router current route and url
const parameters: TramvaiStoriesParameters = {
  tramvai: {
    currentRoute: { name: 'second', path: '/second/' },
  },
};

export default {
  title: 'Page',
  component: Page,
  parameters,
};

export const PageStory = () => <Page />;

React Query

import { createQuery, useQuery } from '@tramvai/react-query';

const query = createQuery({
  key: 'base',
  fn: async () => {
    return { foo: 'bar' };
  },
});

export const Page = () => {
  const { data, isLoading } = useQuery(query);

  return (
    <>
      <h1>Page</h1>
      <p>{isLoading ? 'Loading...' : data.foo}</p>
    </>
  );
};
import type { TramvaiStoriesParameters } from '@tramvai/storybook-addon';
import { Page } from './page';

// You can pass to router QueryClient default options
const parameters: TramvaiStoriesParameters = {
  tramvai: {
    reactQueryDefaultOptions: {
      queries: {
        refetchOnMount: false,
        refetchOnReconnect: false,
        refetchOnWindowFocus: false,
      },
    },
  },
};

export default {
  title: 'Page',
  component: Page,
  parameters,
};

export const PageStory = () => <Page />;

Page actions running

import { declareAction } from '@tramvai/core';

const serverAction = declareAction({
  name: 'server-action',
  fn() {
    console.log('server action');
  },
  conditions: {
    onlyServer: true,
  },
});

const browserAction = declareAction({
  name: 'browser-action',
  fn() {
    console.log('browser action');
  },
  conditions: {
    onlyBrowser: true,
  },
});

export const Page = () => {
  return <h1>Page</h1>;
};

Page.actions = [serverAction, browserAction];
import type { TramvaiStoriesParameters } from '@tramvai/storybook-addon';
import { Page } from './page';

// Actions with `onlyBrowser` condition will be executed
const parameters: TramvaiStoriesParameters = {
  tramvai: {
    actions: Page.actions,
  },
};

export default {
  title: 'Page',
  component: Page,
  parameters,
};

export const PageStory = () => <Page />;

Http clients with real requests

import { declareAction } from '@tramvai/core';

const httpRequestAction = declareAction({
  name: 'http-request-action',
  async fn() {
    return this.deps.httpClient.get('/');
  },
  deps: {
    httpClient: HTTP_CLIENT,
  },
});

export const Page = () => {
  return <h1>Page</h1>;
};

Page.actions = [httpRequestAction];
import { HttpClientModule } from '@tramvai/module-http-client';
import type { TramvaiStoriesParameters } from '@tramvai/storybook-addon';
import { Page } from './page';

// HttpClientModule is required for real requests
const parameters: TramvaiStoriesParameters = {
  tramvai: {
    actions: Page.actions,
    modules: [HttpClientModule],
  },
};

export default {
  title: 'Page',
  component: Page,
  parameters,
};

export const PageStory = () => <Page />;

How to provide environment variables?

This addon provides a few important defaults:

  • Mock provider for ENV_MANAGER_TOKEN
  • Read env.development.js content from application root

So, any variables from env.development.js will be registered in envManager.

If you want to add custom variables for some stories, pass options for CommonTestModule (from @tramvai/test-mocks package) in story parameters:

const parameters: TramvaiStoriesParameters = {
  tramvai: {
    options: {
      env: {
        FOO: 'BAR',
      },
    },
  },
};

Troubleshooting

"Rendered more hooks than during the previous render."

In case of using both fastRefresh and strictMode in reactOptions in Storybook config in main.js, you might see the error message above.

This is a known issue in Storybook itself, as a temporary workaround you can simply disable the strictMode in Storybook config.

Won't work:

module.exports = {
  reactOptions: {
    fastRefresh: true,
    strictMode: true,
  },
};

Works:

module.exports = {
  reactOptions: {
    fastRefresh: true,
  },
};

Contribute

For testing changes in this plugin locally, you need a few steps:

  1. [tramvai repo] Copy examples-standalone/storybook application to different folder, e.g. storybook-app
  2. [storybook-app] run git init in this folder (@storybook/builder-webpack5 uses as root the first parent directory containing .git folder)
  3. [storybook-app] Update there all tramvai dependencies in package.json
  4. [tramvai repo] Copy plugin build output from packages/tramvai/storybook-addon/lib
  5. [storybook-app] Paste into the storybook-app/node_modules/@tramvai/storybook-addon/lib folder
  6. [storybook-app] Run storybook in nested folder cd storybook && npm run storybook