Webpack 4.41.6是否为async_hooks Node核心模块填充(polyfill)呢?

3

我在一个老项目中运行Storybook时遇到了一些小问题。当我使用自定义的Webpack配置运行Storybook时,出现了一个错误:

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'

这个错误意味着无法识别async_hooks。Async_hooks是Node.js的一部分,这意味着我无法在浏览器中访问它。然而,我认为Webpack可以填充这些模块。我的做法如下:

config.target = "node";

但这意味着捆绑的代码将针对 Node.js 进行优化,而不是浏览器应用程序。这就是为什么错误已经消失,我现在可以运行 Storybook 了,但是由于浏览器控制台中的错误,Storybook 中的故事无法加载:

Uncaught ReferenceError: exports is not defined

我现在在应用程序中所做的基本上是这样的:

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

如果环境不是浏览器,那么只有依赖于async_hooks模块的包才需要这个包。然而,不知何故,Webpack仍然想要加载这个核心Node模块,我不明白为什么。这是Webpack配置文件:

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
}

还有针对 Babel 配置文件的情况:

{
  "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"
  ]
}

我真的很难找到解决方法,想知道如何使它工作。我查看了很多类似的问题,但没有一个与我的问题完全相同。

由于项目大小和NDA,我无法复制存储库。

谢谢

编辑: @loganfsmyth 我明白了,回退只适用于Node版本 <8.0.0。该项目在12.14.0上运行,因此必须使用async_hooks。我不理解的是,当我使用yarn dev运行项目(Next.js项目和自定义Express服务器)时,项目可以正常运行。但是,当我尝试运行Storybook(和Webpack构建)时,它会失败并显示Can't resolve 'async_hooks错误消息。这个错误消息可以追溯到高阶组件(Apollo GraphQL客户端包装器)。HOC以这种方式要求async_hooks模块:

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

HOC是一个普通的.jsx组件,所以我想知道为什么它需要ALS包,尽管上面的条件不应该满足,也不应该需要ALS模块。难道我在Webpack设置中漏掉了某些东西吗?再次感谢:)


1
asynchronous-local-storage 模块的文档中写道:“对于旧版 Node.js,可以回退到 cls-hooked。”因此,不管怎样这个模块在浏览器中也无法工作,它只是为了支持旧版 Node.js。浏览器无法填充此 async_hooks 模块。这是该模块被标记为实验性的一个重要原因:https://nodejs.org/api/documentation.html#stability-index - loganfsmyth
@loganfsmyth 感谢您的回答,我根据您的说明更新了我的问题。 - Martin Choutka
1个回答

2

我实际上使用了IgnorePlugin,像这样:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接