/* * 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;