[Webpack 4] React-router does not render any routes when I build with NODE_ENV=production

Do you want to request a feature or report a bug?

What is the current behavior?

If the current behavior is a bug, please provide the steps to reproduce.

Hello,
When I build with NODE_ENV=production, React-Router does not render any routes. Otherwise, I works in developpment.

build script

"build": "rm -rf ./dist && NODE_ENV=production webpack --config build/webpack.config.js -p"

.babel-rc

{
  "presets": [
    ["@babel/preset-env", {
      "modules": false,
      "targets": {
        "browsers": ["last 2 versions"]
      },
      "development": {
        "plugins": [
          "babel-plugin-styled-components"
        ]
      },
      "production": {
        "plugins": [
          "babel-plugin-styled-components"
        ]
      },
      "exclude": ["transform-regenerator", "transform-async-to-generator"]
    }]
  ],
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {"pragma": "h"}],
    ["@babel/plugin-proposal-object-rest-spread"],
    ["transform-react-remove-prop-types"],
    ["babel-plugin-styled-components"],
    ["syntax-dynamic-import"],
    ["module:fast-async", {
      "compiler": {
        "promises": true,
        "generators": false
      },
      "runtimePattern": "home.js",
      "spec": true
    }]
  ]
}

webpack.config.js

const config = require('../config.js');
const path = require('path');
const webpack = require('webpack');
const htmlWebpackPlugin = require('html-webpack-plugin');
const TidyHtmlWebpackPlugin = require('tidy-html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const { InjectManifest } = require('workbox-webpack-plugin');
const autoprefixer = require('autoprefixer');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const production = process.env.NODE_ENV === 'production';

const sw = path.join(__dirname, '../src/sw.js');
const plugins = [
  new MiniCSSExtractPlugin({
    filename: '[name].[contenthash].css'
  }),
  ProgressBarPlugin()
];

const devServer = {
  contentBase: config.contentBase,
  hot: true,
  hotOnly: true,
  historyApiFallback: true,
  port: config.port.front,
  compress: production,
  inline: !production,
  hot: !production,
  stats: {
    assets: true,
    children: false,
    chunks: false,
    hash: true,
    modules: false,
    publicPath: false,
    timings: true,
    version: false,
    warnings: true
  }
}

if (production) {
  plugins.push(
    new webpack.optimize.OccurrenceOrderPlugin(),
    new htmlWebpackPlugin({
      template: config.template,
      minify: {
        removeComments: true
      },
      //cache: true,
      // make it work consistently with multiple chunks
      chunksSortMode: 'dependency'
    }),
    // preload main bundles
    // prefetch should be done with webpack
    // when native support for prefetch will land
    new PreloadWebpackPlugin({
      rel: 'preload',
      include: 'initial'
    }),
    // new TidyHtmlWebpackPlugin(),
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../src/assets/'),
        to: path.resolve(__dirname, '../dist/assets/')
      },
      {
       from: path.resolve(__dirname, '../src/manifest.json'),
       to: path.resolve(__dirname, '../dist/manifest.json')
      },
      {
        from: path.resolve(__dirname, '../src/third_party/idb-keyval.min.js'),
        to: path.resolve(__dirname, '../dist/third_party/idb-keyval.min.js')
      }
    ]),
    new InjectManifest({
      swSrc: sw
    })
  );
} else {
  plugins.push(
    new webpack.HotModuleReplacementPlugin(), // hot reload
    new htmlWebpackPlugin({ // generate index.html
      template: config.template,
    }),
    new FriendlyErrorsPlugin()
  );
};

const common = {
  devtool: config.devtool,
  mode: production ? 'production' : 'development',
  // do not continue build if any errors
  bail: true,
  // watch mode
  watch: !production,
  entry: {
    app: config.entry.front
  },
  output: {
    path: path.resolve('dist'),
    filename: production ? '[name].bundle.[hash].js' : '[name].bundle.js',
    publicPath: '/'
  },
  resolve: {
    extensions: ['.js', '.jsx', '.css', '.scss'],
    alias: {
      // in order to use css-transition-group
      // you have to aliase react and react-dom
      react: 'preact-compat',
			'react-dom': 'preact-compat',
			'react-addons-css-transition-group': 'preact-css-transition-group',
      components: config.componentsPath,
      routes: config.routesPath,
      src: config.staticPath
    }
  },
  module: {
    rules: [{
      test: /\.(css|scss)$/,
      use: [
        MiniCSSExtractPlugin.loader,
        {
          loader: 'css-loader', options: {minimize: true}
        },
        {
          loader: 'sass-loader'
        }
      ]
    },{
      test: /\.(js|jsx)$/,
      exclude: /node_modules/,
      include: path.resolve(__dirname, "../src"),
      loader: 'babel-loader'
    },
    {
      test: /\.(.png|svg)$/,
      // compress images
      loader: 'image-webpack-loader',
      // Ensure this loader run before svg-loader or url-loader
      enforce: 'pre'
    },
    // {
    //   test: /\.svg$/,
    //   loader: 'svg-url-loader',
    //   options: {
    //     // Inline image smaller than 10kb
    //     limit: 10 * 1024,
    //     // remove quotes from url
    //     // https://developers.google.com/web/fundamentals/performance/webpack/decrease-frontend-size
    //     noquotes: true
    //   }
    // },
    {
      test: /\.(png|svg)$/,
      loader: production ? 'file-loader' : 'url-loader',
      query: {
        limit: 10 * 1024,
        name: '[name]-[hash:7].[ext]'
      }
    }]
  },
  optimization: {
    concatenateModules: production,
    nodeEnv: process.env.NODE_ENV,
    minimize: production,
    // optimization.minimizer overrides default optimization
    // in webpack 4.
    // plugin optimizer should be put here
    // not in plugins anymore as before
    minimizer: [
      // minify js
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: false
      }),
      // Compress extracted CSS.
      // Possible duplicated CSS from differents components can be deduped.
      new OptimizeCSSPlugin({
        cssProcessorOptions: {
          safe: true
        }
      })
    ],
    runtimeChunk: true,
    splitChunks: {
      chunks: 'all'
    }
  },
  performance: {
    hints: production ? 'warning' : false
  },
  plugins,
  devServer
};

module.exports = common;

What is the expected behavior?
As it works in dev, it should work in prod.

If this is a feature request, what is motivation or use case for changing the behavior?

Please mention other relevant information such as the browser version, Node.js version, webpack version, and Operating System.

Author: Fantashit

2 thoughts on “[Webpack 4] React-router does not render any routes when I build with NODE_ENV=production

  1. Ran into this today as well. Here is the config that worked for me:

    new UglifyPlugin({
      uglifyOptions: {
        compress: {
          unused: false
        }
      }
    })

Comments are closed.