Hi I am learning React in a Typescript environment with Webpack and trying to display error stack trace in production.
I have enabled sourceMaps in tsconfig.json and have dev-tools: source-map setting in my production webconfig. I am performing minification using the Terser plugin with source maps enabled as follows:
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
sourceMap: true,
....
I can see that the source map url is included as a comment at the end of a minified bundle file, e.g.
//# sourceMappingURL=course-list.6ccadc639a7a607e7b4e.bundle.js.map%
I can also see that the minified map files are produced in the dist folder as expected. However, when I display a stack trace and error message for an Error thrown, the message is unreadable using minified content.
http://localhost:8080/vendors~course-list.3042c44300bc08021f63.bundle.js:2:6029
http://localhost:8080/vendors~course-list.3042c44300bc08021f63.bundle.js:2:5067
in w in b in withRouter(b) in e in e in Suspense in div in e in e in S
How do I display readable stack trace for users in production environments?
Further Information 1 I am testing that a network connection error is thrown (in production environment) by the axios library when trying to connect to a local rest API endpoint. If I run in a development environment I can see further details in stack trace relating to Network connection failure. Details are sparse and garbled in production environment with minified bundle and devtool option set to source-map.
The bundle report generated from the production build is as follows:

Further Information 2 I have used code splitting at the route level to create some bundles. Running source-map-explorer for the route code split bundle that throws the error:
npx source-map-explorer dist/vendors~course-list.3042c44300bc08021f63.bundle.js
results in error message:
dist/vendors~course-list.3042c44300bc08021f63.bundle.js
Unable to map 265/14948 bytes (1.77%)
This is the bundle that contains axios library to make the REST API request. The source map analyse report for the bundle is illustrated in the image below:

My production webpack config is as follows:
module.exports = merge(config.CommonConfig, {
devtool: 'source-map',
mode: 'production', // https://webpack.js.org/configuration/mode/#mode-production
module: {
rules: [
{
// link css modules
test: /\.css$/,
include: path.resolve(constants.dir.SRC, 'app'),
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: require.resolve('css-loader'),
options: {
modules: {
localIdentName: '[hash:base64]',
},
importLoaders: 1,
sourceMap: true,
},
},
],
},
{
// link global css module in styles
test: /\.css$/,
include: path.resolve(constants.dir.SRC, 'styles'),
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: require.resolve('css-loader'),
options: { sourceMap: true },
},
],
},
],
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
sourceMap: true,
terserOptions: {
output: {
comments: false,
},
extractComments: false,
},
}),
new OptimizeCSSAssetsPlugin(),
],
},
plugins: [
// inject react and react-dom CDN to scripts in index.html
new WebpackCdnPlugin({
modules: {
react: [
{ name: 'react', version: 16, path: 'umd/react.production.min.js' },
{
name: 'react-dom',
version: 16,
path: 'umd/react-dom.production.min.js',
},
],
},
prod: true,
}),
// extract css to file, minimize in optimization
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false,
}),
// use brotli compression to compress resources larger than ~10K
new CompressionPlugin({
filename: '[path].br[query]',
algorithm: 'brotliCompress',
test: /\.(css|gif|html|jpg|jpeg|js|png|svg|)$/,
compressionOptions: { level: 11 },
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false,
}),
// use gzip compression to compress resources larger than ~10K
new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(css|gif|html|jpg|jpeg|js|png|svg|)$/,
compressionOptions: { level: 9 },
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false,
}),
],
externals: [
// add libraries to be excluded from bundle add here
// for example loaded from CDN
{ react: 'React' },
{ 'react-dom': 'ReactDOM' },
],
});