@oriflame/config-webpack
Version:
Reusable Webpack configs.
268 lines (245 loc) • 6.5 kB
text/typescript
import type { WebpackConfig } from '@beemo/driver-webpack';
import { requireModule } from '@boost/module';
import {
ALIAS_PATTERN,
ASSET_EXT_PATTERN,
CSS_EXT_PATTERN,
CSS_MODULE_EXT_PATTERN,
EXTS,
GQL_EXT_PATTERN,
TJSX_EXT_PATTERN,
} from '@oriflame/lumos-common';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import fs from 'fs';
import path from 'path';
import TerserPlugin from 'terser-webpack-plugin';
import type { Configuration } from 'webpack';
import { merge } from 'webpack-merge';
import {
DEFAULT_MANIFEST_PACKAGE,
DEFAULT_MANIFEST_PATH,
POSTCSS_SETTING as DEFAULT_POSTCSS_SETTING,
} from './constants';
import { getParallelValue, getPlugins, getUniqueName, PORT, PROD, WEBPACK_ROOT } from './helpers';
import type { WebpackOptions } from './types';
const customConfigPathTs = path.join(process.cwd(), '.config', 'lumos', 'webpack.ts');
const customConfigPathJs = path.join(process.cwd(), '.config', 'lumos', 'webpack.js');
export function getConfig({
analyzeBundle = false,
buildFolder = 'build',
port = PORT,
react = false,
sourceMaps = true,
parallel = true,
root = WEBPACK_ROOT,
publicPath = 'auto',
srcFolder,
entryPoint,
host,
devServerContentBase = 'public',
moduleFederationConfig,
enableSharedModules = false,
sharedModulesManifestPath = DEFAULT_MANIFEST_PATH,
sharedModulesPackage = DEFAULT_MANIFEST_PACKAGE,
monorepoRoot,
}: WebpackOptions): WebpackConfig {
const srcPath = path.join(root, srcFolder);
const internalPath = path.join(root, buildFolder);
const contentBase = path.join(root, devServerContentBase);
const entry: Configuration['entry'] = {
index: [srcPath],
};
const POSTCSS_SETTING = { ...DEFAULT_POSTCSS_SETTING };
if (monorepoRoot) {
try {
process.chdir(monorepoRoot);
} catch (error) {
console.log(error);
}
}
POSTCSS_SETTING.options.sourceMap = sourceMaps;
const output: Configuration['output'] = {
path: internalPath,
publicPath,
filename: '[name].js',
chunkFilename: PROD ? '[id].chunk.js' : '[id].js',
sourceMapFilename: '[file].map',
uniqueName: PROD ? getUniqueName() : undefined,
};
const plugins = getPlugins({
analyzeBundle,
buildFolder,
port,
react,
root,
sourceMaps,
entryPoint,
srcFolder,
moduleFederationConfig,
enableSharedModules,
sharedModulesManifestPath,
sharedModulesPackage,
});
if (entryPoint) {
entry.index = path.join(srcPath, entryPoint);
}
if (entryPoint && PROD) {
output.filename = 'index.js';
}
const baseConfig: WebpackConfig = {
mode: PROD ? 'production' : 'development',
bail: PROD,
entry,
context: root,
plugins,
stats: 'errors-warnings',
module: {
rules: [
{
test: TJSX_EXT_PATTERN,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
configFile: true,
},
},
},
{
test: CSS_MODULE_EXT_PATTERN,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: sourceMaps,
importLoaders: 1,
modules: {
localIdentName: '[local]_[hash:base64:5]',
},
},
},
POSTCSS_SETTING,
],
sideEffects: true,
},
{
test: CSS_EXT_PATTERN,
exclude: CSS_MODULE_EXT_PATTERN,
use: [
'style-loader',
{ loader: 'css-loader', options: { sourceMap: sourceMaps } },
POSTCSS_SETTING,
],
sideEffects: true,
},
{
test: ASSET_EXT_PATTERN,
use: {
loader: 'url-loader',
options: {
limit: 1000,
name: 'assets/[name].[ext]?[hash:7]',
publicPath,
esModule: false,
},
},
},
{
test: GQL_EXT_PATTERN,
exclude: /node_modules/,
use: {
loader: 'graphql-tag/loader',
},
},
],
},
resolve: {
alias: {
[`${ALIAS_PATTERN}`]: path.join(root, srcFolder, '/'),
},
fallback: {
applicationinsights: false,
assert: false,
async_hooks: false,
buffer: false,
child_process: false,
console: false,
constants: false,
crypto: false,
dns: false,
domain: false,
events: false,
fs: false,
http: false,
https: false,
module: false,
net: false,
os: false,
path: false,
process: false,
punycode: false,
querystring: false,
stream: false,
string_decoder: false,
sys: false,
timers: false,
tty: false,
url: false,
util: false,
vm: false,
zlib: false,
},
mainFields: ['browser', 'module', 'main'],
extensions: ['.wasm', '.mjs', ...EXTS],
},
output,
devtool: PROD ? (sourceMaps ? 'source-map' : false) : 'eval-source-map',
// @ts-expect-error -- something wrong
devServer: {
static: {
directory: contentBase,
watch: true,
},
allowedHosts: 'all',
client: {
logging: 'info',
},
headers: {
'Service-Worker-Allowed': '/',
},
historyApiFallback: true,
hot: true,
port, // This can be a unix socket path so a string is valid
host,
},
optimization: {
chunkIds: PROD ? undefined : 'named',
minimize: PROD,
minimizer: [
new TerserPlugin({
parallel: getParallelValue(parallel),
terserOptions: {
sourceMap: sourceMaps,
},
}),
new CssMinimizerPlugin({
parallel: getParallelValue(parallel),
}),
],
},
performance: false,
};
let config: WebpackConfig | undefined;
if (fs.existsSync(customConfigPathTs)) {
config = requireModule<WebpackConfig>(customConfigPathTs).default;
}
if (fs.existsSync(customConfigPathJs)) {
config = requireModule<WebpackConfig>(customConfigPathJs).default;
}
if (config) {
return merge<WebpackConfig>(baseConfig, config);
}
return baseConfig;
}