简体   繁体   English

无法使用 Webpack 和 React 异步加载具有可加载组件的组件

[英]Failed to asynchronously load component with loadable components using Webpack and React

The error错误

I get the following error when (what appears to be) vendor scripts that try downloading:当(似乎是)尝试下载的供应商脚本时,我收到以下错误:

index.js:1 loadable-components: failed to asynchronously load component 
{fileName: undefined, chunkName: undefined, error: 'Loading chunk 1117 failed.\n(missing: http://localhost:3002/1117.a60143c46b916ef6a52d.vendor.js)'}

I don't know if this helps but when I don't obfuscate the file names, 1117 is the node_modules styled-components script.我不知道这是否有帮助,但是当我不混淆文件名时,1117 是 node_modules styled-components 脚本。

The resource exists in the public directory in the correct output path and according to the network tab it gets downloaded successfully.该资源位于正确的 output 路径中的公共目录中,并且根据网络选项卡它已成功下载。

Script 1117.a60143c46b916ef6a52d.vendor.js  200 script  astronomix.js:1 13.5 kB 11 ms

Troubleshooting故障排除

  • I have a UI library with loadable-components exports to create the chunks.我有一个带有loadable-components导出的 UI 库来创建块。
  • The client consuming apps throw this error which started happening yesterday.客户端消费应用程序抛出昨天开始发生的这个错误。
  • I reverted the code back a few weeks for both apps and it still broke.几周前我为这两个应用程序恢复了代码,但它仍然坏了。
  • I created a quick CRA and it breaks there too.我创建了一个快速 CRA,它也在那里中断。
  • I replaced loadable-components with React.lazy and I still encountered issues.我用React.lazy替换了loadable-components ,但我仍然遇到了问题。
  • I thought there was an error with one of the components, I isolated it by creating only one component without Styled Components.我认为其中一个组件有错误,我通过仅创建一个没有样式化组件的组件来隔离它。 This breaks unless I remove code splitting.除非我删除代码拆分,否则这会中断。 Components render correctly then.然后组件正确渲染。

Webpack config Webpack 配置

