129 lines
3.8 KiB
TypeScript
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);
|
|
}
|
|
}
|