Debugging NestJS app in NRWL NX workspace

Debugging can save you ton of time. But sometimes to set up debugging configuration correctly can be a nightmare. There are several common gotchas which may trick you.

  • Code is in Typescript, but NodeJS in debugger does not understand its syntax.
  • You use combination of .ts and .js files with import or export statement
  • Debugger does not attach, and breakpoints are ignored
  • False positive detection of debug mode (flag --inspect or --inspect-brk did not work for my use case)

NRWL NX is a great tool, but somewhat it complicated debugging of NestJS app. At least for me 🙂 So after a couple of hours of trial and error, this is what finally works for me.

launch.json

Notice that --experimental-modules is turned on. Also notice usage of pwa-node, and specification of env variables.

{
	"version": "0.2.0",
	"configurations": [
		{
			"name": "Debug my NESTJS app",
			"type": "pwa-node",
			"request": "launch",
			"args": ["src/main.ts"], // Path to main entry file
			"runtimeArgs": ["--require", "ts-node/register", "--require", "tsconfig-paths/register", "--experimental-modules"],
			"cwd": "${workspaceRoot}",
			"internalConsoleOptions": "openOnSessionStart",
			"env": {
				"NODE_ENV": "local",
				"NODE_PORT": "8000",
				"TS_NODE_PROJECT": "tsconfig.debug.json", // Specify the tsconfig to use. See content of it below.
				"IS_DEBUG_MODE": "true" // Custom env variable to detect debug mode
			},
			"sourceMaps": true,
			"console": "internalConsole",
			"outputCapture": "std",
			"resolveSourceMapLocations": [
				"${workspaceFolder}/**",
				"!**/node_modules/**" // Disable the "could not read source map" error for node_modules
			]
		}
	]
}

tsconfig.debug.json

{
	"extends": "./tsconfig.json",
	"compilerOptions": {
		"outDir": "../../dist/out-tsc",
		"types": ["node"],
		"emitDecoratorMetadata": true,
		"target": "es6",
		"module": "commonjs",
		"importHelpers": false,
		"allowJs": true // Fixes combination of .js and .ts files
	},
	"exclude": ["**/*.spec.ts"],
	"include": ["**/*.ts"]
}

Detection of debug mode inside running application

export function isInDebugMode(): boolean {
	// can not rely on "--inspect" flag, because that is used when launched via NX. Even in standard launching.
	// "--inspect-brk" flag did not work either
	// So in normal situation you would use this:
	// return /--inspect/.test(process.execArgv.join(' '));

	// Workaround using ENV variable
	return process.env['IS_DEBUG_MODE'] === 'true';
}

Fix of path to files in debug mode

Normally the asset files would be in workspace/dist/appname/assets folder. That applies when application is launched normally via nx serve appname command. But when you launch app in debug mode, then the __dirname variable may resolve differently, and then the app crashes.

So this is my workaround.

export class SomeFileService {
	private readonly encoding = 'utf8';

	// Different path in debug mode and standard mode
	private readonly pathToFile = isInDebugMode()
		? path.resolve('./', 'src/assets/configs/predefined-programs.json')
		: path.resolve(__dirname, 'assets/configs/predefined-programs.json');

        async readFile(): Promise<T> {
		return await readFile(this.pathToFile, this.encoding)
			.then((data) => {
				const parsedData = JSON.parse(data);
				return parsedData;
			})
			.catch((err) => {
				console.error('SomeFileService: Error reading data from ' + this.pathToFile, err);
			});
	}
}

Happy coding.