Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] NextJS addon does not get environment variables by default #26215

Open
SalahAdDin opened this issue Feb 27, 2024 · 14 comments · May be fixed by #28395
Open

[BUG] NextJS addon does not get environment variables by default #26215

SalahAdDin opened this issue Feb 27, 2024 · 14 comments · May be fixed by #28395

Comments

@SalahAdDin
Copy link

SalahAdDin commented Feb 27, 2024

Describe the bug

We use the environment variables to set up among others, API url, base url, etc. But when launching the storybook it is unable to find the setup environment variables!

To Reproduce

Just setup and NextJS project with storybook, define any page or function to use with environment variables, create its story and run it.

System

Storybook Environment Info:

  System:
    OS: Linux 6.1 Manjaro Linux
    CPU: (16) x64 AMD Ryzen 9 5900HX with Radeon Graphics
    Shell: 5.2.26 - /bin/bash
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    Yarn: 1.22.21 - /usr/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    pnpm: 8.15.4 - /usr/bin/pnpm <----- active
  npmPackages:
    @storybook/addon-a11y: 7.6.17 => 7.6.17 
    @storybook/addon-essentials: 7.6.17 => 7.6.17 
    @storybook/addon-interactions: 7.6.17 => 7.6.17 
    @storybook/addon-links: 7.6.17 => 7.6.17 
    @storybook/addon-onboarding: 1.0.11 => 1.0.11 
    @storybook/addon-storysource: 7.6.17 => 7.6.17 
    @storybook/addon-themes: 7.6.17 => 7.6.17 
    @storybook/blocks: 7.6.17 => 7.6.17 
    @storybook/nextjs: 7.6.17 => 7.6.17 
    @storybook/react: 7.6.17 => 7.6.17 
    @storybook/test: 8.0.0-alpha.16 => 8.0.0-alpha.16 
    @storybook/theming: 7.6.17 => 7.6.17 
    eslint-plugin-storybook: 0.8.0 => 0.8.0 
    msw-storybook-addon: 2.0.0-beta.1 => 2.0.0-beta.1 
    storybook: 7.6.17 => 7.6.17 
    storybook-addon-pseudo-states: 2.1.2 => 2.1.2 
    storybook-addon-rtl: 1.0.0 => 1.0.0

Additional context

We are using Storybook as a workaround to test the pages with MSW, using the respective addon.

It could be fixed by applying this on the addon.

@shilman
Copy link
Member

shilman commented Mar 4, 2024

cc @valentinpalkovic

@valentinpalkovic
Copy link
Contributor

@SalahAdDin Have you followed the official documentation about setting up environment variables in Storybook?: https://storybook.js.org/docs/configure/environment-variables#using-storybook-configuration

@SalahAdDin
Copy link
Author

@SalahAdDin Have you followed the official documentation about setting up environment variables in Storybook?: https://storybook.js.org/docs/configure/environment-variables#using-storybook-configuration

The thing is, if we are working with NextJS, it should not require extra configuration for environment variables.

@valentinpalkovic
Copy link
Contributor

valentinpalkovic commented Mar 4, 2024

Storybook isn't an integration into Next.js, but rather it runs as a separate App. Our APIs are mainly designed in a way to be usable across different kind of frameworks and renderers. Automatically loading your environment variables or even expose process.env to the browser automatically can be seriously dangerous. For sure, we could do whatever Next.js is doing behind the scenes to provide environment variables to the client and server bundle by following specific rules, but since an universal API to support envs already exists in Storybook and it is pretty trivial to set it up (usually did once), I don’t think we will support automatic detection of env vars for Next.js

@SalahAdDin
Copy link
Author

SalahAdDin commented Mar 5, 2024

@valentinpalkovic OK, I tried to mock some of the NextJS required environment variables as the documentation says:

  env: (config) => ({
    ...config,
    NEXT_PUBLIC_API_PORT: "6006",
  }),

But it always returns undefined, and it is problematic.

Even this does not work:

Additional context

We are using Storybook as a workaround to test the pages with MSW, using the respective addon.

It could be fixed by applying this on the addon.

@jflheureux
Copy link

jflheureux commented Jun 13, 2024

I have not tried the solution mentioned in the issue. With recent Storybook main.js/ts file, it would look more like this now:

import type { StorybookConfig } from '@storybook/nextjs';
import webpack from 'webpack';

