[英]ChunkLoadError: Loading chunk XY failed. - Randomly getting fatal on PRODUCTION
we have got our ecommerce platform already in production and we are experiencing weird ChunkLoadError.我们的电子商务平台已经投入生产,我们遇到了奇怪的 ChunkLoadError。 This error happens randomly, and is not replicable.此错误随机发生,不可复制。 When we are trying to open failed file it is there and can be loaded normaly.当我们尝试打开失败的文件时,它就在那里并且可以正常加载。
If user get's this error, he get's white screen (logicaly) but after refresh everything is fine.如果用户得到这个错误,他得到的白屏(逻辑)但刷新后一切正常。
We are running SSR ecommerce on React (latest), Express (latest)我们在 React(最新)、Express(最新)上运行 SSR 电子商务
our webpack / razzle config我们的 webpack / razzle 配置
const path = require('path');
const autoprefixer = require('autoprefixer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const LoadablePlugin = require('@loadable/webpack-plugin');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const TerserPlugin = require('terser-webpack-plugin');
// const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin');
module.exports = {
modify: (baseConfig, env, webpack) => {
const { target, dev } = env;
const appConfig = { ...baseConfig };
// Setup SCSS
if (target === 'web') {
const filename = path.resolve(__dirname, 'build');
const cssLoader = {
loader: 'css-loader',
options: {
minimize: !dev,
sourceMap: false,
importLoaders: 1
}
};
const postCSSLoader = {
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: false,
plugins: () => [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9' // React doesn't support IE8 anyway
]
})
]
}
};
const sassLoader = {
loader: 'sass-loader',
options: {
minimize: !dev,
sourceMap: false,
importLoaders: 1
}
};
if (dev) {
appConfig.output.filename = 'static/js/[name].js';
appConfig.module.rules.push({
test: /\.scss$/,
use: ['style-loader', cssLoader, postCSSLoader, sassLoader]
});
} else {
appConfig.output.filename = 'static/js/[name].[chunkhash:8].js';
// For production, extract CSS
appConfig.module.rules.push({
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, cssLoader, postCSSLoader, sassLoader]
});
appConfig.plugins.push(
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new webpack.IgnorePlugin(/moment/, /react-kronos/),
new webpack.optimize.OccurrenceOrderPlugin(),
// new webpack.optimize.LimitChunkCountPlugin({maxChunks: 50}),
new CompressionPlugin()
,new BundleAnalyzerPlugin({
analyzerMode: 'static',
generateStatsFile: true,
openAnalyzer: false
})
// ,new DuplicatePackageCheckerPlugin()
);
}
// optimization
appConfig.optimization = {
...baseConfig.optimization,
minimize: !dev,
minimizer: [new TerserPlugin({
parallel: true,
})],
splitChunks: {
chunks: 'initial',
minSize: 30000,
// minRemainingSize: 0,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 6,
maxInitialRequests: 4,
automaticNameDelimiter: '~',
automaticNameMaxLength: 30,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
},
moduleIds: 'total-size', //added in future deterministic
chunkIds: 'total-size', //added
mangleWasmImports: !dev, //added
removeAvailableModules: !dev, //added
mergeDuplicateChunks: !dev, //added
flagIncludedChunks: !dev,
occurrenceOrder: false,
usedExports: !dev,
// namedModules: true,
// namedChunks: true,
runtimeChunk: 'single'
// runtimeChunk: {
// name: entrypoint => `runtimechunk~${entrypoint.name}`
// }
};
appConfig.plugins.push(
new LoadablePlugin({
outputAsset: false,
writeToDisk: { filename }
}),
new LodashModuleReplacementPlugin({
collections: true,
cloning: true,
deburring: true,
// coercions: true,
flattening: true,
paths: true,
// placeholders: true
shorthands: true
// caching: true
})
);
} else {
appConfig.module.rules.push({
test: /\.(scss)$/,
use: ['ignore-loader']
});
}
return appConfig;
},
modifyBabelOptions: mainBabelOptions => {
return {
...mainBabelOptions,
...{ plugins: [].concat(mainBabelOptions.plugins ? mainBabelOptions.plugins : [], ['lodash']) }
};
}
};
Here is randomly picked trace这是随机挑选的痕迹
(error: https://www.freshbox.sk/static/js/common-blocks-functional-userButton.3074d9ca.chunk.js)
at m.e(webpack/bootstrap:170:18)
at importAsync(./src/common/blocks/header/HeaderVariant2.jsx:35:9)
at requireAsync(./src/common/blocks/header/HeaderVariant2.jsx:34:28)
at loadAsync(./node_modules/@loadable/component/dist/loadable.esm.js:217:31)
at componentDidMount(./node_modules/@loadable/component/dist/loadable.esm.js:147:16)
at Ji(./node_modules/react-dom/cjs/react-dom.production.min.js:212:132)
at b(./node_modules/react-dom/cjs/react-dom.production.min.js:255:229)
at If(./node_modules/scheduler/cjs/scheduler.production.min.js:19:467)
at cg(./node_modules/react-dom/cjs/react-dom.production.min.js:122:325)
at Jj(./node_modules/react-dom/cjs/react-dom.production.min.js:248:370)
at yj(./node_modules/react-dom/cjs/react-dom.production.min.js:239:376)
at Ig(./node_modules/react-dom/cjs/react-dom.production.min.js:230:137)
at bk(./node_modules/react-dom/cjs/react-dom.production.min.js:281:43)
at a(./node_modules/react-dom/cjs/react-dom.production.min.js:284:301)
at Nj(./node_modules/react-dom/cjs/react-dom.production.min.js:240:120)
at ik(./node_modules/react-dom/cjs/react-dom.production.min.js:284:287)
at hydrate(./node_modules/react-dom/cjs/react-dom.production.min.js:290:206)
at done(./src/client/index.js:81:3)
at checkReadyState(./node_modules/@loadable/component/dist/loadable.esm.js:428:11)
at E/</n.push(./node_modules/@loadable/component/dist/loadable.esm.js:435:7)
at ? (/static/js/common-components-category-listing-_default-LayoutSwitcher.869947cb.chunk.js:1:75)```
If the code is split into chunks in order to optimise the loading, the index file usually contains the names and path to all the chunks according to the current webpack build.如果为了优化加载将代码拆分成块,索引文件通常包含根据当前 webpack 构建的所有块的名称和路径。 Making changes to the code and building again can rename the chunks with edited code.更改代码并再次构建可以使用编辑过的代码重命名块。 The browser however loads the index first along with certain required chunks, and then the rest of the chunks are fetched on demand, to make the whole code-splitting optimisation work.然而,浏览器首先加载索引以及某些所需的块,然后按需获取其余的块,以使整个代码拆分优化工作。
I suspect that in this case, there is a production deploy after the index is loaded by the browser, and some of the chunks get renamed by the changes next build.我怀疑在这种情况下,浏览器加载索引后会进行生产部署,并且某些块会因下一次构建的更改而重命名。 Which results in invalid addresses for certain chunks in the stale index.这会导致陈旧索引中某些块的地址无效。 Afterwards when the old index which was in the browser tries to load those non-existent chunks when the user navigated to that part of the website, it throws Loading chunk XY failed
.之后,当用户导航到网站的该部分时,浏览器中的旧索引尝试加载那些不存在的块时,它会抛出Loading chunk XY failed
。 Refreshing should update the index and resolve the issue.刷新应该更新索引并解决问题。
One way to resolve this would be to use service workers.解决此问题的一种方法是使用服务工作者。 The way it could work is as follows:它的工作方式如下:
Using the stale-while-revalidate or cache-first logic for service workers should work here.在这里应该可以为 Service Worker 使用 stale-while-revalidate 或 cache-first 逻辑。 Hope that helps.希望有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.