/* eslint-disable @typescript-eslint/no-var-requires */ const path = require("path"); const webpack = require("webpack"); const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); const CopyPlugin = require("copy-webpack-plugin"); /** @type {import("webpack-cli").CallableOption} */ module.exports = (env, argv) => { const isDevServer = (env || {}).WEBPACK_SERVE === true; const runInContainer = (env || {}).runInContainer === true; const isDevelopment = argv.mode === "development"; const enableReactRefresh = (env || {}).enableReactRefresh === true; const outputDirectory = "dist"; const entry = "./src/index.tsx"; /** @type {webpack.StatsOptions} */ const statsConfig = { builtAt: true, children: false, chunks: false, chunkGroups: false, chunkModules: false, chunkOrigins: false, colors: true, entrypoints: false, }; /** @type {webpack.Configuration["devServer"]} */ const devServerSettings = { hot: true, port: 8000, devMiddleware: { stats: statsConfig, }, static: { directory: path.join(__dirname, "dist"), publicPath: "/dist", }, }; // By default, the webpack-dev-server is not exposed outside of localhost. // When running in a container we need it accessible externally. if (runInContainer) { devServerSettings.host = "0.0.0.0"; } // Get the current commit hash to inject into the app // https://stackoverflow.com/a/38401256 const commitHash = require("child_process").execSync("git rev-parse --short HEAD").toString().trim(); /** @type {HtmlWebpackPlugin.Options} */ const htmlConfig = { title: "Bitburner", template: "src/index.html", filename: isDevServer ? "index.html" : "../index.html", favicon: "favicon.ico", googleAnalytics: { trackingId: "UA-100157497-1", }, meta: {}, minify: isDevelopment ? false : { collapseBooleanAttributes: true, collapseInlineTagWhitespace: false, collapseWhitespace: false, conservativeCollapse: false, html5: true, includeAutoGeneratedTags: false, keepClosingSlash: true, minifyCSS: false, minifyJS: false, minifyURLs: false, preserveLineBreaks: false, preventAttributesEscaping: false, processConditionalComments: false, quoteCharacter: '"', removeAttributeQuotes: false, removeComments: false, removeEmptyAttributes: false, removeEmptyElements: false, removeOptionalTags: false, removeScriptTypeAttributes: false, removeStyleLinkTypeAttributes: false, removeTagWhitespace: false, sortAttributes: false, sortClassName: false, useShortDoctype: false, }, }; return { plugins: [ new MonacoWebpackPlugin({ languages: ["javascript", "typescript", "json"] }), new webpack.DefinePlugin({ "process.env.NODE_ENV": isDevelopment ? '"development"' : '"production"', }), new HtmlWebpackPlugin(htmlConfig), new ForkTsCheckerWebpackPlugin({ typescript: { diagnosticOptions: { semantic: true, syntactic: true, }, }, }), new webpack.DefinePlugin({ __COMMIT_HASH__: JSON.stringify(commitHash || "DEV"), }), // In dev mode, use a faster method of create sourcemaps // while keeping lines/columns accurate isDevServer && new webpack.EvalSourceMapDevToolPlugin({ // Exclude vendor files from sourcemaps // This is a huge speed improvement for not much loss exclude: ["vendor"], columns: true, module: true, }), !isDevServer && new webpack.SourceMapDevToolPlugin({ filename: "[file].map", columns: true, module: true, }), enableReactRefresh && new ReactRefreshWebpackPlugin(), new CopyPlugin({ patterns: [ { from: "{tex-chtml.js,*/**/*}", to: "mathjax", context: "node_modules/mathjax-full/es5", }, ], }), ].filter(Boolean), target: "web", entry: entry, output: { path: path.resolve(__dirname, outputDirectory), filename: "[name].bundle.js", assetModuleFilename: "assets/[hash][ext][query]", }, module: { rules: [ { test: /\.(js$|jsx|ts|tsx)$/, exclude: /node_modules/, resourceQuery: { not: /raw/ }, use: { loader: "babel-loader", options: { plugins: [enableReactRefresh && require.resolve("react-refresh/babel")].filter(Boolean), cacheDirectory: true, }, }, }, { test: /\.(ttf|woff2|png|jpe?g|gif|jp2|webp)$/, type: "asset/resource" }, { test: /\.s?css$/, use: ["style-loader", "css-loader"], }, { resourceQuery: /raw/, type: "asset/source", }, ], }, optimization: { removeAvailableModules: true, removeEmptyChunks: true, mergeDuplicateChunks: true, flagIncludedChunks: true, sideEffects: true, providedExports: true, usedExports: true, concatenateModules: false, minimize: !isDevelopment, portableRecords: true, splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: `vendor`, chunks: "all", }, }, }, }, devServer: devServerSettings, watchOptions: { // When running in a container, we can't necesarily watch filesystem events. poll: runInContainer ? true : undefined, }, resolve: { extensions: [".tsx", ".ts", ".js", ".jsx"], alias: { "@player": path.resolve(__dirname, "src/Player"), "@enums": path.resolve(__dirname, "src/Enums"), "@nsdefs": path.resolve(__dirname, "src/ScriptEditor/NetscriptDefinitions.d.ts"), }, fallback: { crypto: false }, }, stats: statsConfig, ignoreWarnings: [ { module: /@babel\/standalone/, message: /Critical dependency: the request of a dependency is an expression/, }, ], }; };