peridot/rules_resf/internal/resf_bundle/webpack.config.js

276 lines
7.9 KiB
JavaScript

/*
* Copyright (c) All respective contributors to the Peridot Project. All rights reserved.
* Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved.
* Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// Global imports
const path = require('path');
const fs = require('fs-extra');
const webpack = require('webpack');
const glob = require('glob');
const TerserJSPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
// Function imports
const resolve = path.resolve; // eslint-disable-line
// Env variables
const dev = process.env.NODE_ENV !== 'production';
const title = 'TMPL_title';
const moduleMappings = TMPL_module_mappings;
const rawName = 'TMPL_global_name';
const name = rawName
.replace(/-/g, '_')
.replace('.bundle', '')
.replace('.server', '');
const indexHtml = 'TMPL_indexHtml';
const inputs = [TMPL_inputs];
const bodyScript = 'TMPL_body_script';
const headStyle = 'TMPL_head_style';
const typekit = 'TMPL_typekit';
Object.keys(moduleMappings).forEach((k) => {
moduleMappings[k] = resolve(process.cwd(), moduleMappings[k]);
});
// Entries
const entries = inputs.map((n) => resolve(process.cwd(), n));
const devEntries = dev ? ['webpack-hot-middleware/client'] : [];
const modules = [
resolve(process.cwd(), '../npm/node_modules'),
resolve(process.cwd(), 'external/npm/node_modules'),
resolve(process.cwd()),
];
const fileName = `${name}.bundle${dev ? '' : '.min'}`;
const apiUrl = process.env.API_URL;
const apiKey = process.env.API_KEY;
const htmlFile = resolve(process.cwd(), indexHtml);
// Plugins
// (dev)
const devPlugins = dev
? [new webpack.HotModuleReplacementPlugin(), new ReactRefreshWebpackPlugin()]
: [];
// (prod)
const prodPlugins = !dev
? [
new MiniCssExtractPlugin({
filename: `${fileName}.[hash].[id].css`,
chunkFilename: `${fileName}.[id].chunk.[hash].css`,
}),
new CompressionPlugin(),
]
: [];
// In prod, openapi sometimes misplaces generated files, let's merge that
if (!dev) {
const files = glob.sync('bazel-out/*-fastbuild/bin', {});
if (files.length === 1) {
fs.copySync(files[0], process.cwd(), { overwrite: false });
}
}
const webpackConfig = {
devtool: dev ? 'eval-cheap-module-source-map' : undefined,
mode: dev ? 'development' : 'production',
entry: {
main: [...devEntries, ...entries],
},
output: {
filename: `${fileName}.[hash].[id].js`,
chunkFilename: `${fileName}.[id].chunk.[hash].js`,
publicPath: '/',
library: name || 'PRD',
},
devServer: dev
? {
publicPath: '/',
http2: true,
hot: true,
liveReload: false,
historyApiFallback: {
index: '/',
},
watchOptions: {
ignored: /node_modules/,
},
stats: {
colors: true,
hash: false,
version: false,
timings: false,
assets: false,
chunks: false,
modules: false,
reasons: false,
children: false,
source: false,
errors: false,
errorDetails: false,
warnings: false,
publicPath: false,
},
}
: {},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less', '.scss', '.css'],
alias: {
'bazel-bin': resolve(process.cwd()),
common: resolve(process.cwd(), 'common'),
tailwind: resolve(process.cwd(), 'tailwind'),
},
modules,
},
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin(), new TerserJSPlugin()],
splitChunks: {
chunks: 'all',
name: dev ? false : 'all',
minSize: 30000,
maxSize: 300000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
runtimeChunk: 'single',
usedExports: true,
},
plugins: [
indexHtml !== 'null' &&
new HtmlWebpackPlugin({
filename: dev ? 'index.html' : 'index.hbs',
template: htmlFile,
templateParameters: {
script: bodyScript !== '' ? bodyScript : null,
style: headStyle !== '' ? headStyle : null,
title: title || name || 'Peridot',
typekit: typekit !== 'none' ? typekit : null,
},
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(apiUrl),
'process.env.API_KEY': JSON.stringify(apiKey),
}),
...devPlugins,
...prodPlugins,
],
module: {
rules: [
{
test: /\.(js|ts)x?$/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
configFile: resolve(
process.cwd(),
'rules_resf/internal/resf_bundle/babel.config.js'
),
plugins: [dev && require.resolve('react-refresh/babel')].filter(
Boolean
),
},
},
],
exclude: /node_modules\/(?!antd)/,
sideEffects: false,
},
{
test: /\.(css|scss|sass)$/,
use: [
dev ? require.resolve('style-loader') : MiniCssExtractPlugin.loader,
require.resolve('css-loader'),
{
loader: require.resolve('postcss-loader'),
options: {
postcssOptions: {
ident: 'postcss',
plugins: [
[
require.resolve('tailwindcss'),
{
config: resolve(process.cwd(), 'TMPL_tailwind_config'),
},
],
require.resolve('autoprefixer'),
],
},
},
},
],
},
{
test: /\.(woff|woff2)$/,
use: [
{
loader: require.resolve('file-loader'),
options: {},
},
],
},
],
},
};
module.exports = webpackConfig;