UNPKG

@pega/custom-dx-components

Version:

Utility for building custom UI components

364 lines (343 loc) 13.7 kB
import { createRequire } from 'module'; import webpack from 'webpack'; import TerserPlugin from 'terser-webpack-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; import getCSSModuleLocalIdent from 'react-dev-utils/getCSSModuleLocalIdent.js'; import ModuleNotFoundPlugin from 'react-dev-utils/ModuleNotFoundPlugin.js'; import CompressionPlugin from 'compression-webpack-plugin'; import paths from './paths.js'; const require = createRequire(import.meta.url); // const appPackageJson = require(paths.appPackageJson); // Source maps are resource heavy and can cause out of memory issue for large source files. const compressionBRConfObj = { filename: '[path][base].br', algorithm: 'brotliCompress', test: /\.(js|css|html|svg|png|jpg|woff|woff2)$/, compressionOptions: { level: 11 } }; /* For gzip use below */ const compressionGZConfObj = { filename: '[path][base].gz', algorithm: 'gzip', test: /\.(js|css|html|svg|png|jpg|woff|woff2)$/, compressionOptions: { level: 9 } }; let shouldUseSourceMap = process.env.SOURCE_MAP; const imageInlineSizeLimit = Number.parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000', 10); // style files regex const cssRegex = /\.css$/; const cssModuleRegex = /\.module\.css$/; const sassRegex = /\.(scss|sass)$/; const sassModuleRegex = /\.module\.(scss|sass)$/; // This is the production and development configuration. // It is focused on developer experience, fast rebuilds, and a minimal bundle. export default ( webpackEnv, // eslint-disable-next-line no-unused-vars { inputFile, outputFile, componentKey, externals, globals, sourceMap, devBuild } ) => { const isEnvDevelopment = webpackEnv === 'development' || devBuild; const isEnvProduction = webpackEnv === 'production'; sourceMap = sourceMap === 'true'; shouldUseSourceMap = shouldUseSourceMap || sourceMap; // common function to get style loaders const getStyleLoaders = (cssOptions, preProcessor) => { const loaders = [ isEnvProduction && { loader: MiniCssExtractPlugin.loader }, { loader: require.resolve('css-loader'), options: cssOptions }, { // Options for PostCSS as we reference these options twice // Adds vendor prefixing based on your specified browser support in // package.json loader: require.resolve('postcss-loader'), options: { postcssOptions: { plugins: [ [ 'postcss-preset-env', { // Options } ] ] }, sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment } } ].filter(Boolean); if (preProcessor) { loaders.push( { loader: require.resolve('resolve-url-loader'), options: { sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment, root: paths.appSrc } }, { loader: require.resolve(preProcessor), options: { sourceMap: true } } ); } return loaders; }; return { mode: devBuild ? 'development' : 'production', // Stop compilation early in production bail: isEnvProduction, // These are the "entry points" to our application. // This means they will be the "root" imports that are included in JS bundle. entry: inputFile, devtool: devBuild ? 'eval-cheap-module-source-map' : false, output: { // The build folder. path: paths.appBuild, // There will be one main bundle, and one file per asynchronous chunk. // In development, it does not produce real files. filename: isEnvProduction ? `${componentKey}/${componentKey}.js` : isEnvDevelopment && `${componentKey}/${componentKey}.js`, chunkFilename: isEnvProduction ? `${componentKey}/js/[name].[contenthash:8].chunk.js` : isEnvDevelopment && `${componentKey}/js/[name].chunk.js`, library: { name: componentKey, type: 'umd', export: 'default' }, publicPath: '' }, optimization: { minimize: isEnvProduction, minimizer: [new TerserPlugin(), new CssMinimizerPlugin()] }, resolve: { plugins: [], extensions: ['.tsx', '.ts', '.js'] }, resolveLoader: { plugins: [] }, module: { strictExportPresence: true, rules: [ { // "oneOf" will traverse all following loaders until one will // match the requirements. When no loader matches it will fall // back to the "file" loader at the end of the loader list. oneOf: [ // TODO: Merge this config once `image/avif` is in the mime-db // https://github.com/jshttp/mime-db { test: [/\.avif$/], loader: require.resolve('url-loader'), options: { limit: imageInlineSizeLimit, mimetype: 'image/avif', name: `${componentKey}/media/[name].[hash:8].[ext]` } }, // "url" loader works like "file" loader except that it embeds assets // smaller than specified limit in bytes as data URLs to avoid requests. // A missing `test` is equivalent to a match. { test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/], loader: require.resolve('url-loader'), options: { limit: imageInlineSizeLimit, name: `${componentKey}/media/[name].[hash:8].[ext]` } }, // Process application JS with TS-Loader. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { test: /\.(js|mjs|jsx)$/, include: paths.appSrc, loader: 'ts-loader', options: { configFile: 'tsconfig.build.json' }, exclude: /node_modules/ }, { test: /\.(ts|tsx)$/, loader: 'ts-loader', options: { configFile: 'tsconfig.build.json' }, exclude: /node_modules/ }, // "postcss" loader applies autoprefixer to our CSS. // "css" loader resolves paths in CSS and adds assets as dependencies. // "style" loader turns CSS into JS modules that inject <style> tags. // In production, we use MiniCSSExtractPlugin to extract that CSS // to a file, but in development "style" loader enables hot editing // of CSS. // By default we support CSS Modules with the extension .module.css { test: cssRegex, exclude: cssModuleRegex, use: getStyleLoaders({ importLoaders: 1, sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment }), // Don't consider CSS imports dead code even if the // containing package claims to have no side effects. // Remove this when webpack adds a warning or an error for this. // See https://github.com/webpack/webpack/issues/6571 sideEffects: true }, // Adds support for CSS Modules (https://github.com/css-modules/css-modules) // using the extension .module.css { test: cssModuleRegex, use: getStyleLoaders({ importLoaders: 1, sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment, modules: { getLocalIdent: getCSSModuleLocalIdent } }) }, // Opt-in support for SASS (using .scss or .sass extensions). // By default we support SASS Modules with the // extensions .module.scss or .module.sass { test: sassRegex, exclude: sassModuleRegex, use: getStyleLoaders( { importLoaders: 3, sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment }, 'sass-loader' ), // Don't consider CSS imports dead code even if the // containing package claims to have no side effects. // Remove this when webpack adds a warning or an error for this. // See https://github.com/webpack/webpack/issues/6571 sideEffects: true }, // Adds support for CSS Modules, but using SASS // using the extension .module.scss or .module.sass { test: sassModuleRegex, use: getStyleLoaders( { importLoaders: 3, sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment, modules: { getLocalIdent: getCSSModuleLocalIdent } }, 'sass-loader' ) }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. // This loader doesn't use a "test" so it will catch all modules // that fall through the other loaders. { loader: require.resolve('file-loader'), // Exclude `js` files to keep "css" loader working as it injects // its runtime that would otherwise be processed through "file" loader. // Also exclude `html` and `json` extensions so they get processed // by webpack's internal loaders. exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], options: { name: `${componentKey}/media/[name].[hash:8].[ext]` } } // ** STOP ** Are you adding a new loader? // Make sure to add the new loader(s) before the "file" loader. ] } ] }, plugins: [ // This gives some necessary context to module not found errors, such as // the requesting resource. new ModuleNotFoundPlugin(paths.appPath), // Makes some environment variables available to the JS code, for example: // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. // It is absolutely essential that NODE_ENV is set to production // during a production build. // Otherwise React will be compiled in the very slow development mode. isEnvProduction && new webpack.DefinePlugin({ PRODUCTION: JSON.stringify(true) }), isEnvProduction && new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: `${componentKey}/css/${componentKey}.[contenthash:8].css`, chunkFilename: `${componentKey}/css/${componentKey}.[contenthash:8].chunk.css` }), // Moment.js is an extremely popular library that bundles large locale files // by default due to how webpack interprets its code. This is a practical // solution that requires the user to opt into importing specific locales. // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ }), /* cosmos 4.x and below */ /* 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 */ /* Ignore cosmos icons */ 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 webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }), new webpack.optimize.MinChunkSizePlugin({ minChunkSize: 100000 // Minimum number of characters }), !devBuild && new CompressionPlugin(compressionBRConfObj) /* Dont generate gzip file */ /* isEnvProduction && new CompressionPlugin(compressionGZConfObj) */ ].filter(Boolean), performance: { hints: false, maxEntrypointSize: 512000, maxAssetSize: 512000 }, externals }; };