/**
 * @fileoverview This file contains a set of webpack configurations that should
 * be shared between development and production.
 */

import HtmlWebpackPlugin from "html-webpack-plugin"
import * as path from "path"
import { Configuration, EnvironmentPlugin } from "webpack"

/**
 * environmentPlugin sets process.env.* variables so that they're available in
 * the application.
 */
const environmentPlugin = new EnvironmentPlugin({
  INSPECT_XSTATE: "",
  CODER_VERSION: "main",
})
console.info(`--- Setting INSPECT_XSTATE to '${process.env.INSPECT_XSTATE || ""}'`)
console.info(`--- Setting CODER_VERSION to '${process.env.CODER_VERSION || "main"}'`)
console.info(`--- Setting NODE_ENV to '${process.env.NODE_ENV || ""}'`)

/**
 * dashboardEntrypoint is the top-most module in the dashboard chunk.
 */
const dashboardEntrypoint = path.join(__dirname, "src/Main.tsx")

/**
 * templatePath is the path to HTML templates for injecting webpack bundles
 */
const templatePath = path.join(__dirname, "htmlTemplates")

/**
 * dashboardHTMLPluginConfig is the HtmlWebpackPlugin configuration for the
 * dashboard chunk.
 */
const dashboardHTMLPluginConfig = new HtmlWebpackPlugin({
  publicPath: "/",
  template: path.join(templatePath, "index.html"),
})

export const createCommonWebpackConfig = (options?: { skipTypecheck: boolean }): Configuration => ({
  // entry defines each "page" or "chunk". In v1, we have two "pages":
  // dashboard and terminal. This is desired because the terminal has the xterm
  // vendor, and it is undesirable to load all of xterm on a dashboard
  // page load.
  //
  // The object key determines the chunk 'name'. This can be used in `output`
  // to create a final bundle name.
  //
  // REMARK: We may need to further vendorize the pieces shared by the chunks
  //         such as React, ReactDOM. This is not yet _optimized_, but having
  //         them split means less initial load on dashboard page load.
  entry: dashboardEntrypoint,

  // output defines the name and location of the final bundle
  output: {
    // The chunk name along with a hash of its content will be used for the
    // generated bundle name.
    //
    // REMARK: It's important to use [contenthash] here to invalidate caches.
    filename: "bundle.[contenthash].js",
    path: path.resolve(__dirname, "out"),
  },

  // modules specify how different modules are loaded
  // See: https://webpack.js.org/concepts/modules/
  module: {
    rules: [
      // TypeScript (ts, tsx) files use ts-loader for simplicity.
      //
      // REMARK: We may want to configure babel-loader later on for further
      //         optimization (build time, tree-shaking). babel-loader on its
      //         own does not run type checks.
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: "ts-loader",
            options: {
              configFile: "tsconfig.prod.json",
              transpileOnly: options?.skipTypecheck,
            },
          },
        ],
        exclude: /node_modules/,
      },

      // REMARK: webpack 5 asset modules
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: "asset/resource",
      },
    ],
  },

  cache: {
    type: "filesystem",
  },

  // resolve extend/modify how modules are resolved.
  //
  // REMARK: Do not add aliases here, unless they cannot be defined in a
  //         tsconfig file (see TSConfigWebpackPlugin).
  resolve: {
    // extensions are attempted in order and enable importing files without
    // the extensions explicitly stated
    //
    // See: https://webpack.js.org/guides/typescript/
    extensions: [".tsx", ".ts", ".js"],
    modules: [path.resolve(__dirname, "src"), "node_modules"],
  },

  // plugins customize the build process
  plugins: [environmentPlugin, dashboardHTMLPluginConfig],
})
