Home > Back-end >  Does Webpack 4.41.6 polyfill for the async_hooks Node core module?
Does Webpack 4.41.6 polyfill for the async_hooks Node core module?

Time:07-16

I have a little problem with running Storybook in one of older projects. When I run Storybook with custom Webpack config, I run into an error:

ERROR in ./node_modules/asynchronous-local-storage/dist/lib/als.js
Module not found: Error: Can't resolve 'async_hooks' in 'C:\Users\Martin\Documents\censored\censored\node_modules\asynchronous-local-storage\dist\lib'

This error means, that async_hooks is not recognized. Async_hooks is a part of Node.js, which means I can't access it in a browser. However, I thought Webpack polyfills these modules. What I did was this:

config.target = "node";

But this means that the bundled code will be optimalized for Node.js and not a browser app. That's why the error is gone, and I can now run Storybook but stories from Storybook won't load due to an error in a browsers console:

Uncaught ReferenceError: exports is not defined

What I'm doing right now in the application is basically this:

let als
if (typeof window === 'undefined') {
  als = require('asynchronous-local-storage').als
}

Which should require this package, that depends on the async_hooks module only, if the environment is not a browser. However, somehow, Webpack still wants to load this core Node module, and I don't understand why. This is the Webpack config file:

const path = require('path')
const PnpWebpackPlugin = require('pnp-webpack-plugin')
const webpack = require('webpack')

module.exports = async ({ config, mode }) => {
  config.module.rules = [
    ...config.module.rules,
    ...[
      {
        test: /\.(gif|png|jpe?g|svg)$/i,
        use: [
          'file-loader',
        ],
      },
      {
        test: /\.stor[a-z] \.jsx?$/,
        loaders: [
          {
            loader: require.resolve('@storybook/source-loader'),
            options: { injectDecorator: true },
          },
        ],
        enforce: 'pre',
      },
      {
        test: /\.css$/,
        exclude: [],
        include: [/node_modules/, /src/],
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              sourceMap: false,
            },
          },
        ],
      },
      {
        test: /\.s?css$/,
        exclude: [],
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              sourceMap: false,
            },
          },
          {
            loader: 'sass-loader',
          },
        ],
      },
    ],
  ]

  config.resolve = {
    ...config.resolve,
    ...{
      extensions: [ '.mjs', '.web.js', '.js', '.json', '.web.jsx', '.jsx' ],
      alias: {
        './lodash.min': 'lodash/lodash.js',
        fs: path.join(__dirname, '..', '__mocks__', 'file.js'),
      },
      mainFields: [ 'browser', 'main' ],
    },
  }

  config.plugins.push(PnpWebpackPlugin)
  config.plugins.push(new webpack.DefinePlugin({
    'process.env.IS_BROWSER': JSON.stringify(true)
  }))

  return config
}

And just for case Babel config file:

{
  "presets": [
    "@babel/preset-react",
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": 10,
          "browsers": ["last 2 versions", "> 1%", "IE 11"]
        },
        "loose": true,
        "modules": "auto",
        "debug": true,
        "useBuiltIns": "entry"
      }
    ],
    "@babel/preset-flow"
  ],
  "retainLines": true,
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-optional-chaining"
  ]
}

I'm really having a hard time to find a way how to make this work. I looked at a lot of similar quetions but none have the exact same problem as I do.

I can't replicate the repository however, due to the project size and NDA.

Thanks

Edit: @loganfsmyth I understand, the fallback only happens for Node version <8.0.0 I guess. The project runs on 12.14.0, so async_hooks has to be used. What I don't understand, is the fact, that when I run the project (Next.js project and custom Express server) with yarn dev, the project runs fine. However, when I try to run Storybook (and Webpack builds), it fails with the Can't resolve 'async_hooks error message. This error message can be traced to the higher order component (Apollo GraphQL client wrapper). The HOC requires the async_hooks module this way:

let als
if (typeof window === 'undefined') {
  als = require('asynchronous-local-storage').als
}

The HOC is a normal .jsx component, so I'm wondering, why it does require the ALS package, even though the condition above shouldn't fulfill and ALS module shouldn't require. Can't be something done in the Webpack settings I simply missed? Thank you again :)

CodePudding user response:

I actually used IgnorePlugin, like this:

config.plugins.push(
  new IgnorePlugin({
    resourceRegExp: /async_hooks/,
  }),
)
  • Related