UNPKG

@nestjs/cli

Version:

Nest - modern, fast, powerful node.js web framework (@cli)

180 lines (179 loc) 7.03 kB
import { builtinModules, createRequire } from 'module'; import { join } from 'path'; import { defaultTsconfigFilename } from '../../configuration/defaults.js'; import { appendTsExtension } from '../helpers/append-extension.js'; const require = createRequire(import.meta.url); function loadRspackDeps() { try { const rspack = require('@rspack/core'); const externals = require('webpack-node-externals'); const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin'); return { nodeExternals: externals, TsconfigPathsPlugin, rspack }; } catch (e) { if (e?.code !== 'MODULE_NOT_FOUND' && e?.code !== 'ERR_MODULE_NOT_FOUND') { // Only the "package missing" branch is wrapped with install advice. // Surfacing unrelated errors as "package not found" would mislead // users into reinstalling perfectly valid dependencies. throw e; } // Use a non-greedy match so error messages that contain multiple // quoted paths (e.g. ESM "Cannot find package 'foo' imported from // '/abs/path.mjs'") still extract the package name rather than the // importing file path. const pkg = e?.message?.match?.(/Cannot find.*?'([^']+)'/)?.[1] ?? 'webpack-node-externals'; throw new Error(`The "${pkg}" package is required when using the rspack compiler but could not be found. ` + `Please install it:\n\n npm install --save-dev @rspack/core webpack-node-externals tsconfig-paths-webpack-plugin\n`, { cause: e }); } } export const rspackDefaultsFactory = (sourceRoot, relativeSourceRoot, entryFilename, isDebugEnabled = false, tsConfigFile = defaultTsconfigFilename, plugins, isEsm = false, tsOptions) => { const { nodeExternals: externals, TsconfigPathsPlugin } = loadRspackDeps(); const isPluginRegistered = isAnyPluginRegistered(plugins); const sourceMaps = tsOptions?.sourceMap || (tsOptions?.inlineSourceMap && 'inline'); const devtool = sourceMaps === 'inline' ? 'inline-source-map' : sourceMaps ? 'source-map' : false; const rspackConfiguration = { entry: appendTsExtension(join(sourceRoot, entryFilename)), devtool, target: 'node', output: { filename: join(relativeSourceRoot, `${entryFilename}.js`).replace(/\\/g, '/'), ...(isEsm && { module: true, library: { type: 'module' }, chunkFormat: 'module', chunkLoading: 'import', }), }, ...(isEsm && { experiments: { outputModule: true, topLevelAwait: true }, }), ignoreWarnings: [/^(?!CriticalDependenciesWarning$)/], externals: [ externals(isEsm ? { importType: 'module' } : {}), ...(isEsm ? [ ({ request }, callback) => { if (!request) return callback(); const bare = request.startsWith('node:') ? request.slice(5) : request; if (builtinModules.includes(bare)) { return callback(null, `module ${request}`); } callback(); }, ] : []), ], externalsPresets: { node: !isEsm }, module: { rules: [ { test: /\.tsx?$/, use: [ { loader: 'builtin:swc-loader', options: { jsc: { parser: { syntax: 'typescript', decorators: true, }, transform: { legacyDecorator: true, decoratorMetadata: true, }, target: 'es2021', }, sourceMaps, }, }, ], exclude: /node_modules/, ...(isEsm && { type: 'javascript/esm' }), }, ], }, resolve: { extensions: ['.tsx', '.ts', '.js'], ...(isEsm && { extensionAlias: { '.js': ['.ts', '.js'], '.mjs': ['.mts', '.mjs'], }, }), tsConfig: tsConfigFile, plugins: [ new TsconfigPathsPlugin({ configFile: tsConfigFile, }), ], }, mode: 'none', optimization: { nodeEnv: false, }, node: { __filename: false, __dirname: false, }, plugins: [], }; // rspack has built-in IgnorePlugin (compatible with webpack's) try { const rspack = require('@rspack/core'); rspackConfiguration.plugins.push(new rspack.IgnorePlugin({ checkResource(resource) { const lazyImports = [ '@nestjs/microservices', '@nestjs/microservices/microservices-module', '@nestjs/websockets/socket-module', 'class-validator', 'class-transformer', 'class-transformer/storage', ]; if (!lazyImports.includes(resource)) { return false; } try { require.resolve(resource, { paths: [process.cwd()], }); } catch { return true; } return false; }, })); } catch { // @rspack/core not available, skip IgnorePlugin } if (!isPluginRegistered) { try { const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); rspackConfiguration.plugins.push(new ForkTsCheckerWebpackPlugin({ typescript: { configFile: tsConfigFile, }, })); } catch { // fork-ts-checker-webpack-plugin not available, skip } } return rspackConfiguration; }; function isAnyPluginRegistered(plugins) { return ((plugins.afterHooks && plugins.afterHooks.length > 0) || (plugins.beforeHooks && plugins.beforeHooks.length > 0) || (plugins.afterDeclarationsHooks && plugins.afterDeclarationsHooks.length > 0)); }