storybookjs / require-context.macro

🖇 A Babel macro needed for some advanced Storybook setups. Used to mock webpack's context function in test environments.
MIT License
48 stars 8 forks source link

Module not found: Error during Netlify build (can't resolve 'fs' in ...../require-context.macro) #25

Open RichardPK opened 4 years ago

RichardPK commented 4 years ago

Everything works when running the Storybook instance locally (and in fact when deploying to Github pages), but I am getting an error during the Storybook build process on Netlify:

Module not found: Error: Can't resolve 'fs' in '/opt/build/repo/node_modules/require-context.macro'
10:05:04 AM: (node:1297) UnhandledPromiseRejectionWarning: ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in '/opt/build/repo/node_modules/require-context.macro'

I am running this with NODE_ENV variable set to test within Netlify, as I was previously getting this error:

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: [BABEL] /opt/build/repo/.storybook/addons.js: `babel-preset-gatsby` has been loaded, which consumes config generated by the Gatsby CLI. Set `NODE_ENV=test` to bypass, or run `gatsby build` first. 

My .babelrc file:


{
  "plugins": ["macros"],
  "presets": ["babel-preset-gatsby"]
}

My webpack.config.js file:

module.exports = ({ config }) => {
  config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]

  config.module.rules[0].use[0].loader = require.resolve("babel-loader")
  config.module.rules[0].use[0].loader.options = { babelrc: true }

  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 = [
    require.resolve("@babel/plugin-proposal-class-properties"),
    require.resolve("babel-plugin-remove-graphql-queries"),
  ]

  config.resolve.mainFields = ["browser", "module", "main"]

  return config
}

I realise this is unique to Netlify and I actually have a deployment workaround via Github Pages, just putting this here to try and expand my understanding and figure out what is going on.

kylemh commented 4 years ago

Where do you actually call the macro?

RichardPK commented 4 years ago

/storybook/config.js

kylemh commented 4 years ago

Can you show that code please?

RichardPK commented 4 years ago

Apologies Kyle - that was terribly unhelpful of me. /storybook/config.js below

import React from "react"
import { configure, addDecorator } from "@storybook/react"
import { withKnobs, select } from "@storybook/addon-knobs"
import { action } from "@storybook/addon-actions"
import StorybookGlobalStyle from "../src/global-styles/StorybookGlobalStyle"
import Colors from "../src/consts/Colors"
import requireContext from "require-context.macro"

const req = requireContext("../src", true, /.stories.js$/)

function loadStories() {
  req.keys().forEach(filename => {
    req(filename)
  })
}

window.matchMedia =
  window.matchMedia ||
  function() {
    return {
      matches: false,
      addListener: function() {},
      removeListener: function() {},
    }
  }

addDecorator((story, { parameters }) => {
  const label = "Background color"
  const options = {
    Black: Colors.primaryBlack,
    White: Colors.white,
    Grey: Colors.grey,
  }
  let defaultValue = options.Black
  const groupId = "Universal"
  if (parameters.storybookBackground) {
    switch (parameters.storybookBackground) {
      case "white":
        defaultValue = options.White
        break
      case "black":
        defaultValue = options.Black
        break
      case "grey":
        defaultValue = options.Grey
        break
      default:
        break
    }
  }

  const value = select(label, options, defaultValue, groupId)

  return (
    <>
      <StorybookGlobalStyle htmlColor={value} />
      {story()}
    </>
  )
})

addDecorator(
  withKnobs({
    escapeHTML: false,
  })
)

global.___loader = {
  enqueue: () => {},
  hovering: () => {},
}

global.__PATH_PREFIX__ = ""

window.___navigate = pathname => {
  action("NavigateTo:")(pathname)
}
configure(loadStories, module)
kylemh commented 4 years ago

That looks fine.

Back to your webpack config (this is .storybook/webpack.config.js right?), I'm a little concerned because you're using babelrc, but then you attempt to override it, yet the Gatsby preset still shows up in the build.

I'd try to refactor your Storybook config to be immutable. Maybe even drop the babelrc integration for a second.

RichardPK commented 4 years ago

Hey Kyle,

Yep .storybook/webpack.config.js is the config.

Deleting the babelrc file creates the following errors when running Storybook (all relating to the macro):

Module not found: Error: Can't resolve 'fs' in '/Users/rpk/Coding/neu_codebase/studio/neu-neu-site/node_modules/cosmiconfig/dist'

Module not found: Error: Can't resolve 'fs' in '/Users/rpk/Coding/neu_codebase/studio/neu-neu-site/node_modules/resolve/lib'

Module not found: Error: Can't resolve 'fs' in '/Users/rpk/Coding/neu_codebase/studio/neu-neu-site/node_modules/resolve/lib'

Module not found: Error: Can't resolve 'module' in '/Users/rpk/Coding/neu_codebase/studio/neu-neu-site/node_modules/resolve-from'

And then under each:

...
...
...
 @ ./node_modules/babel-plugin-macros/dist/index.js
 @ ./node_modules/require-context.macro/require-context.macro.js
 @ ./.storybook/config.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true

I take your point about using a babelrc is confusing things here - though don't have enough knowledge to understand how refactoring my webpack config might help.

Is there a way for me to incorporate plugin & preset loading into .storybook/webpack.config.js?

kylemh commented 4 years ago

Lemme try and break it down for ya! I'm gonna close this cuz I'm certain it's not an issue with the macro and just how you've configured things, but I'll keep this issue's notifications on and we can parse thru it!

module.exports = ({ config }) => {
  config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]

  // You're forcing that the first loader is gonna be `babel-loader`
  config.module.rules[0].use[0].loader = require.resolve("babel-loader")

  // Now you're defining that loader's options (indicating that you're using a babelrc file)
  config.module.rules[0].use[0].loader.options = { babelrc: true }

  // In these next two blocks, you're overriding the presets/plugins from babel-loader... 
  // This is what concerns me most because these will conflict with what you've defined in your babelrc
  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 = [
    require.resolve("@babel/plugin-proposal-class-properties"),
    require.resolve("babel-plugin-remove-graphql-queries"),
  ]

  config.resolve.mainFields = ["browser", "module", "main"]

  return config
}

You have a .babelrc file that looks like this:

{
  "plugins": ["macros"],
  "presets": ["babel-preset-gatsby"]
}

Can you make it into what you're trying to do in your babel config, and tell me what happens then?

{
  "plugins": [
    "macros",
    "@babel/plugin-proposal-class-properties",
    "babel-plugin-remove-graphql-queries"
  ],
  "presets": ["@babel/preset-env", "@babel/preset-react", "babel-preset-gatsby"]
}
kylemh commented 4 years ago

Hey now i'm getting the same thing 😅

Looks like CSF + Storyshots isn't quite yet ironed out. I don't think the macro is the issue, but I'll be trying to work with the Storybook team to get this resolved ASAP (especially since it's affecting me now 😂 )

RichardPK commented 4 years ago

Aha thank you @kylemh maybe there's something else at play here!

Regardless - thanks for your time to explain what's going on in the config - that all makes sense. I'll have a play around with pushing those into .babelrc and out of the config.module.rules[0].use[0].options.presets object assignment within the config.