@pega/constellation-dx-components-build-utils
Version:
This tool uses a 'v3' approach to group components in a library, create a component map, employ webpack, and load the library like Pega-generated components, constellation app-static.
201 lines (189 loc) • 7.3 kB
JavaScript
const path = require('path');
const customDonePlugin = require('./plugins/CustomDonePlugin');
const dynamicFetchScriptHookPlugin = require('./plugins/DynamicFetchScriptHookPlugin');
const SourceMapDevToolPlugin = require('webpack').SourceMapDevToolPlugin;
const webpack = require('webpack');
const { StatsWriterPlugin } = require('webpack-stats-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
function short3CharId(input) {
const parts = input.match(/[A-Z][a-z]+|[A-Za-z0-9]+/g) || [];
const initials = parts.map(p => p[0]).join('').slice(0, 2); // 1–2 initials
const hash = require("crypto")
.createHash("md5").update(input).digest("hex").slice(0, 1); // 1 hex char
return (initials + hash).padEnd(3, 'x'); // ensure 3 chars
}
const compressionBRConfObj = {
filename: '[path][base].br',
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg|png|jpg|woff|woff2)$/,
compressionOptions: { level: 11 }
};
const imageInlineSizeLimit = Number.parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000', 10);
module.exports = (env) => {
return {
mode: env.mode ? env.mode : 'production',
entry: env.customCmptDir != 'undefined' ? './index.js' : './src/index.js',
output: {
path: env.customCmptDir != 'undefined' ? path.resolve(env.outputPath) : path.resolve(env.buildFolderFullPath),
filename: (pathData) => {
return env.mode === 'development' ? (pathData.chunk.name === 'main' ? 'index.js' : '[name].[contenthash:8].js') : 'componentsmap.js';
},
chunkFilename: env.v3 == 'true' ? short3CharId(env.buildFolderName) + env.packageVersion.replaceAll('.', '') + '_[name].[contenthash:8].js' : 'chunks/[name].[contenthash:8].js'
},
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
},
compress: false,
port: env.port,
hot: true,
open: false,
allowedHosts: 'all',
headers: {
'Access-Control-Allow-Origin': '*', // or specify your domain instead of '*'
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
},
client: {
webSocketURL: {
hostname: 'localhost'
},
}
},
devtool: env.mode === 'development' ? 'eval-source-map' : 'source-map',
module: {
rules: [
{
test: /\.(?:js|mjs|jsx|cjs|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', { targets: "defaults" }],
['@babel/preset-react', { runtime: "automatic" }],
['@babel/preset-typescript']
]
}
}
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|bmp|svg|jpe?g|gif)$/i,
loader: 'url-loader',
options: {
limit: imageInlineSizeLimit,
name: 'images/[name].[contenthash:4].[ext]',
},
}
]
},
plugins: [
...((env.v3 === 'true' || env.mode === 'development') ? [] : [ new SourceMapDevToolPlugin({
append: '\n//# sourceMappingURL='+env.appStaticUrl+'/component/'+env.buildFolderName+':'+env.packageVersion+'/chunks/[url]?orgId='+env.orgId,
filename: '[file].map[query]',
})]),
new customDonePlugin({ projectName: path.resolve(""), libName: env.buildFolderName, libVersion: env.packageVersion }),
...(env.mode === 'development' ? [] : (
env.v3 === 'true' ? [new dynamicFetchScriptHookPlugin(true)] : [new dynamicFetchScriptHookPlugin()]
)),
new webpack.ids.DeterministicChunkIdsPlugin({
maxLength:8
}),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/
}),
/* Ignore cosmos icons */
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/icons$/,
contextRegExp: /@pega\/cosmos-react-core\/lib\/components\/Icon$/
}),
/* Ignore cosmos icons - windows */
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/icons$/,
contextRegExp: /@pega\\cosmos-react-core\\lib\\components\\Icon$/
}),
/* Ignore cosmos streamline-icons */
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/streamline-icons$/,
contextRegExp: /@pega\/cosmos-react-core\/lib\/components\/Icon$/
}),
/* Ignore cosmos streamline-icons - windows */
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/streamline-icons$/,
contextRegExp: /@pega\\cosmos-react-core\\lib\\components\\Icon$/
}),
/* cosmos 6.x and above */
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/.*\/.*\.icon$/,
contextRegExp: /@pega\/cosmos-react-core\/lib\/components\/Icon$/
}),
/* Ignore cosmos icons - windows */
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/.*\/.*\.icon$/,
contextRegExp: /@pega\\cosmos-react-core\\lib\\components\\Icon$/
}),
new CompressionPlugin(compressionBRConfObj),
/* To generate Manifest */
/*new StatsWriterPlugin({
stats: {
fields: ["assets"]
},
filename: "stats.json",
})*/
new StatsWriterPlugin({
filename: 'stats.json',
stats: {
assets: true,
entrypoints: true,
namedChunkGroups: true,
chunks: true, // Omit if not needed
modules: false, // This can be huge — include only if necessary
performance: false,
},
transform(data) {
return JSON.stringify({
assets: (data.assets || []).filter(asset => !asset.name.endsWith('.map')).slice(0, 10000),
entrypoints: data.entrypoints,
namedChunkGroups: data.namedChunkGroups,
}, null);
},
})
],
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
resolve: {
extensions: ['.ts', '.js', '.jsx', '.tsx'],
fallback: {
stream: require.resolve('stream-browserify'),
os: require.resolve('os-browserify/browser'),
perf_hooks: false,
module: require.resolve("module"),
path: require.resolve("path-browserify"),
browser: require.resolve('os-browserify/browser'),
"fs": false,
"constants": require.resolve("constants-browserify")
}
},
optimization: env.mode === 'development' ? {
splitChunks: false,
runtimeChunk: false,
} : {
splitChunks: {
chunks: 'all',
minSize: 60000, // 60 KB
maxSize: 300000, // 300 KB
},
},
};
};