const path = require('path');
const postcss = require('postcss');
const cssnano = require('cssnano');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { LicenseWebpackPlugin } = require('license-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const PUBLIC_PATH = process.env.PUBLIC_PATH || '/';

module.exports = {
  mode: 'production',
  devtool: false,
  entry: {
    library: './src/components/index.js',
  },
  output: {
    publicPath: PUBLIC_PATH,
    filename: '[name].js',
    sourceMapFilename: '[id].[contenthash].lib.map',
    chunkFilename: '[id].[contenthash].lib.js',
    path: path.resolve(__dirname, 'dist/'),
    library: 'MyLibrary', 
    libraryTarget: 'umd',
    globalObject: 'this',
    assetModuleFilename: 'images/[name].[contenthash][ext][query]',
  },
  externals: {
    react: {
      root: 'React',
      commonjs: 'react',
      commonjs2: 'react',
      amd: 'react',
    },
    'react-dom': {
      root: 'ReactDOM',
      commonjs: 'react-dom',
      commonjs2: 'react-dom',
      amd: 'ReactDOM',
    },
  },
  resolve: {
    extensions: ['.js'],
    alias: {
      react: path.resolve('./node_modules/react'),
      'react-dom': path.resolve('./node_modules/react-dom'),
    },
  },
  optimization: {
    usedExports: true,
    minimize: true,
    emitOnErrors: true,
    removeAvailableModules: true,
    concatenateModules: true,
    moduleIds: 'deterministic',
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          reuseExistingChunk: false,
          filename: (pathData) => {
            return `${pathData.chunk.id}.[contenthash].vendor.js`;
          },
        },
        default: {
          reuseExistingChunk: false,
        },
      },
    },
    minimizer: [
      new MiniCssExtractPlugin({
        filename: (pathData) => {
          return `${pathData.chunk.name}.[contenthash].min.css`;
        },
        chunkFilename: (pathData) => {
          return `${pathData.chunk.id}.[contenthash].min.css`;
        },
      }),
      new TerserPlugin({
        terserOptions: {
          format: {
            // Tell terser to remove all comments except for the banner added via LicenseWebpackPlugin.
            // This can be customized further to allow other types of comments to show up in the final js file as well.
            // See the terser documentation for format.comments options for more details.
            comments: (astNode, comment) => {
              return comment.value.startsWith('! licenses are at ');
            },
          },
          // This option was added to fix the following error in 10n6:
          // Uncaught TypeError: Super expression must either be null or a function
          keep_fnames: true,
        },
        extractComments: false, // prevents TerserPlugin from extracting a [chunkName].js.LICENSE.txt file
      }),
    ],
  },
  plugins: [
    // This makes it possible for us to safely use env vars on our code
    new webpack.DefinePlugin({
      // https://webpack.js.org/guides/public-path/#root
      'process.env.PUBLIC_PATH': JSON.stringify(PUBLIC_PATH),
    }),
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'src/vendors/**/*.css',
          to: './css/[name].[contenthash].min[ext]',
          transform: (content, path) => {
            return postcss([cssnano])
              .process(content, {
                from: path,
              })
              .then((result) => {
                return result.css;
              });
          },
        },
      ],
    }),
    new LicenseWebpackPlugin({
      addBanner: true,
      renderBanner: (filename, modules) => {
        return `/*! licenses are at ${filename}*/`;
      },
      handleMissingLicenseText: (packageName, licenseType) => {
        console.log(`No license found for ${packageName}`);
        return 'UNKNOWN';
      },
      licenseTextOverrides: {
        'styled-components':
          'https://github.com/styled-components/styled-components/blob/main/LICENSE',
        'use-onclickoutside': 'No license found',
        'use-latest': 'No license found',
        'are-passive-events-supported': 'No license found',
        'react-select':
          'MIT | https://github.com/JedWatson/react-select/blob/master/LICENSE',
      },
    }),
  ],
  module: {
    rules: [
      { oneOf: [{ type: 'javascript/auto' }] },
      {
        test: /\.(js|jsx)$/,
        exclude: [/\/node_modules\//, /\/demos\//],
        loader: 'babel-loader',
      },
      {
        test: /\.(png|jpg|jpeg|webp|gif|svg|ico)$/,
        type: 'asset/resource',
      },
      {
        test: /\.(s*)css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
      },
    ],
  },
};

Dependencies依赖项

...
"devDependencies": {
    "@babel/core": "7.18.10",
    "@babel/plugin-proposal-class-properties": "7.18.6",
    "@babel/plugin-transform-react-jsx": "7.18.10",
    "@babel/preset-env": "7.18.10",
    "@babel/preset-react": "7.18.6",
    "@loadable/component": "5.15.2",
    "@react-theming/storybook-addon": "1.1.7",
    "@storybook/addon-actions": "6.5.10",
    "@storybook/addon-console": "1.2.3",
    "@storybook/addon-docs": "6.5.10",
    "@storybook/addon-essentials": "6.5.10",
    "@storybook/addon-links": "6.5.10",
    "@storybook/addon-storyshots": "6.5.10",
    "@storybook/builder-webpack5": "6.5.10",
    "@storybook/manager-webpack5": "6.5.10",
    "@storybook/node-logger": "6.5.10",
    "@storybook/preset-create-react-app": "4.1.2",
    "@storybook/react": "6.5.10",
    "@wojtekmaj/enzyme-adapter-react-17": "0.6.7",
    "babel-jest": "28.1.3",
    "babel-loader": "8.2.5",
    "babel-plugin-styled-components": "2.0.7",
    "babel-plugin-transform-react-jsx": "6.24.1",
    "bootstrap": "5.2.0",
    "classnames": "2.3.1",
    "clean-webpack-plugin": "4.0.0",
    "copy-webpack-plugin": "11.0.0",
    "core-js": "3.24.1",
    "css-loader": "6.7.1",
    "css-minimizer-webpack-plugin": "4.0.0",
    "cssnano": "5.1.12",
    "date-fns": "2.29.1",
    "enzyme": "3.11.0",
    "enzyme-to-json": "3.6.2",
    "eslint": "8.21.0",
    "eslint-config-prettier": "8.5.0",
    "eslint-plugin-import": "2.26.0",
    "eslint-plugin-jsx-a11y": "6.6.1",
    "eslint-plugin-react": "7.30.1",
    "eslint-plugin-storybook": "0.6.3",
    "jest": "28.1.3",
    "jest-environment-enzyme": "7.1.2",
    "jest-environment-jsdom": "28.1.3",
    "jest-enzyme": "7.1.2",
    "jest-styled-components": "7.0.8",
    "license-webpack-plugin": "4.0.2",
    "mini-css-extract-plugin": "2.6.1",
    "node-sass": "7.0.1",
    "numeral": "2.0.6",
    "prettier": "2.7.1",
    "prop-types": "15.8.1",
    "ramda": "0.28.0",
    "react-bootstrap": "2.4.0",
    "react-helmet": "6.1.0",
    "react-icons": "4.4.0",
    "react-is": "18.2.0",
    "react-places-autocomplete": "7.3.0",
    "react-scripts": "5.0.1",
    "react-select": "5.4.0",
    "react-test-renderer": "17.0.2",
    "regenerator-runtime": "0.13.9",
    "sass": "1.54.2",
    "sass-loader": "13.0.2",
    "styled-components": "5.3.5",
    "terser-webpack-plugin": "5.3.3",
    "use-onclickoutside": "0.4.1",
    "webpack": "5.74.0",
    "webpack-cli": "4.10.0"
  },
  "peerDependencies": {
    "react": "17.0.2",
    "react-dom": "17.0.2"
  }
