@nestjs/cli
Version:
Nest - modern, fast, powerful node.js web framework (@cli)
180 lines (179 loc) • 7.03 kB
JavaScript
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));
}