Newer
Older
//------------------------------------------------------------------------------
// This app is configured to use typescript.
// See https://webpack.js.org/concepts/ on how to configure this file.
//------------------------------------------------------------------------------
"use-strict";
//------------------------------------------------------------------------------
const path = require("path");
const webpack = require("webpack");
// Configure envirement (NOTE: This must be done as early as possible)
require("dotenv").config();
//------------------------------------------------------------------------------
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
const CheckPortPlugin = require("./plugins/check-port");
const BuildFolderWiper = require("./plugins/build-wiper");
const rootDir = path.resolve(__dirname, "../");
const nodeModulesDir = path.join(rootDir, "node_modules");
const publicDir = path.join(rootDir, "src/assets/public");
const sourcesDir = path.join(rootDir, "src");
const buildDir = path.join(rootDir, "build");
const indexHtmlPath = path.join(rootDir, "index.html");
const entryPointFile = path.join(rootDir, "src/index.tsx");
//------------------------------------------------------------------------------
const checkRequiredFiles = require("react-dev-utils/checkRequiredFiles");
const eslintFormatter = require("react-dev-utils/eslintFormatter");
//------------------------------------------------------------------------------
const requiredFiles = [indexHtmlPath, entryPointFile];
if (!checkRequiredFiles(requiredFiles)) {
process.exit(1);
}
//------------------------------------------------------------------------------
const mainTsRegex = /\.(ts|tsx)$/;
const mainCssRegex = /\.(css)$/;
const assetsRegex = /\.(jpg|jpeg|png|gif|mp3|mp4|svg)$/;
//------------------------------------------------------------------------------
module.exports = function (_, argv) {
const isDevelopment = argv.mode === "development";
const isProduction = argv.mode === "production";
const port = process.env.PORT || 8080;
const getStyleLoaders = () => [
isDevelopment ? "style-loader" : MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: isDevelopment,
},
},
];
return {
target: "web",
entry: entryPointFile,
path: buildDir,
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
filename: isDevelopment
? "static/js/[name].js"
: isProduction && "static/js/[name].[contenthash:8].js",
chunkFilename: isDevelopment
? "static/js/[name].chunk.js"
: isProduction && "static/js/[name].[contenthash:8].chunk.js",
publicPath: "/",
assetModuleFilename: "assets/[hash][ext]",
},
devtool: isDevelopment ? "source-map" : false,
devServer: {
client: {
logging: "none",
overlay: {
// Show only errors on the browser
errors: true,
warnings: false,
},
},
headers: [
// Security headers
{
key: "Strict-Transport-Security",
value: "max-age=63072000; preload",
},
{
key: "X-XSS-Protection",
value: "1; mode=block",
},
{
key: "X-Frame-Options",
value: "deny",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Referrer-Policy",
value: "origin-when-cross-origin",
},
],
historyApiFallback: true, // Nessessary for react router to work
host: "0.0.0.0", // Allow local network access to the server
hot: true,
port,
},
module: {
rules: [
{
exclude: /node_modules/,
use: ["ts-loader"],
},
{
exclude: /node_modules/,
use: getStyleLoaders(),
},
{
exclude: [
/node_modules/,
/\.(js|mjs|jsx|ts|tsx)$/,
/\.html$/,
/\.json$/,
],
use: [
{
loader: "file-loader",
options: {
outputPath: "static/media",
name: "[name].[contenthash:8].[ext]",
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
],
},
resolve: {
extensions: ["*", ".js", ".ts", ".tsx"],
modules: [sourcesDir, nodeModulesDir],
contentBase: buildDir,
events: false,
url: false,
},
},
plugins: [
new ESLintPlugin({ formatter: eslintFormatter }),
new HtmlWebpackPlugin({
template: indexHtmlPath,
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
}),
isProduction &&
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:8].css",
chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
}),
new WebpackManifestPlugin({
fileName: "asset-manifest.json",
publicPath: "/",
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter((fileName) => {
return !fileName.endsWith(".map");
});
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
}),
new CopyWebpackPlugin({
patterns: [
{
from: publicDir,
to: ".",
},
],
}),
isDevelopment && new CheckPortPlugin(port),
isProduction && new BuildFolderWiper(buildDir),
"process.env.NODE_ENV": JSON.stringify(argv.mode),
}),
new webpack.EnvironmentPlugin([
// Pass all public env variables here
]),
].filter(Boolean),
};
};