...

Code splitting代码拆分

import loadable from '@loadable/component';

global.SC_DISABLE_SPEEDY = true;

export const Theme = loadable(() => import('./Theme'), {
  resolveComponent: (component) => component.default,
});

...

Other其他

Related question but did not assist in solving the problem loadable-components: failed to asynchronously load component .相关问题但没有帮助解决问题loadable-components: failed to asynchronously load component Let me know if you need anything else.需要帮助请叫我。


Edits编辑

Stacktrace堆栈跟踪

Uncaught ChunkLoadError: Loading chunk 2526 failed.
(missing: http://localhost:3002/2526.4c1d9fbd8f9d0aa16a08.vendor.js)
    at __webpack_require__.f.j (library.js:1:1)
    at library.js:1:1
    at Array.reduce (<anonymous>)
    at __webpack_require__.e (library.js:1:1)
    at h.resolveComponent [as requireAsync] (library.js:1:1)
    at cachedLoad (library.js:1:1)
    at InnerLoadable.resolveAsync (library.js:1:1)
    at InnerLoadable.loadAsync (library.js:1:1)
    at InnerLoadable.componentDidMount (library.js:1:1)
    at commitLifeCycles (react-dom.development.js:20663:1)
    at commitLayoutEffects (react-dom.development.js:23426:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
    at invokeGuardedCallback (react-dom.development.js:4056:1)
    at commitRootImpl (react-dom.development.js:23151:1)
    at unstable_runWithPriority (scheduler.development.js:468:1)
    at runWithPriority$1 (react-dom.development.js:11276:1)
    at commitRoot (react-dom.development.js:22990:1)
    at performSyncWorkOnRoot (react-dom.development.js:22329:1)
    at scheduleUpdateOnFiber (react-dom.development.js:21881:1)
    at updateContainer (react-dom.development.js:25482:1)
    at react-dom.development.js:26021:1
    at unbatchedUpdates (react-dom.development.js:22431:1)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:26020:1)
    at Object.render (react-dom.development.js:26103:1)
    at Module.<anonymous> (index.js:5:1)
    at ./src/index.js (index.js:7:1)
    at __webpack_require__ (bootstrap:851:1)
    at fn (bootstrap:150:1)
    at 1 (index.js:7:1)
    at __webpack_require__ (bootstrap:851:1)
    at checkDeferredModules (bootstrap:45:1)
    at Array.webpackJsonpCallback [as push] (bootstrap:32:1)
    at main.chunk.js:1:71

I deleted the node_modules in the library directory and then reinstalled with npm install .我删除了库目录中的node_modules ,然后用npm install重新安装。 I believe the cached node modules must have gone wonky with the numerous git reverts I made.我相信缓存的节点模块一定会因为我所做的众多 git 恢复而变得不稳定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM