gatsby: Importing Link from gatsby breaks Storybook

Storybook breaks (https://github.com/gatsbyjs/gatsby/issues/10662) if a component includes import { Link } from 'gatsby'

This was working fine before https://github.com/gatsbyjs/gatsby/pull/9123 because

  • main was an es6 build
  • webpack would treeshake when Link was imported

Now that main is a commonjs build and the ES6 build is at module, it breaks since

  • the commonjs entry point at gatsby-browser-entry.js requires public-page-renderer
  • which tries to require pages.json
  • which doesn’t exist because since presumably a gatsby build hasn’t been run yet

public-page-renderer.js looks like

if (process.env.BUILD_STAGE === `develop`) {
  module.exports = preferDefault(require(`./public-page-renderer-dev`))
} else if (process.env.BUILD_STAGE === `build-javascript`) {
  module.exports = preferDefault(require(`./public-page-renderer-prod`))
} else {
  module.exports = () => null
}

I assumed that this would work since BUILD_STAGE is not set but it seems webpack wants to resolve both calls to require

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 36 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I was having the issue where I was receiving the __BASE_PATH__ error when using the Link component from gatsby inside another component inside that component’s story

Though the docs doesn’t specifically mention __BASE_PATH__, I was able to resolve this by adding:

// .storybook/preview.js
global.__BASE_PATH__ = '';

Similar to how in the docs they mention to add:

// .storybook/preview.js
global.__PATH_PREFIX__ = '';

https://www.gatsbyjs.org/docs/visual-testing-with-storybook/#storybook-version-5

Hope that helps someone else 😃

Same issue here.

In my environment, I can workaround to use gatsby-link

// import { Link } from "gatsby" // error 
import Link from "gatsby-link" // not error 

Same issue here.

In my environment, I can workaround to use gatsby-link

// import { Link } from "gatsby" // error 
import Link from "gatsby-link" // not error 

This workaround also solves my problem.

@Levino I tried nohoist and I have gatsby in the child’s (common component’s) node_modules.

stencils/common-components/kenekt-helper/node_modules/gatsby on  master [⇡!] is 📦 v2.19.49 via ⬢ v12.16.1
➜

I still get the following when I import gatsby…


kenekt-helper: ERROR in ../node_modules/gatsby/cache-dir/gatsby-browser-entry.js 25:4
kenekt-helper: Module parse failed: Unexpected token (25:4)
kenekt-helper: You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
kenekt-helper: |
kenekt-helper: |   return (
kenekt-helper: >     <React.Fragment>
kenekt-helper: |       {finalData && render(finalData)}
kenekt-helper: |       {!finalData && <div>Loading (StaticQuery)</div>}

Same issue here. In my environment, I can workaround to use gatsby-link

// import { Link } from "gatsby" // error 
import Link from "gatsby-link" // not error 

This workaround also solves my problem.

Tried this solution but got:

__PATH_PREFIX__ is not defined
ReferenceError: __PATH_PREFIX__ is not defined
    at withPrefix (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:74828:80)
    at GatsbyLink.render (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:74970:22)
    at finishClassComponent (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:162866:31)
    at updateClassComponent (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:162816:24)
    at beginWork (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:164335:16)
    at HTMLUnknownElement.callCallback (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:145870:14)
    at Object.invokeGuardedCallbackDev (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:145919:16)
    at invokeGuardedCallback (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:145974:31)
    at beginWork$1 (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:168916:7)
    at performUnitOfWork (http://localhost:62911/vendors~main.3925691bc29e63af178f.bundle.js:167867:12)

For me the issue was related to using Yarn Workspaces to develop my Gatsby theme and nesting it within the Gatsby package. The Webpack config runs in the root of the current package, in this case my Gatsby theme directory/ Yarn Workspace. My node_modules/gatsby files that need transpiling are actually in a parent directory. The code in the guide doesn’t consider this scenario, so I needed to update the config to point to the correct directory. Adding the following to my Storybook webpack config did the trick:

// Since we're using Yarn Workspaces and nesting the packages, we need to include the parent package
config.module.rules[0].include = require('path').resolve('../..');

Having this same issue with Storybook v6 and the recommended settings from Gatsby’s tutorial.

Unfortunately, I was only able to make it work switching to gatsby-link, what I find not that great 😦

@tevla I think it should be import { navigate } from "gatsby-link". It works fine here both for Storybook and Gatsby.

Gatsby has some useful information on how to tweak the Storybook config to make it work https://www.gatsbyjs.org/docs/visual-testing-with-storybook/.

However, since Storybook’s config files have changed in version 5.3, and Gatsby’s documentation isn’t up to date yet, the stuff they say should go into ./storybook/config.js should actually go into ./storybook/preview.js. And the things they say should go into .storybook/webpack.config.js should actually go into the webpackFinal option of .storybook/main.js.

But otherwise it was mostly copy and paste.

Why is this issue closed? Its is an issue related to creating a common lib, adding gatsby to it and importing ‘Link’ (or anything else). Its quite simple to reproduce as well. Am I missing something? It is not a Story book related issue. Its for all shared libs where gatsby is used.

It effectively stops us from using gatsby in a common lib. We have 3 templates and common/shared libs across the templates. https://share.getcloudapp.com/p9uKLEkK

Importing ‘gatsby-link’ also does not work for the reasons mentioned above by @salatielq .

Env Lerna: 3.20.2 gatsby-cli: 2.10.10 gatsby: 2.19.41 Node: 12.16.1 - ~/.nvm/versions/node/v12.16.1/bin/node Yarn: 1.22.4 - ~/.yarn/bin/yarn npm: 6.14.2 - ~/.nvm/versions/node/v12.16.1/bin/npm

Webpack:

  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env', '@babel/react'],
              plugins: ["transform-class-properties"]
            }
          }
        ],
        include: [
          path.resolve(__dirname, "src")
        ],
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
          },
        ],
        include: path.resolve(__dirname, "src"),
        exclude: /node_modules/
      }
    ]
  },