const config: StorybookConfig = {
  // All of your existing Storybook config
  webpackFinal: async (config) => {
    if (!config?.plugins) {
      return config;
    }

    config.plugins.push(
      new webpack.DefinePlugin(
        Object.keys(process.env)
          .filter((key) => key.startsWith('NEXT_PUBLIC_'))
          .reduce(
            (state, nextKey) => ({ ...state, [nextKey]: process.env[nextKey] }),
            {},
          ),
      ),
    );
    return config;
  },
};
export default config;

@SalahAdDin
Copy link
Author

I have not tried the solution mentioned in the issue. With recent Storybook main.js/ts file, it would look more like this now:

import type { StorybookConfig } from '@storybook/nextjs';
import webpack from 'webpack';

const config: StorybookConfig = {
  // All of your existing Storybook config
  webpackFinal: async (config) => {
    if (!config?.plugins) {
      return config;
    }

    config.plugins.push(
      new webpack.DefinePlugin(
        Object.keys(process.env)
          .filter((key) => key.startsWith('NEXT_PUBLIC_'))
          .reduce(
            (state, nextKey) => ({ ...state, [nextKey]: process.env[nextKey] }),
            {},
          ),
      ),
    );
    return config;
  },
};
export default config;

Does it work?

@jflheureux
Copy link

jflheureux commented Jun 13, 2024

One of my colleague just tested and this works:

  webpackFinal: async (config: Configuration) => {
    config.plugins = config.plugins || [];

    config.plugins.push(
      new DefinePlugin(
        Object.keys(process.env)
          .filter((key) => key.startsWith('NEXT_PUBLIC_'))
          .reduce(
            (acc, key) => ({
              ...acc,
              [`process.env.${key}`]: JSON.stringify(process.env[key]),
            }),
            {}
          )
      )
    );

    return config;
  },

@SalahAdDin SalahAdDin changed the title [Bug]: NextJS addon does not get environment variables by default [BUG] NextJS addon does not get environment variables by default Jun 24, 2024
@SalahAdDin
Copy link
Author

One of my colleague just tested and this works:

  webpackFinal: async (config: Configuration) => {
    config.plugins = config.plugins || [];

    config.plugins.push(
      new DefinePlugin(
        Object.keys(process.env)
          .filter((key) => key.startsWith('NEXT_PUBLIC_'))
          .reduce(
            (acc, key) => ({
              ...acc,
              [`process.env.${key}`]: JSON.stringify(process.env[key]),
            }),
            {}
          )
      )
    );

    return config;
  },

How do you manage the types? Where is the DefinePlugin type?

@shilman
Copy link
Member

shilman commented Jun 25, 2024

@valentinpalkovic I think this is something we can support easily in @storybook/next and we might as well to reduce friction for users. WDYT?

@jflheureux
Copy link

jflheureux commented Jun 25, 2024

@SalahAdDin Here are the imports for TypeScript and the code:

import type { StorybookConfig } from '@storybook/nextjs';
import { Configuration } from 'webpack';
const { DefinePlugin } = require('webpack');

const config: StorybookConfig = {
  // The rest of your configuration goes here...
  // Needed to add this so that the NEXT_PUBLIC_ env variables are available in Storybook
  webpackFinal: async (config: Configuration) => {
    config.plugins = config.plugins || [];

    config.plugins.push(
      new DefinePlugin(
        Object.keys(process.env)
          .filter((key) => key.startsWith('NEXT_PUBLIC_'))
          .reduce(
            (acc, key) => ({
              ...acc,
              [`process.env.${key}`]: JSON.stringify(process.env[key]),
            }),
            {}
          )
      )
    );

    return config;
  },
};
export default config;

@SalahAdDin
Copy link
Author

const { DefinePlugin } = require('webpack');

It requires to install the Webpack types from DefinitelyTyped, right?

@shilman shilman linked a pull request Jun 29, 2024 that will close this issue
8 tasks
@jflheureux
Copy link

I do not know where 'webpack' comes from as it is not in your package.json dependencies. It must be a dependency of Storybook. For me, webpack is located at /myproject/node_modules/webpack/types
I also guess this import code would work just as fine: import { Configuration, DefinePlugin } from 'webpack';

@SalahAdDin
Copy link
Author

I do not know where 'webpack' comes from as it is not in your package.json dependencies. It must be a dependency of Storybook. For me, webpack is located at /myproject/node_modules/webpack/types I also guess this import code would work just as fine: import { Configuration, DefinePlugin } from 'webpack';

image

We are getting this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Empathy Backlog
Development

Successfully merging a pull request may close this issue.

5 participants
@shilman @jflheureux @SalahAdDin @valentinpalkovic and others