ModusCreateOrg/budgeting

View on GitHub
webpack.config.prod.js

Summary

Maintainability
A
0 mins
Test Coverage
/* eslint-disable indent */
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const sourceDir = path.join(__dirname, 'app');
const buildDir = path.join(__dirname, 'build');

const entryPath = path.join(sourceDir, 'index.js');

const { NODE_ENV = 'production' } = process.env;

module.exports = require('./webpack.config.base')({
  mode: 'production',
  devtool: 'source-map',

  entry: {
    main: entryPath,
  },

  output: {
    filename: '[name]-[hash:4].js',
    chunkFilename: '[name]-[chunkhash:4].js',
    publicPath: '/',
  },

  optimization: {
    namedModules: true,
    noEmitOnErrors: true,
    minimizer: [
      // in some cases we may want to try to run prod build without the uglifyer
      // for debugging purposes only
      NODE_ENV === 'production'
        ? new TerserPlugin({
            sourceMap: process.env.SOURCEMAPS === 'true',
            parallel: 4,
            cache: path.join(__dirname, '../.uglify-cache'),
            terserOptions: {
              compress: {
                warnings: false,
                conditionals: true,
                unused: true,
                comparisons: true,
                sequences: true,
                dead_code: true,
                evaluate: true,
                if_return: true,
                join_vars: true,
              },
              output: {
                comments: false,
              },
            },
          })
        : null,

      new OptimizeCSSAssetsPlugin({}),

      // copy statics
      new CopyWebpackPlugin([{ from: '**/*', context: path.join(sourceDir, 'static') }]),

      // remove null plugins
    ].filter(Boolean),
  },

  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: 'static/[name].[hash:4].css',
      chunkFilename: 'static/[id].[hash:4].css',
    }),

    new CopyWebpackPlugin([
      {
        from: path.join(__dirname, 'public'),
        to: path.join(buildDir, 'static'),
        ignore: '_redirects',
      },
      {
        from: path.join(__dirname, 'public', '_redirects'),
        to: buildDir,
      },
    ]),

    new SWPrecacheWebpackPlugin({
      cacheId: 'budgeting-app',
      filename: 'sw.js',
      maximumFileSizeToCacheInBytes: 800000,
      staticFileGlobsIgnorePatterns: [/_redirects$/],
      mergeStaticsConfig: true,
      minify: true,
      runtimeCaching: [
        {
          handler: 'cacheFirst',
          urlPattern: /(.*?)/,
        },
      ],
    }),

    new HtmlWebpackPlugin({
      template: 'index.prod.ejs',
      inject: true,
      production: true,
      inlineSource: '.*main.*(css)$',
      root: '/',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true,
      },
    }),

    // make sure script tags are async to avoid blocking html render
    new ScriptExtHtmlWebpackPlugin({
      defaultAttribute: 'async',
    }),

    // inline entrypoint css
    new HtmlWebpackInlineSourcePlugin(),

    // preload JS and CSS
    // ScriptExtHtmlWebpackPlugin doesn't preload CSS well ATM
    new PreloadWebpackPlugin({
      include: 'initial',
      fileWhitelist: [/(css|js)/],
    }),
  ],
  module: {
    rules: [
      {
        test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
        include: sourceDir,
        use: {
          loader: 'file-loader',
          query: {
            name: 'static/[name]-[hash:5].[ext]',
          },
        },
      },
      {
        test: /\.scss$/,
        include: [sourceDir],
        use: [
          MiniCssExtractPlugin.loader,
          'cache-loader',
          {
            loader: 'css-loader',
            options: {
              module: true,
              localIdentName: '[hash:base64:5]',
              importLoaders: 2,
              context: sourceDir,
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: false,
            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'collapsed',
              sourceMap: false,
              includePaths: [sourceDir, path.resolve(sourceDir, '../')],
            },
          },
        ],
      },
      {
        test: /\.(js)$/,
        include: [sourceDir],
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: path.join(__dirname, '.babel-cache', 'production'),
            },
          },
        ],
      },
    ],
  },
});