Using link from @reach/router solved my problem, like this

import { Link } from "@reach/router";

I applied the fix but now I get this error:

WARNING in ./node_modules/gatsby/cache-dir/page-renderer.js 41:24-33
"export 'apiRunner' was not found in './api-runner-browser'
 @ ./node_modules/gatsby/cache-dir/public-page-renderer-prod.js
 @ ./node_modules/gatsby/cache-dir/public-page-renderer.js
 @ ./node_modules/gatsby/cache-dir/gatsby-browser-entry.js

I think these lines in Visual Testing with Storybook - Storybook version 5 are problematic because it makes an assumption about the order of the Webpack rules.

Namely, it doesn’t take into consideration if you have other add-ons that also change the rules. In my case, this is happening because I use @storybook/preset-create-react-app@2.1.2, which modifies these rules before the webpackFinal callback runs.

If I had a vanilla Storybook webpack configuration, using the latest v5 (v5.3.21), the config should output the following module.rules:

module: {
  rules: [
    {
      test: /\.(mjs|jsx?)$/,
      use: [
        {
          loader: 'babel-loader',
          options: babelOptions,
        },
      ],
      include: [path.resolve('./')],
      exclude: [path.resolve('./node_modules')],
    },
    {
      test: /\.md$/,
      use: [
        {
          loader: require.resolve('raw-loader'),
        },
      ],
    },
  ],
}

However, after @storybook/preset-create-react-app executes, my module.rules webpack config looks like this (several items below have been pruned / edited so it fits better in this comment):

module: {
  rules: [
    {
      test: /\.md$/,
      use: ['raw-loader'],
    },
    { parser: { requireEnsure: false } },
    {
      test: /\.(js|mjs|jsx|ts|tsx)$/,
      enforce: 'pre',
      use: ['eslint-loader'],
      include: ['~/src', '~/.storybook'],
    },
    {
      oneOf: [
        {
          test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
          loader: 'url-loader',
        },
        {
          test: /\.(js|mjs|jsx|ts|tsx)$/,
          include: ['~/src', '~/.storybook'],
          loader: 'babel-loader',
          options: { /* ... */ }
        },
        {
          test: /\.(js|mjs)$/,
          exclude: /@babel(?:\/|\\{1,2})runtime/,
          loader: 'babel-loader',
          options: { /* ... */ },
          include: ['~/.storybook'],
        },
        { test: /\.css$/, /* ... */ },
        { test: /\.module\.css$/, /* ... */ },
        { test: /\.(scss|sass)$/, /* ... */ },
        { test: /\.module\.(scss|sass)$/, /* ... */ },
        {
          exclude: [
            /\.(js|mjs|jsx|ts|tsx)$/,
            /\.html$/,
            /\.json$/,
            /\.(ejs|md|mdx)$/,
          ],
          loader: 'file-loader',
          options: { /* ... */ },
        },
      ],
    },
    {
      test: /\.js$/,
      include: /node_modules\/acorn-jsx/,
      use: ['babel-loader'],
    },
    { test: /\.(stories|story).mdx$/, /* ... */ },
    {
      test: /\.mdx$/,
      exclude: /\.(stories|story).mdx$/,
      // ...
    },
    {
      test: /\.(stories|story)\.[tj]sx?$/,
      loader: '@storybook/source-loader',
      // ...
    },
  ],
}

I got this configuration by running yarn storybook --debug-webpack per the docs.

Importantly, @storybook/preset-create-react-app moves all “non JS” rules to the front when it finally returns a webpack config. Since we only have two rules before (the /\.(mjs|jsx?)$/ and the /\.md$/ one), this effectively moves the /\.md$/ rule to the front of our array.

So, when making modifications to the rules first item via:

// Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
// use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
config.module.rules[0].use[0].loader = require.resolve("babel-loader")
// use @babel/preset-react for JSX and env (instead of staged presets)
config.module.rules[0].use[0].options.presets = [
    require.resolve("@babel/preset-react"),
    require.resolve("@babel/preset-env"),
]
config.module.rules[0].use[0].options.plugins = [
    // use @babel/plugin-proposal-class-properties for class arrow functions
    require.resolve("@babel/plugin-proposal-class-properties"),
    // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
    require.resolve("babel-plugin-remove-graphql-queries"),
]

config.module.rules[0] is not the rule concerning how JS-related files are loaded, and instead we are making changes to how Markdown files are loaded!


I’m not 100% sure how to change the webpackFinal(config) callback to address this, but either way, if you use @storybook/preset-create-react-app, the instructions given will not work as they are intended!

@turistua

project/
+-- gastby-theme-mytheme/
|   +-- .storybook/
|   |   +-- main.js
|   +-- gatsby-config.js
+-- node_modules/
|   +-- gatsby/

@terrierscript’s solution works nicely. but this is still an issue