Can you use vanilla JavaScript in NestJS

Updated: January 1, 2024 By: Guest Contributor Post a comment

Introduction

NestJS is a progressive Node.js framework for building server-side applications, but what about incorporating vanilla JavaScript? This guide explores seamless integration and application in the NestJS context.

Understanding NestJS and JavaScript

NestJS, while built with TypeScript, is fully compatible with JavaScript. Nonetheless, it leverages TypeScript features for improved productivity and scalability. To embody vanilla JavaScript in NestJS, one should compile TypeScript into JavaScript or directly code in JavaScript. Below are examples showcasing the transition from TypeScript to JavaScript in a NestJS application:

// Basics: A simple controller
// In TypeScript (NestJS default)
import { Controller, Get } from '@nestjs/common';

@Controller('hello-world')
export class HelloWorldController {
  @Get()
  getHello(): string {
    return 'Hello World';
  }
}

// In JavaScript (vanilla)
const { Controller, Get } = require('@nestjs/common');

@Controller('hello-world')
class HelloWorldController {
  @Get()
  getHello() {
    return 'Hello World';
  }
}

module.exports = { HelloWorldController };

Setting Up a JavaScript-Based NestJS Project

To start with vanilla JavaScript in NestJS, set up the project to support JavaScript. This section walks through using NestJS CLI and adjusting it for a JavaScript environment, touching on tsconfig.json, Typescript compilation, and renaming files from .ts to .js.

// Setting up NestJS with JavaScript
const nestCli = require('@nestjs/cli');

nestCli.run(['new', 'nest-js-vanilla'], {
  language: 'js', // Instructing to use JavaScript
}).then(() => {
  // Additional configuration and dependency installation
});

Integrating Vanilla JavaScript Functions

Including vanilla JavaScript functions in a NestJS app can enhance its functionality. It’s possible to integrate plain JavaScript utilities or scripts without TypeScript classes or decorators. This provides flexibility, particularly for those with existing JavaScript codebases.

// Vanilla JavaScript function in a service
function calculateSum(a, b) {
  return a + b;
}

module.exports = { calculateSum };

Services and Dependency Injection in JavaScript

Even without TypeScript, NestJS retains its DI system. Services, now without decorators, should be registered explicitly with the module’s providers array. Look at how we transition from a TypeScript service to a purely JavaScript one and how to register it.

// TypeScript version
import { Injectable } from '@nestjs/common';

@Injectable()
export class AdditionService {
  calculate(a, b) {
    return a + b;
  }
}

// JavaScript version
class AdditionService {
  calculate(a, b) {
    return a + b;
  }
}

module.exports = { AdditionService };

Middleware and Interceptors in Vanilla JavaScript

Middleware and interceptors enhance control over the request-response cycle. Even if we discard TypeScript, the Nest structure remains intact. Let’s dig into implementing a middleware both in TypeScript, and then in plain JavaScript without decorators.

// TypeScript middleware
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(req.method, req.url);
    next();
  }
}

// JavaScript middleware
const { NestMiddleware } = require('@nestjs/common');

class LoggerMiddleware {
  use(req, res, next) {
    console.log(req.method, req.url);
    next();
  }
}

module.exports = { LoggerMiddleware };

Advanced Patterns and Modules

NestJS modules can too be created with vanilla JavaScript, as they organize related code. Dynamic modules and complex patterns showcase power regardless of the language choice. Here’s an overview of constructing a module without TypeScript.

// JavaScript NestJS module
const { Module } = require('@nestjs/common');
const { LoggerMiddleware } = require('./logger.middleware');
const { HelloWorldController } = require('./hello-world.controller');

@Module({
  controllers: [HelloWorldController],
  providers: [],
})
class AppModule {}

module.exports = { AppModule };

Testing with Vanilla JavaScript

Testing remains crucial and unaltered at its core. Unit tests in JavaScript for your Nest services and controllers allow you to maintain code quality. This piece illustrates JavaScript tests for a NestJS HTTP controller without relying on TypeScript.

// JavaScript Jest test for a NestJS controller
const { HelloWorldController } = require('./hello-world.controller');

describe('HelloWorldController', () => {
  let helloWorldController;

  beforeEach(() => {
    helloWorldController = new HelloWorldController();
  });

  describe('getHello', () => {
    it('should return "Hello World"', () => {
      expect(helloWorldController.getHello()).toBe('Hello World');
    });
  });
});

Conclusion

NestJS’s flexibility allows the use of vanilla JavaScript, offering a bridge for those transitioning from a JavaScript background. We have walked through integrating JavaScript in various aspects of a NestJS app, proving that simplified JavaScript can coexist and thrive within the Nest ecosystem.