<commit_before>const webpack = require('webpack');

const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { InjectManifest } = require('workbox-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackIncludeSiblingChunksPlugin = require('html-webpack-include-sibling-chunks-plugin');
const GenerateJsonPlugin = require('generate-json-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const csp = require('./content-security-policy');
const i18nextWebpackPlugin = require('i18next-scanner-webpack');
const PacktrackerPlugin = require('@packtracker/webpack-plugin');

const Visualizer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const NotifyPlugin = require('notify-webpack-plugin');

const ASSET_NAME_PATTERN = 'static/[name]-[hash:6].[ext]';

const packageJson = require('../package.json');

module.exports = (env) => {
  if (process.env.WEBPACK_SERVE) {
    env = 'dev';
    if (!fs.existsSync('key.pem') || !fs.existsSync('cert.pem')) {
      console.log('Generating certificate');
      execSync('mkcert create-ca --validity 3650');
      execSync('mkcert create-cert --validity 3650 --key key.pem --cert cert.pem');
    }
  }
  const isDev = env === 'dev';
  let version = packageJson.version.toString();
  if (env === 'beta' && process.env.TRAVIS_BUILD_NUMBER) {
    version += `.${process.env.TRAVIS_BUILD_NUMBER}`;
  }

  const config = {
    mode: isDev ? 'development' : 'production',

    entry: {
      main: './src/Index.tsx',
      browsercheck: './src/browsercheck.js',
      authReturn: './src/authReturn.ts',
      gdriveReturn: './src/gdriveReturn.ts'
    },

    output: {
      path: path.resolve('./dist'),
      publicPath: '/',
      filename: isDev ? '[name]-[hash].js' : '[name]-[contenthash:6].js',
      chunkFilename: isDev ? '[name]-[hash].js' : '[name]-[contenthash:6].js'
    },

    // Dev server
    serve: process.env.WEBPACK_SERVE
      ? {
          host: process.env.DOCKER ? '0.0.0.0' : 'localhost',
          devMiddleware: {
            stats: 'errors-only'
          },
          https: {
            key: fs.readFileSync('key.pem'), // Private keys in PEM format.
            cert: fs.readFileSync('cert.pem') // Cert chains in PEM format.
          }
        }
      : {},

    // Bail and fail hard on first error
    bail: !isDev,

    stats: isDev ? 'minimal' : 'normal',

    devtool: 'source-map',

    performance: {
      // Don't warn about too-large chunks
      hints: false
    },

    optimization: {
      // We always want the chunk name, otherwise it's just numbers
      namedChunks: true,
      // Extract the runtime into a separate chunk
      runtimeChunk: 'single',
      splitChunks: {
        chunks: 'all',
        automaticNameDelimiter: '-'
      },
      minimizer: [
        new TerserPlugin({
          cache: true,
          parallel: true,
          terserOptions: {
            ecma: 8,
            module: true,
            compress: { warnings: false, passes: 3, toplevel: true },
            mangle: { safari10: true, toplevel: true },
            output: { safari10: true }
          },
          sourceMap: true
        })
      ]
    },

    module: {
      strictExportPresence: true,

      rules: [
        {
          test: /\.js$/,
          exclude: [/node_modules/],
          loader: 'babel-loader',
          options: {
            cacheDirectory: true
          }
        },
        {
          test: /\.html$/,
          loader: 'html-loader',
          options: {
            exportAsEs6Default: true,
            minimize: true
          }
        },
        {
          test: /\.(jpg|gif|png|eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
          loader: 'url-loader',
          options: {
            limit: 5 * 1024, // only inline if less than 5kb
            name: ASSET_NAME_PATTERN
          }
        },
        // *.m.scss will have CSS Modules support
        {
          test: /\.m\.scss$/,
          use: [
            isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
            {
              loader: 'css-modules-typescript-loader',
              options: {
                mode: process.env.CI ? 'verify' : 'emit'
              }
            },
            {
              loader: 'css-loader',
              options: {
                modules: {
                  localIdentName: isDev ? '[name]_[local]-[hash:base64:5]' : '[hash:base64:5]'
                },
                localsConvention: 'camelCaseOnly',
                sourceMap: true
              }
            },
            'postcss-loader',
            'sass-loader'
          ]
        },
        // Regular *.scss are global
        {
          test: /\.scss$/,
          exclude: /\.m\.scss$/,
          use: [
            isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                sourceMap: true
              }
            },
            'postcss-loader',
            'sass-loader'
          ]
        },
        {
          test: /\.css$/,
          use: [isDev ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader']
        },
        // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
        {
          test: /\.tsx?$/,
          loader: 'awesome-typescript-loader',
          options: {
            useBabel: true,
            babelCore: '@babel/core',
            useCache: true
          }
        },
        // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
        {
          enforce: 'pre',
          test: /\.jsx?$/,
          loader: 'source-map-loader'
        },
        {
          type: 'javascript/auto',
          test: /\.json/,
          include: /src(\/|\\)locale/,
          use: [
            {
              loader: 'file-loader',
              options: { name: '[name]-[hash:6].[ext]' }
            }
          ]
        },
        {
          type: 'javascript/auto',
          test: /\.wasm/
        },
        {
          test: /CHANGELOG\.md$/,
          loader: path.resolve('./config/changelog-loader')
        }
      ],

      noParse: function(path) {
        return false;
      }
    },

    resolve: {
      extensions: ['.js', '.json', '.ts', '.tsx', '.jsx'],

      alias: {
        app: path.resolve('./src/app/'),
        data: path.resolve('./src/data/'),
        images: path.resolve('./src/images/'),
        'destiny-icons': path.resolve('./destiny-icons/')
      }
    },

    plugins: [
      new CaseSensitivePathsPlugin(),

      new webpack.IgnorePlugin(/caniuse-lite\/data\/regions/),

      new webpack.ProvidePlugin({
        i18next: 'i18next',
        'window.i18next': 'i18next'
      }),

      new NotifyPlugin('DIM', !isDev),

      new MiniCssExtractPlugin({
        filename: isDev ? '[name]-[hash].css' : '[name]-[contenthash:6].css',
        chunkFilename: isDev ? '[name]-[hash].css' : '[id]-[contenthash:6].css'
      }),

      // Fix some chunks not showing up in Webpack 4
      new HtmlWebpackIncludeSiblingChunksPlugin(),

      new HtmlWebpackPlugin({
        inject: true,
        filename: 'index.html',
        template: '!html-loader!src/index.html',
        chunks: ['main', 'browsercheck']
      }),

      new HtmlWebpackPlugin({
        inject: true,
        filename: 'return.html',
        template: '!html-loader!src/return.html',
        chunks: ['authReturn']
      }),

      new HtmlWebpackPlugin({
        inject: true,
        filename: 'gdrive-return.html',
        template: '!html-loader!src/gdrive-return.html',
        chunks: ['gdriveReturn']
      }),

      // Generate the .htaccess file (kind of an abuse of HtmlWebpack plugin just for templating)
      new HtmlWebpackPlugin({
        filename: '.htaccess',
        template: 'src/htaccess',
        inject: false,
        templateParameters: {
          csp: csp(env)
        }
      }),

      // Generate a version info JSON file we can poll. We could theoretically add more info here too.
      new GenerateJsonPlugin('./version.json', {
        version
      }),

      new CopyWebpackPlugin([
        { from: './extension', to: '../extension-dist' },
        { from: `./icons/${env}-extension/`, to: '../extension-dist' },
        { from: './src/manifest-webapp-6-2018.json' },
        { from: './src/manifest-webapp-6-2018-ios.json' },
        { from: './src/data', to: 'data/', ignore: ['missing_sources.json'] },
        { from: `./icons/${env}/` },
        { from: './src/safari-pinned-tab.svg' }
      ]),

      new webpack.DefinePlugin({
        $DIM_VERSION: JSON.stringify(version),
        $DIM_FLAVOR: JSON.stringify(env),
        $DIM_BUILD_DATE: JSON.stringify(Date.now()),
        // These are set from the Travis repo settings instead of .travis.yml
        $DIM_WEB_API_KEY: JSON.stringify(process.env.WEB_API_KEY),
        $DIM_WEB_CLIENT_ID: JSON.stringify(process.env.WEB_OAUTH_CLIENT_ID),
        $DIM_WEB_CLIENT_SECRET: JSON.stringify(process.env.WEB_OAUTH_CLIENT_SECRET),

        $GOOGLE_DRIVE_CLIENT_ID: JSON.stringify(
          '22022180893-raop2mu1d7gih97t5da9vj26quqva9dc.apps.googleusercontent.com'
        ),

        $BROWSERS: JSON.stringify(packageJson.browserslist),

        // Feature flags!

        // Print debug info to console about item moves<commit_msg>Don't copy data<commit_after>const webpack = require('webpack');

const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { InjectManifest } = require('workbox-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackIncludeSiblingChunksPlugin = require('html-webpack-include-sibling-chunks-plugin');
const GenerateJsonPlugin = require('generate-json-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const csp = require('./content-security-policy');
const i18nextWebpackPlugin = require('i18next-scanner-webpack');
const PacktrackerPlugin = require('@packtracker/webpack-plugin');

const Visualizer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const NotifyPlugin = require('notify-webpack-plugin');

const ASSET_NAME_PATTERN = 'static/[name]-[hash:6].[ext]';

const packageJson = require('../package.json');

module.exports = (env) => {
  if (process.env.WEBPACK_SERVE) {
    env = 'dev';
    if (!fs.existsSync('key.pem') || !fs.existsSync('cert.pem')) {
      console.log('Generating certificate');
      execSync('mkcert create-ca --validity 3650');
      execSync('mkcert create-cert --validity 3650 --key key.pem --cert cert.pem');
    }
  }
  const isDev = env === 'dev';
  let version = packageJson.version.toString();
  if (env === 'beta' && process.env.TRAVIS_BUILD_NUMBER) {
    version += `.${process.env.TRAVIS_BUILD_NUMBER}`;
  }

  const config = {
    mode: isDev ? 'development' : 'production',

    entry: {
      main: './src/Index.tsx',
      browsercheck: './src/browsercheck.js',
      authReturn: './src/authReturn.ts',
      gdriveReturn: './src/gdriveReturn.ts'
    },

    output: {
      path: path.resolve('./dist'),
      publicPath: '/',
      filename: isDev ? '[name]-[hash].js' : '[name]-[contenthash:6].js',
      chunkFilename: isDev ? '[name]-[hash].js' : '[name]-[contenthash:6].js'
    },

    // Dev server
    serve: process.env.WEBPACK_SERVE
      ? {
          host: process.env.DOCKER ? '0.0.0.0' : 'localhost',
          devMiddleware: {
            stats: 'errors-only'
          },
          https: {
            key: fs.readFileSync('key.pem'), // Private keys in PEM format.
            cert: fs.readFileSync('cert.pem') // Cert chains in PEM format.
          }
        }
      : {},

    // Bail and fail hard on first error
    bail: !isDev,

    stats: isDev ? 'minimal' : 'normal',

    devtool: 'source-map',

    performance: {
      // Don't warn about too-large chunks
      hints: false
    },

    optimization: {
      // We always want the chunk name, otherwise it's just numbers
      namedChunks: true,
      // Extract the runtime into a separate chunk
      runtimeChunk: 'single',
      splitChunks: {
        chunks: 'all',
        automaticNameDelimiter: '-'
      },
      minimizer: [
        new TerserPlugin({
          cache: true,
          parallel: true,
          terserOptions: {
            ecma: 8,
            module: true,
            compress: { warnings: false, passes: 3, toplevel: true },
            mangle: { safari10: true, toplevel: true },
            output: { safari10: true }
          },
          sourceMap: true
        })
      ]
    },

    module: {
      strictExportPresence: true,

      rules: [
        {
          test: /\.js$/,
          exclude: [/node_modules/],
          loader: 'babel-loader',
          options: {
            cacheDirectory: true
          }
        },
        {
          test: /\.html$/,
          loader: 'html-loader',
          options: {
            exportAsEs6Default: true,
            minimize: true
          }
        },
        {
          test: /\.(jpg|gif|png|eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
          loader: 'url-loader',
          options: {
            limit: 5 * 1024, // only inline if less than 5kb
            name: ASSET_NAME_PATTERN
          }
        },
        // *.m.scss will have CSS Modules support
        {
          test: /\.m\.scss$/,
          use: [
            isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
            {
              loader: 'css-modules-typescript-loader',
              options: {
                mode: process.env.CI ? 'verify' : 'emit'
              }
            },
            {
              loader: 'css-loader',
              options: {
                modules: {
                  localIdentName: isDev ? '[name]_[local]-[hash:base64:5]' : '[hash:base64:5]'
                },
                localsConvention: 'camelCaseOnly',
                sourceMap: true
              }
            },
            'postcss-loader',
            'sass-loader'
          ]
        },
        // Regular *.scss are global
        {
          test: /\.scss$/,
          exclude: /\.m\.scss$/,
          use: [
            isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                sourceMap: true
              }
            },
            'postcss-loader',
            'sass-loader'
          ]
        },
        {
          test: /\.css$/,
          use: [isDev ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader']
        },
        // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
        {
          test: /\.tsx?$/,
          loader: 'awesome-typescript-loader',
          options: {
            useBabel: true,
            babelCore: '@babel/core',
            useCache: true
          }
        },
        // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
        {
          enforce: 'pre',
          test: /\.jsx?$/,
          loader: 'source-map-loader'
        },
        {
          type: 'javascript/auto',
          test: /\.json/,
          include: /src(\/|\\)locale/,
          use: [
            {
              loader: 'file-loader',
              options: { name: '[name]-[hash:6].[ext]' }
            }
          ]
        },
        {
          type: 'javascript/auto',
          test: /\.wasm/
        },
        {
          test: /CHANGELOG\.md$/,
          loader: path.resolve('./config/changelog-loader')
        }
      ],

      noParse: function(path) {
        return false;
      }
    },

    resolve: {
      extensions: ['.js', '.json', '.ts', '.tsx', '.jsx'],

      alias: {
        app: path.resolve('./src/app/'),
        data: path.resolve('./src/data/'),
        images: path.resolve('./src/images/'),
        'destiny-icons': path.resolve('./destiny-icons/')
      }
    },

    plugins: [
      new CaseSensitivePathsPlugin(),

      new webpack.IgnorePlugin(/caniuse-lite\/data\/regions/),

      new webpack.ProvidePlugin({
        i18next: 'i18next',
        'window.i18next': 'i18next'
      }),

      new NotifyPlugin('DIM', !isDev),

      new MiniCssExtractPlugin({
        filename: isDev ? '[name]-[hash].css' : '[name]-[contenthash:6].css',
        chunkFilename: isDev ? '[name]-[hash].css' : '[id]-[contenthash:6].css'
      }),

      // Fix some chunks not showing up in Webpack 4
      new HtmlWebpackIncludeSiblingChunksPlugin(),

      new HtmlWebpackPlugin({
        inject: true,
        filename: 'index.html',
        template: '!html-loader!src/index.html',
        chunks: ['main', 'browsercheck']
      }),

      new HtmlWebpackPlugin({
        inject: true,
        filename: 'return.html',
        template: '!html-loader!src/return.html',
        chunks: ['authReturn']
      }),

      new HtmlWebpackPlugin({
        inject: true,
        filename: 'gdrive-return.html',
        template: '!html-loader!src/gdrive-return.html',
        chunks: ['gdriveReturn']
      }),

      // Generate the .htaccess file (kind of an abuse of HtmlWebpack plugin just for templating)
      new HtmlWebpackPlugin({
        filename: '.htaccess',
        template: 'src/htaccess',
        inject: false,
        templateParameters: {
          csp: csp(env)
        }
      }),

      // Generate a version info JSON file we can poll. We could theoretically add more info here too.
      new GenerateJsonPlugin('./version.json', {
        version
      }),

      new CopyWebpackPlugin([
        { from: './extension', to: '../extension-dist' },
        { from: `./icons/${env}-extension/`, to: '../extension-dist' },
        { from: './src/manifest-webapp-6-2018.json' },
        { from: './src/manifest-webapp-6-2018-ios.json' },
        // Only copy the manifests out of the data folder. Everything else we import directly into the bundle.
        { from: './src/data', to: 'data/', test: /data\/d1\/manifests/ },
        { from: `./icons/${env}/` },
        { from: './src/safari-pinned-tab.svg' }
      ]),

      new webpack.DefinePlugin({
        $DIM_VERSION: JSON.stringify(version),
        $DIM_FLAVOR: JSON.stringify(env),
        $DIM_BUILD_DATE: JSON.stringify(Date.now()),
        // These are set from the Travis repo settings instead of .travis.yml
        $DIM_WEB_API_KEY: JSON.stringify(process.env.WEB_API_KEY),
        $DIM_WEB_CLIENT_ID: JSON.stringify(process.env.WEB_OAUTH_CLIENT_ID),
        $DIM_WEB_CLIENT_SECRET: JSON.stringify(process.env.WEB_OAUTH_CLIENT_SECRET),

        $GOOGLE_DRIVE_CLIENT_ID: JSON.stringify(
          '22022180893-raop2mu1d7gih97t5da9vj26quqva9dc.apps.googleusercontent.com'
        ),

        $BROWSERS: JSON.stringify(packageJson.browserslist),

        // Feature flags!

        // Print debug info to console about item moves
{'fraction_non_alphanumeric': 0.14926730672056593, 'fraction_numerical': 0.00833754421424962, 'mean_word_length': 1.8715902495647128, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4964382', 'n_tokens_mistral': 6167, 'n_tokens_neox': 5957, 'n_words': 1190}