UNPKG

@nx/rspack

Version:

The Nx Plugin for Rspack contains executors and generators that support building applications using Rspack.

393 lines (392 loc) • 15.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.applyWebConfig = applyWebConfig; const core_1 = require("@rspack/core"); const instantiate_script_plugins_1 = require("./instantiate-script-plugins"); const path_1 = require("path"); const hash_format_1 = require("./hash-format"); const normalize_entry_1 = require("./normalize-entry"); const stylesheet_loaders_1 = require("./loaders/stylesheet-loaders"); function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) { if (global.NX_GRAPH_CREATION) return; // Defaults that was applied from executor schema previously. options.runtimeChunk ??= true; // need this for HMR and other things to work options.extractCss ??= true; options.generateIndexHtml ??= true; options.index = options.index ? (0, path_1.join)(options.root, options.index) : (0, path_1.join)(options.root, options.projectGraph.nodes[options.projectName].data.sourceRoot, 'index.html'); options.styles ??= []; options.scripts ??= []; const isProd = process.env.NODE_ENV === 'production' || options.mode === 'production'; const plugins = [ new core_1.EnvironmentPlugin({ NODE_ENV: isProd ? 'production' : 'development', }), ]; const stylesOptimization = typeof options.optimization === 'object' ? options.optimization.styles : options.optimization; if (Array.isArray(options.scripts)) { plugins.push(...(0, instantiate_script_plugins_1.instantiateScriptPlugins)(options)); } if (options.index && options.generateIndexHtml) { plugins.push(new core_1.HtmlRspackPlugin({ template: options.index, sri: options.subresourceIntegrity ? 'sha256' : undefined, ...(options.baseHref ? { base: { href: options.baseHref } } : {}), ...(config.output?.scriptType === 'module' ? { scriptLoading: 'module' } : {}), })); } const minimizer = []; if (isProd && stylesOptimization) { minimizer.push(new core_1.LightningCssMinimizerRspackPlugin({ test: /\.(?:css|scss|sass|less|styl)$/, })); } if (!options.ssr) { plugins.push(new core_1.DefinePlugin(getClientEnvironment(process.env.NODE_ENV).stringified)); } const entries = {}; const globalStylePaths = []; // Determine hashing format. const hashFormat = (0, hash_format_1.getOutputHashFormat)(options.outputHashing); const sassOptions = options.stylePreprocessorOptions?.sassOptions; const lessOptions = options.stylePreprocessorOptions?.lessOptions; const includePaths = []; if (options?.stylePreprocessorOptions?.includePaths?.length > 0) { options.stylePreprocessorOptions.includePaths.forEach((includePath) => includePaths.push((0, path_1.resolve)(options.root, includePath))); } let lessPathOptions = {}; if (includePaths.length > 0) { lessPathOptions = { paths: includePaths, }; } // Process global styles. if (options.styles.length > 0) { (0, normalize_entry_1.normalizeExtraEntryPoints)(options.styles, 'styles').forEach((style) => { const resolvedPath = style.input.startsWith('.') ? style.input : (0, path_1.resolve)(options.root, style.input); // Add global css paths. globalStylePaths.push(resolvedPath); }); } const cssModuleRules = [ { test: /\.module\.css$/, exclude: globalStylePaths, use: (0, stylesheet_loaders_1.getCommonLoadersForCssModules)(options, includePaths), }, { test: /\.module\.(scss|sass)$/, exclude: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForCssModules)(options, includePaths), { loader: require.resolve('sass-loader'), options: { implementation: options.sassImplementation === 'sass-embedded' ? require.resolve('sass-embedded') : require.resolve('sass'), api: 'modern-compiler', sassOptions: { fiber: false, precision: 8, includePaths, ...(sassOptions ?? {}), }, }, }, ], }, { test: /\.module\.less$/, exclude: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForCssModules)(options, includePaths), { loader: require.resolve('less-loader'), options: { lessOptions: { paths: includePaths, ...(lessOptions ?? {}), }, }, }, ], }, { test: /\.module\.styl$/, exclude: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForCssModules)(options, includePaths), { loader: (0, path_1.join)(__dirname, '../../../utils/webpack/deprecated-stylus-loader.js'), options: { stylusOptions: { include: includePaths, }, }, }, ], }, ]; const globalCssRules = [ { test: /\.css$/, exclude: globalStylePaths, use: (0, stylesheet_loaders_1.getCommonLoadersForGlobalCss)(options, includePaths), }, { test: /\.scss$|\.sass$/, exclude: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForGlobalCss)(options, includePaths), { loader: require.resolve('sass-loader'), options: { api: 'modern-compiler', implementation: options.sassImplementation === 'sass-embedded' ? require.resolve('sass-embedded') : require.resolve('sass'), sourceMap: !!options.sourceMap, sassOptions: { fiber: false, // bootstrap-sass requires a minimum precision of 8 precision: 8, includePaths, ...(sassOptions ?? {}), }, }, }, ], }, { test: /\.less$/, exclude: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForGlobalCss)(options, includePaths), { loader: require.resolve('less-loader'), options: { sourceMap: !!options.sourceMap, lessOptions: { javascriptEnabled: true, ...lessPathOptions, ...(lessOptions ?? {}), }, }, }, ], }, { test: /\.styl$/, exclude: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForGlobalCss)(options, includePaths), { loader: (0, path_1.join)(__dirname, '../../../utils/webpack/deprecated-stylus-loader.js'), options: { sourceMap: !!options.sourceMap, stylusOptions: { include: includePaths, }, }, }, ], }, ]; const globalStyleRules = [ { test: /\.css$/, include: globalStylePaths, use: (0, stylesheet_loaders_1.getCommonLoadersForGlobalStyle)(options, includePaths), }, { test: /\.scss$|\.sass$/, include: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForGlobalStyle)(options, includePaths), { loader: require.resolve('sass-loader'), options: { api: 'modern-compiler', implementation: options.sassImplementation === 'sass-embedded' ? require.resolve('sass-embedded') : require.resolve('sass'), sourceMap: !!options.sourceMap, sassOptions: { fiber: false, // bootstrap-sass requires a minimum precision of 8 precision: 8, includePaths, ...(sassOptions ?? {}), }, }, }, ], }, { test: /\.less$/, include: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForGlobalStyle)(options, includePaths), { loader: require.resolve('less-loader'), options: { sourceMap: !!options.sourceMap, lessOptions: { javascriptEnabled: true, ...lessPathOptions, ...(lessOptions ?? {}), }, }, }, ], }, { test: /\.styl$/, include: globalStylePaths, use: [ ...(0, stylesheet_loaders_1.getCommonLoadersForGlobalStyle)(options, includePaths), { loader: (0, path_1.join)(__dirname, '../../../utils/webpack/deprecated-stylus-loader.js'), options: { sourceMap: !!options.sourceMap, stylusOptions: { include: includePaths, }, }, }, ], }, ]; const rules = [ { test: /\.css$|\.scss$|\.sass$|\.less$|\.styl$/, oneOf: [...cssModuleRules, ...globalCssRules, ...globalStyleRules], }, ]; if (options.extractCss) { plugins.push( // extract global css from js files into own css file new core_1.CssExtractRspackPlugin({ filename: `[name]${hashFormat.extract}.css`, })); } config.output = { ...(config.output ?? {}), assetModuleFilename: '[name].[contenthash:16][ext]', crossOriginLoading: 'anonymous', }; // In case users customize their rspack config with unsupported entry. if (typeof config.entry === 'function') throw new Error('Entry function is not supported. Use an object.'); if (typeof config.entry === 'string') throw new Error('Entry string is not supported. Use an object.'); if (Array.isArray(config.entry)) throw new Error('Entry array is not supported. Use an object.'); Object.entries(entries).forEach(([entryName, entryData]) => { if (useNormalizedEntry) { config.entry[entryName] = { import: entryData.import }; } else { config.entry[entryName] = entryData.import; } }); config.optimization = !isProd ? {} : { ...(config.optimization ?? {}), minimizer: [...(config.optimization?.minimizer ?? []), ...minimizer], emitOnErrors: false, moduleIds: 'deterministic', runtimeChunk: options.runtimeChunk ? { name: 'runtime' } : false, splitChunks: { defaultSizeTypes: config.optimization?.splitChunks !== false ? config.optimization?.splitChunks?.defaultSizeTypes : ['...'], maxAsyncRequests: Infinity, cacheGroups: { default: !!options.commonChunk && { chunks: 'async', minChunks: 2, priority: 10, }, common: !!options.commonChunk && { name: 'common', chunks: 'async', minChunks: 2, enforce: true, priority: 5, }, vendors: false, vendor: !!options.vendorChunk && { name: 'vendor', chunks: (chunk) => chunk.name === 'main', enforce: true, test: /[\\/]node_modules[\\/]/, }, }, }, }; config.resolve.mainFields = ['browser', 'module', 'main']; config.module = { ...(config.module ?? {}), rules: [ ...(config.module.rules ?? []), // Images: Inline small images, and emit a separate file otherwise. { test: /\.(avif|bmp|gif|ico|jpe?g|png|webp)$/, type: 'asset', parser: { dataUrlCondition: { maxSize: 10_000, // 10 kB }, }, }, // SVG: same as image but we need to separate it so it can be swapped for SVGR in the React plugin. { test: /\.svg$/, type: 'asset', parser: { dataUrlCondition: { maxSize: 10_000, // 10 kB }, }, }, // Fonts: Emit separate file and export the URL. { test: /\.(eot|otf|ttf|woff|woff2)$/, type: 'asset/resource', }, ...rules, ], }; config.plugins ??= []; config.plugins.push(...plugins); } function getClientEnvironment(mode) { // Grab NODE_ENV and NX_PUBLIC_* environment variables and prepare them to be // injected into the application via DefinePlugin in rspack configuration. const nxPublicKeyRegex = /^NX_PUBLIC_/i; const raw = Object.keys(process.env) .filter((key) => nxPublicKeyRegex.test(key)) .reduce((env, key) => { env[key] = process.env[key]; return env; }, {}); // Stringify all values so we can feed into rspack DefinePlugin const stringified = { 'process.env': Object.keys(raw).reduce((env, key) => { env[key] = JSON.stringify(raw[key]); return env; }, {}), }; return { stringified }; }