Files
mcb-platform-monorepo/packages/webpack-config/src/config/webpack/WebpackConfigBuilder.ts
T
2025-07-21 17:12:41 +03:00

129 lines
3.8 KiB
TypeScript

import type { IWebpackAppConfig, Mode } from 'types';
import type { Configuration } from 'webpack';
import { merge } from 'webpack-merge';
import path from 'node:path';
import { setDevServer } from './setDevServer';
import { setModuleOptions } from './setModuleOptions';
import { setOptimizationRules } from './setOptimizationRules';
import { setPlugins } from './setPlugins';
export class WebpackConfigBuilder {
private config: Configuration = {};
private appConfig: IWebpackAppConfig;
private isDevelopmentMode: boolean;
private isProductionMode: boolean;
private cwd: string;
private srcPath: string;
constructor(appConfig: IWebpackAppConfig, mode: Mode) {
this.appConfig = appConfig;
this.isDevelopmentMode = mode === 'development';
this.isProductionMode = mode === 'production';
this.cwd = process.cwd();
this.srcPath = path.resolve(this.cwd, appConfig.paths?.srcPath || 'src');
const entry = appConfig.paths?.entry || path.resolve(this.srcPath, 'index.ts');
const target = this.isDevelopmentMode ? 'web' : 'browserslist';
const devtool = this.isDevelopmentMode ? 'eval-cheap-module-source-map' : 'source-map';
this.config = {
mode,
target,
devtool,
entry,
};
}
public get configuration() {
return this.config;
}
public applyOutput() {
const port = this.appConfig.devServerOptions?.port;
this.config.output = {
path: this.appConfig.paths?.outputPath || path.resolve(this.cwd, 'dist'),
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].js',
publicPath: this.isDevelopmentMode && port ? `http://localhost:${port}/` : this.appConfig.paths?.publicUrl || '/',
clean: true,
};
}
public applyResolve() {
this.config.resolve = {
alias: {
// FSD alias
'@/app': path.resolve(this.srcPath, 'app'),
'@/shared': path.resolve(this.srcPath, 'shared'),
'@/pages': path.resolve(this.srcPath, 'pages'),
'@/widgets': path.resolve(this.srcPath, 'widgets'),
'@/features': path.resolve(this.srcPath, 'features'),
'@/entities': path.resolve(this.srcPath, 'entities'),
// jsx-runtime
'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js',
'react/jsx-runtime': 'react/jsx-runtime.js',
},
extensions: ['.js', '.jsx', '.ts', '.tsx'],
};
}
public applyDevServer() {
if (this.isDevelopmentMode) {
const devServerOptions = {
...this.appConfig.devServerOptions,
port: this.appConfig.devServerOptions?.port || 3001,
};
this.config.devServer = setDevServer(devServerOptions);
}
}
public applyPerfomance() {
if (this.isProductionMode) {
this.config.performance = {
hints: false,
maxEntrypointSize: 512_000,
maxAssetSize: 512_000,
};
}
}
public applyOptimizationRules() {
if (this.isProductionMode) {
this.config.optimization = setOptimizationRules(this.appConfig.optimizationOptions);
}
}
public applyModuleOptions() {
this.config.module = setModuleOptions({
isDevelopmentMode: this.isDevelopmentMode,
isProductionMode: this.isProductionMode,
});
}
public applyPlugins() {
const publicPath = this.appConfig.paths?.publicPath || 'public';
this.config.plugins =
setPlugins({
isDevelopmentMode: this.isDevelopmentMode,
isProductionMode: this.isProductionMode,
publicPath,
moduleName: this.appConfig.moduleName,
moduleFederationOptions: this.appConfig.moduleFederationOptions,
}) || [];
const otherPlugins = this.appConfig.plugins;
if (Array.isArray(otherPlugins) && Array.isArray(this.config.plugins)) {
this.config.plugins = this.config.plugins.concat(otherPlugins);
}
}
public merge(newConfig: Configuration) {
merge(this.config, newConfig);
}
}