webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineChunkHtmlPlugin = require('inline-chunk-html-plugin');
const HTMLInlineCSSWebpackPlugin = require('html-inline-css-webpack-plugin').default;
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const workboxPlugin = require('workbox-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const { DuplicatesPlugin } = require('inspectpack/plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const path = require('path');

const DEVELOPMENT = 'development';
const SITE_TITLE = 'Comedy Collection';
const environment = process.env.NODE_ENV || DEVELOPMENT;
const target = process.env.TARGET || 'dev';
const resolve = (filename) => path.resolve(__dirname, filename);

/***************************
 ********* Loaders *********
 **************************/
const js = {
  test: /\.js$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env', '@babel/preset-react']
    }
  }
};

const scss = {
  test: /\.scss$/i,
  use: [
    // Creates `style` nodes from JS strings
    'style-loader',
    /**
     * NOTE: Use following loader to generate css files
     */
    // MiniCssExtractPlugin.loader,
    // Translates CSS into CommonJS
    'css-loader',
    // Compiles Sass to CSS
    {
      loader: 'sass-loader',
      options: {
        sassOptions: {
          outputStyle: 'compressed'
        }
      }
    }
  ]
};

const imgs = {
  test: /\.(png|svg|jpg|gif)$/,
  use: ['file-loader']
};

const css = {
  test: /\.css$/,
  use: [MiniCssExtractPlugin.loader, 'css-loader']
};

/***************************
 ******* Entry config ******
 **************************/
const entry = {};
// VENDORS
entry[`react-libs`] = ['react', 'react-dom', 'react-router-dom', 'swr'];
entry[`common-libs`] = ['react-youtube'];

// MAIN SCRIPTS
entry[`app-index`] = resolve('main.js');
// service worker: registeration scripts only
entry[`caching-configs.register`] = resolve('service-workers/caching-configs.register.js');

// CRITICAL STYLES
// TODO: change type to inline
// entry[`styles-home`] = [resolve('assets/scss/home-spinner.scss')];

/*************************************
 *** Inject Manifest plugin config ***
 ** (list of resources to precache) **
 ************************************/
// service workers mapping here
const injectManifestCachingConfigSW = {
  swSrc: resolve(`service-workers/caching-configs.sw.js`),
  /**
   * NOTE: following sw applies to root of the application.
   * adding it under folder `comedians/` would make it be applicable to code under that folder
   */
  swDest: `caching-configs.sw.js`,
  include: []
};

/***************************
 *** HTML plugin config ****
 **************************/
const htmlPluginConfig = {
  inject: false,
  filename: 'index.html',
  template: 'index.html'
};

/***************************
 ******** Plugins **********
 **************************/
const commonPlugins = [
  new workboxPlugin.InjectManifest(injectManifestCachingConfigSW),
  new MiniCssExtractPlugin({
    filename: '[name].css',
    chunkFilename: '[name].css'
  }),
  new HtmlWebpackPlugin(htmlPluginConfig),
  new CopyPlugin({
    patterns: [
      {
        from: './assets/icons/'
      }
    ]
  }),
  new DuplicatesPlugin({
    emitErrors: false,
    verbose: true
  })
];
const plugins = [];
plugins.push(...commonPlugins);

/*****************************************************************/
////////////////////////// All Config /////////////////////////////
/*****************************************************************/
const BUILD_PATH = resolve(`../build/${target}`);
const clientConfig = {
  mode: environment,
  target: 'web',
  entry,
  module: {
    rules: [js, scss, imgs]
  },
  output: {
    path: BUILD_PATH,
    filename: '[name].[contenthash:8].js',
    publicPath: '/',
    // fixes issue with window not defined while using webworkers
    // https://github.com/webpack/webpack/issues/6642
    globalObject: 'this'
  },
  // create seperate bundle for node_modules packages
  optimization: {
    splitChunks: {
      chunks: 'async'
    }
  },
  plugins
};

if (environment === DEVELOPMENT) {
  clientConfig['devtool'] = 'source-map';
  clientConfig['devServer'] = {
    contentBase: BUILD_PATH
  };
} else {
  clientConfig['optimization'].minimize = true;
  clientConfig['optimization'].minimizer = [new TerserPlugin({ cache: true })];
}

module.exports = [clientConfig];