Back to Rspack

NestJS

website/docs/en/guide/tech/nestjs.mdx

2.0.37.2 KB
Original Source

import { PackageManagerTabs } from '@theme';

NestJS

Rspack can build NestJS applications. Compared with tsc, Rspack can bundle application code, transform TypeScript with SWC, enable development HMR, and leave runtime dependencies external when needed.

How to use

Start with the common Node.js application configuration, then add the NestJS settings described below. You can also use the NestJS example in rstack-examples as a reference. It includes a complete rspack.config.mjs, development script, production build script, and HMR entry.

Example

The rstack-examples repository contains a complete NestJS application built with Rspack.

Install dependencies

Install the common Node.js build dependencies from the Node.js guide, then install the NestJS runtime packages:

<PackageManagerTabs command="add @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs" />

Basic concepts

NestJS applications run in Node.js, so most configurations can follow the common Node.js configuration. The main NestJS-specific requirement is decorator metadata, which NestJS uses at runtime.

  • Decorator metadata: Enable TypeScript decorators and emitted metadata so dependency injection, controllers, routes, guards, interceptors, and other NestJS features work correctly.
  • HMR cleanup: When development HMR updates the server bundle, close the previous Nest application instance before accepting the update.
  • Production minification: Keep class and function names stable because NestJS may use them through metadata reflection and execution context APIs.

Configure Rspack

The following configuration is adapted from the NestJS example. It combines the common Node.js setup with the decorator metadata options required by NestJS:

js
// @ts-check
import { defineConfig } from '@rspack/cli';
import { rspack } from '@rspack/core';
import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin';
import nodeExternals from 'webpack-node-externals';

export default defineConfig({
  context: import.meta.dirname,
  target: 'node',
  entry: {
    main:
      process.env.NODE_ENV === 'production'
        ? './src/main.ts'
        : ['@rspack/core/hot/poll?100', './src/main.ts'],
  },
  output: {
    clean: true,
  },
  resolve: {
    extensions: ['...', '.ts', '.tsx', '.jsx'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: {
          loader: 'builtin:swc-loader',
          options: {
            detectSyntax: 'auto',
            jsc: {
              parser: {
                decorators: true,
              },
              transform: {
                legacyDecorator: true,
                decoratorMetadata: true,
              },
            },
          },
        },
      },
    ],
  },
  optimization: {
    minimizer: [
      new rspack.SwcJsMinimizerRspackPlugin({
        minimizerOptions: {
          compress: {
            keep_classnames: true,
            keep_fnames: true,
          },
          mangle: {
            keep_classnames: true,
            keep_fnames: true,
          },
        },
      }),
    ],
  },
  plugins: [
    process.env.NODE_ENV !== 'production' &&
      new RunScriptWebpackPlugin({
        name: 'main.js',
        autoRestart: false,
      }),
  ],
  devServer: {
    devMiddleware: {
      writeToDisk: true,
    },
  },
  externals: [
    nodeExternals({
      allowlist: [/@rspack\/core\/hot\/poll/],
    }),
  ],
});

Configure scripts

Use rspack dev during development and rspack build for production:

json
{
  "scripts": {
    "build": "rspack build",
    "dev": "rspack dev",
    "start": "node dist/main.js"
  }
}
  • dev: Runs Rspack Dev Server, writes the server bundle to disk, and starts dist/main.js.
  • build: Creates a production bundle without the HMR polling entry.
  • start: Runs the production bundle with Node.js.

Configure TypeScript decorators

NestJS uses decorators such as @Module(), @Controller(), @Injectable(), and @Get(). Configure builtin:swc-loader so SWC can parse these decorators and emit the metadata NestJS needs:

js
export default {
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: {
          loader: 'builtin:swc-loader',
          options: {
            detectSyntax: 'auto',
            jsc: {
              parser: {
                decorators: true,
              },
              transform: {
                legacyDecorator: true,
                decoratorMetadata: true,
              },
            },
          },
        },
      },
    ],
  },
};

If your project also runs tsc, keep experimentalDecorators and emitDecoratorMetadata enabled in tsconfig.json so TypeScript and Rspack use the same decorator assumptions:

json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Configure development HMR

Add @rspack/core/hot/poll only in development. If it is included in the production bundle, the Node.js application will fail at runtime because HMR is not available in build mode:

js
export default {
  entry: {
    main:
      process.env.NODE_ENV === 'production'
        ? './src/main.ts'
        : ['@rspack/core/hot/poll?100', './src/main.ts'],
  },
};

Add HMR handling to the NestJS bootstrap file. This closes the old application instance before accepting the updated module:

ts
declare const module: any;

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}

bootstrap();

See Node.js - Configure development HMR for the shared Rspack entry, writeToDisk, RunScriptWebpackPlugin, and externals allowlist settings used with this bootstrap code. If your project needs ESM output, see Node.js - Use ESM output.

Configure production minification

When minifying a NestJS server bundle, keep class names and function names. NestJS can rely on stable class and handler references through metadata reflection and execution context APIs.

js
import { rspack } from '@rspack/core';

export default {
  optimization: {
    minimizer: [
      new rspack.SwcJsMinimizerRspackPlugin({
        minimizerOptions: {
          compress: {
            keep_classnames: true,
            keep_fnames: true,
          },
          mangle: {
            keep_classnames: true,
            keep_fnames: true,
          },
        },
      }),
    ],
  },
};

Native node modules

If a NestJS dependency includes a Node.js native addon (.node module), follow Node.js - Native node modules to emit the addon with asset/resource and let Node.js load it at runtime.