Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@doodle/frontend-config / webpack / webpack.prod.js
Size: Mime:
const path = require('path');
const { DefinePlugin } = require('webpack');

const CleanWebpackPlugin = require('clean-webpack-plugin');
const WebpackPwaManifest = require('webpack-pwa-manifest');
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

const { PuppeteerRenderer } = PrerenderSPAPlugin;

/**
 * This is the webpack configuration used when running the frontend in development mode.
 * @param {WebpackAppParameters} parameters See {@link ../webpack.js}
 * @param {string} parameters.babelTargetEnv The name of the target babel env, as defined in babel config
 * @returns {Promise<Object>} parameters.babelTargetEnv The name of the target babel env, as defined in babel config
 */
// We use async here to promisy the returned value
// eslint-disable-next-line require-await
module.exports = async parameters => {
  const {
    babelTargetEnv,
    publicPath,
    manifestDescription,
    postProcessPrerenderedHtml,
    prerenderAppConfig,
    prerenderRoutes = [`/${parameters.publicPath}`],
  } = parameters;

  return {
    mode: 'production',
    output: {
      path: path.resolve('dist', 'assets', publicPath, babelTargetEnv),
      filename: '[name].bundle.[contenthash].js',
      chunkFilename: '[name].bundle.[contenthash].js',
    },
    /**
     * https://webpack.js.org/configuration/optimization/
     */
    optimization: {
      noEmitOnErrors: true,
      minimize: true,
    },
    /**
     * https://webpack.js.org/configuration/node
     */
    node: {
      dgram: false,
      fs: false,
      net: false,
      tls: false,
      child_process: false,
    },
    plugins: [
      /**
       * Clean up the build folders on build
       * https://github.com/johnagan/clean-webpack-plugin
       */
      new CleanWebpackPlugin({
        cleanOnceBeforeBuildPatterns: [
          `${process.cwd()}/dist/assets/${publicPath}/${babelTargetEnv}`,
          `${process.cwd()}/dist/prpl/${babelTargetEnv}`,
        ],
      }),
      /**
       * Define global variables
       */
      new DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify('production'),
        // even though this is the production build, we need to pass in a protocol + host for __webpack_public_path__ to work
        // this will be overridden by the `app-config`'s `cdn` field, which points to the CDN
        'process.env.ASSETS_PATH': JSON.stringify(`http://localhost:8080/assets/${publicPath}`),
        'process.env.BUILD_TARGET': JSON.stringify(`/${babelTargetEnv}/`),
      }),
      /**
       * Generate the PWA manifest.json
       * https://github.com/arthurbergmz/webpack-pwa-manifest
       */
      new WebpackPwaManifest({
        name: publicPath,
        description: manifestDescription,
        start_url: `/${publicPath}`,
        display: 'standalone',
        orientation: 'portrait',
        background_color: '#2372E8',
        theme_color: '#2372E8',
        ios: true,
        crossorigin: 'use-credentials', // can be null, use-credentials or anonymous
        icons: [
          {
            src: path.resolve(__dirname, '../assets/icon.png'),
            sizes: [96, 128, 192, 256, 384, 512], // multiple sizes
          },
        ],
      }),
      /**
       * Generate bundle stats
       */
      new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        generateStatsFile: true,
        openAnalyzer: false,
      }),
      /**
       * Prerenders the pages on the server-side
       * https://github.com/chrisvfritz/prerender-spa-plugin
       */
      new PrerenderSPAPlugin({
        staticDir: path.resolve('dist', 'assets', publicPath, babelTargetEnv),
        indexPath: path.resolve('dist', 'assets', publicPath, babelTargetEnv, 'index.html'),
        routes: prerenderRoutes,
        /**
         * Rewrites the HTML files before pre-rendering them. Scripts and links that point
         * at the CDN will be replaced with relative paths.
         * From the plugin docs, this is the structure of the renderedRoute object:
         * {
         *   route: String, // Where the output file will end up (relative to outputDir)
         *   originalRoute: String, // The route that was passed into the renderer, before redirects.
         *   html: String, // The rendered HTML for this route.
         *   outputPath: String // The path the rendered HTML will be written to.
         * }
         */
        postProcess(renderedRoute) {
          const cdn = `/assets/${publicPath}/${babelTargetEnv}/`;
          // replace script src
          renderedRoute.html = renderedRoute.html.replace(
            /(<script[^>]*src=")((?!http|https)[^>"]*)("[^>]*>[^>]*<\/script>)/gi,
            `$1${cdn}$2$3`
          );
          // replace link href
          renderedRoute.html = renderedRoute.html.replace(
            /(<link[^>]*href=")((?!http|https)[^>"]*)("[^>]*>)/gi,
            `$1${cdn}$2$3`
          );

          if (postProcessPrerenderedHtml) {
            renderedRoute.html = postProcessPrerenderedHtml(renderedRoute.html);
          }

          // adjust output path for prpl-server
          renderedRoute.outputPath = path.resolve(
            'dist',
            'prpl',
            babelTargetEnv,
            renderedRoute.originalRoute.replace(`/${publicPath}`, ''),
            'index.html'
          );
          return renderedRoute;
        },
        renderer: new PuppeteerRenderer({
          skipThirdPartyRequests: true,
          renderAfterTime: 500,
          headless: true,
          injectProperty: '__INJECTED__',
          inject: {
            cdn: '',
            target: '',
            ...prerenderAppConfig,
          },
          executablePath: process.env.CHROMIUM_EXECUTABLE,
          args: ['--disable-dev-shm-usage'],
        }),
      }),
    ],
  };
};