initial commit

This commit is contained in:
Karli
2025-09-18 19:02:11 +03:00
commit f8a7da141f
55 changed files with 8461 additions and 0 deletions

46
webpack/base.js Executable file
View File

@@ -0,0 +1,46 @@
import { join } from "path";
import SpeedMeasurePlugin from "speed-measure-webpack-plugin";
import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
import config from "./config";
import { basePlugins } from "./options/plugins";
import rules from "./options/rules";
const { devServer } = config;
console.log("dev server", JSON.stringify(devServer));
const baseConfig = {
context: __dirname,
entry: {
main: ["../src/index.tsx"],
},
output: {
path: join(config.webpack.rootDir, "dist"),
publicPath: devServer.isDevServer ? devServer.url : "./",
filename: devServer.isDevServer
? "[name].[fullhash].js"
: "[name].[contenthash].js",
},
module: { rules },
plugins: basePlugins,
resolve: {
extensions: [".tsx", ".ts", ".js", ".jsx"],
plugins: [new TsconfigPathsPlugin({})],
},
optimization: {
runtimeChunk: {
name: "runtime",
},
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
},
},
},
},
};
export default process.env.MEASURE
? new SpeedMeasurePlugin().wrap(baseConfig)
: baseConfig;

43
webpack/config.js Normal file
View File

@@ -0,0 +1,43 @@
import { join } from "path";
const port = process.env.PORT || 5005;
const devServerHost = "127.0.0.1";
const devServerUrl = `http://${devServerHost}:${port}/`;
const Environment = {
development: "development",
production: "production",
};
const environment = process.env.NODE_ENV || Environment.production;
const EnvironmentConfig = {
development: "development",
nonprod: "nonprod",
prelive: "prelive",
production: "production",
};
const environmentConfiguration = process.env.ENV_CONFIGURATION || EnvironmentConfig.development;
const isProd = environmentConfiguration === EnvironmentConfig.production;
const isPrelive = environmentConfiguration === EnvironmentConfig.prelive;
const isNonprod = environmentConfiguration === EnvironmentConfig.nonprod;
const isDev = environment === Environment.development
&& environmentConfiguration === EnvironmentConfig.development;
export default {
environment,
environmentConfiguration,
isProd,
isNonprod,
isDev,
isPrelive,
devServer: {
isDevServer: process.env.WEBPACK_IS_DEV_SERVER === "true",
host: devServerHost,
url: devServerUrl,
},
webpack: {
rootDir: join(__dirname, "../"),
},
};
export { EnvironmentConfig };

21
webpack/dev.js Normal file
View File

@@ -0,0 +1,21 @@
import config from "./config";
import { devPlugins } from "./options/plugins";
export default {
target: "web",
mode: "development",
devtool: "eval-cheap-source-map",
devServer: {
port: process.env.PORT || 5005,
host: config.devServer.host,
historyApiFallback: true,
hot: true,
headers: {
"Access-Control-Allow-Origin": "*",
},
client: {
overlay: false,
},
},
plugins: devPlugins,
};

View File

@@ -0,0 +1,66 @@
import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin";
import CopyPlugin from "copy-webpack-plugin";
import Dotenv from "dotenv-webpack";
import ESLintPlugin from "eslint-webpack-plugin";
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import HtmlWebpackPlugin from "html-webpack-plugin";
import { join } from "path";
import { ProgressPlugin } from "webpack";
import config, { EnvironmentConfig } from "../config";
const basePlugins = [
new HtmlWebpackPlugin({
publicPath: "/",
template: join(config.webpack.rootDir, "src/index.html"),
}),
new ForkTsCheckerWebpackPlugin({
typescript: {
configFile: join(config.webpack.rootDir, "tsconfig.json"),
mode: "write-references",
},
}),
new ESLintPlugin({
context: join(config.webpack.rootDir, "src"),
extensions: ["ts", "tsx"],
failOnError: !config.isDev,
lintDirtyModulesOnly: true,
}),
new CopyPlugin({
patterns: [
{
from: join(config.webpack.rootDir, "src/assets"),
to: "assets",
globOptions: {
dot: false,
ignore: ["**/*.tsx", "**/*.ico"],
},
noErrorOnMissing: true,
},
],
}),
new Dotenv({
path: (() => {
let path = "./.env";
if (config.isProd) {
path = "./.env.production";
} else if (config.isPrelive) {
path = "./.env.prelive";
} else if (config.isNonprod) {
path = "./.env.nonprod";
}
console.log(`Using '${path}' for build variables.`)
return path;
})(),
}),
];
const devPlugins = [
new ProgressPlugin(),
!config.isProd &&
new ReactRefreshWebpackPlugin({
overlay: false,
}),
].filter((_) => _);
export { basePlugins, devPlugins };

56
webpack/options/rules.js Normal file
View File

@@ -0,0 +1,56 @@
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import config from "../config";
const styleRules = [
{
loader: config.isProd ? MiniCssExtractPlugin.loader : "style-loader",
options: {
esModule: false,
},
},
{ loader: "css-loader" },
{ loader: "postcss-loader" },
];
export default [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: "esbuild-loader",
options: {
loader: "tsx",
target: "es2015",
},
},
},
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: "html-loader",
},
},
{
test: /\.(gif|png|jpg|jpeg|webp)$/i,
exclude: /node_modules/,
type: "asset/resource",
},
{
test: /\.(woff(2)?|eot|ttf|otf|)$/,
exclude: /node_modules/,
type: "asset/inline",
},
{
test: /\.s([ca])ss$/,
use: [
...styleRules,
{ loader: "fast-sass-loader" },
],
},
{
test: /\.css$/,
use: styleRules,
},
];

28
webpack/prod.js Normal file
View File

@@ -0,0 +1,28 @@
import { ESBuildMinifyPlugin } from "esbuild-loader";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
export default {
target: "web",
mode: "production",
devtool: false,
optimization: {
minimizer: [
new ESBuildMinifyPlugin({
target: "es2015",
css: true,
legalComments: "eof",
sourcemap: false,
minifyWhitespace: true,
}),
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
chunkFilename: "[id].[contenthash].css",
}),
],
performance: {
hints: false,
},
};