Getting started with NestJS, Vite, and esbuild
Tags: webdev, vite
Published: 2022-09-15 17:07:32

**Written by [Alexander Nnakwue](https://blog.logrocket.com/author/alexandernnakwue/)✏️**

## Introduction

In this article, we’ll learn about NestJS, Vite, and esbuild; how they work together; and how to configure a NestJS app to make use of both other tools as dependencies. In the process, we will get to learn how to work with them in real life scenarios, their major features, and use cases. 

_Jump ahead:_

*   [What is NestJS?](#what-is-nestjs)
*   [What is Vite?](#what-is-vite)
*   [What is esbuild?](#what-is-esbuild)
*   [Installing and configuring a NestJS app](#installing-configuring-nestjs-app)
*   [Exploring the NestJS boilerplate](#exploring-nestjs-boilerplate)
*   [Installing Vite and esbuild with NestJS](#installing-vite-esbuild-nestjs)

## What is NestJS?

[NestJS](https://docs.nestjs.com/) is a Node.js framework for building efficient and scalable enterprise server-side/backend applications. According to the documentation, it supports all latest ECMAScript versions of both JavaScript and TypeScript. 

NestJS combines the well-known programming concepts and philosophies of OOP, functional programming, and functional reactive programming to solve the architectural challenges in the design of backend applications that are scalable, maintainable, easily testable, and are not tightly coupled together. 

Although NestJS is [platform independent](https://docs.nestjs.com/first-steps#platform) and can work with any Node.js library if a binding is written for it, NestJS uses Express as a dependency by default, and can also be configured to use Fastify. This ease in configuring the framework via exposed APIs with other third-party modules makes it very easy for developers to customize the framework on a case-by-case basis.

## What is Vite?

[Vite](https://vitejs.dev/) is a build tool with [lots of features](https://vitejs.dev/guide/features.html), chief of which is a near-instant dev server startup time. It leverages the introduction of native ES modules in the browser and tooling written with languages that compile to native code to solve the issues with [previous build tools](https://blog.logrocket.com/webpack-or-esbuild-why-not-both/) (webpack, Parcel, etc.) relating to performance. 

Vite works by first dividing the modules in an application into two categories, dependencies and source code, because dependencies rarely change during development. Vite pre-bundles these dependencies using [esbuild](https://esbuild.github.io/) under the hood. For source code that might need transforming (CSS, JSX, etc.), Vite serves them over native ESM to the browser. 

As the browser makes the requests for the source code, Vite transforms and loads them on demand and the browser can use route-based [code-splitting and conditional dynamic imports](https://blog.logrocket.com/dynamic-imports-code-splitting-next-js/) to bundle the needed code, making it a pretty fast process.

## What is esbuild?

esbuild is a blazing fast JavaScript bundler written in Go and makes use of Go’s parallelism and ability to transform source code to machine code. Its features include, among others:

*   Huge plugin support
*   A minifier
*   TypeScript and JSX support
*   Both ES2015 and CommonJS module support
*   Tree-shaking capabilities

## Installing and configuring a NestJS app <a name="installing-configuring-nestjs-app">

Now that we have looked at NestJS, Vite, and esbuild at a high level, let’s proceed to learn about how they work together by configuring a NestJS app to make use of both Vite and esbuild as dependencies. In the process, we‘ll learn how to work with them in real life scenarios, their major features, and prime use cases. 

To get started with NestJS, go ahead and install the CLI, which bootstraps the starter code. This is an especially better option for those who are new to NestJS. 

Another option is to [clone the starter repo](https://github.com/nestjs/typescript-starter) from GitHub. Note that to install the JavaScript flavor of the starter project, we can [clone this repo](https://github.com/nestjs/javascript-starter), but you’ll need Babel to compile vanilla JavaScript). 

For our purposes, we are going to go ahead and install the CLI. Run the following command:

```bash
npm i -g @nestjs/cli
```
After we are done installing the CLI, we can go ahead to create a new Nest project:

```bash
nest new nest_vite_esbuild_demo
```

The output of running this command is shown below:

```bash
nest new nest_vite_esbuild_demo                                                                                 took 24s
⚡  We will scaffold your app in a few seconds..

CREATE nest_vite_esbuild_demo/.eslintrc.js (665 bytes)
CREATE nest_vite_esbuild_demo/.prettierrc (51 bytes)
CREATE nest_vite_esbuild_demo/README.md (3340 bytes)
CREATE nest_vite_esbuild_demo/nest-cli.json (118 bytes)
CREATE nest_vite_esbuild_demo/package.json (2007 bytes)
CREATE nest_vite_esbuild_demo/tsconfig.build.json (97 bytes)
CREATE nest_vite_esbuild_demo/tsconfig.json (546 bytes)
CREATE nest_vite_esbuild_demo/src/app.controller.spec.ts (617 bytes)
CREATE nest_vite_esbuild_demo/src/app.controller.ts (274 bytes)
CREATE nest_vite_esbuild_demo/src/app.module.ts (249 bytes)
CREATE nest_vite_esbuild_demo/src/app.service.ts (142 bytes)
CREATE nest_vite_esbuild_demo/src/main.ts (208 bytes)
CREATE nest_vite_esbuild_demo/test/app.e2e-spec.ts (630 bytes)
CREATE nest_vite_esbuild_demo/test/jest-e2e.json (183 bytes)

? Which package manager would you ❤️  to use? (Use arrow keys)
❯ npm 
  yarn 
  pnpm 
```

Make sure you have the latest Node.js version installed on your machine (except v13, which is [not supported](https://github.com/nestjs/nest/issues/4870)). 

As we can see from the above, the project directory has been populated with Nest’s core files, dependencies, and base modules. Follow the steps and select the package manager of your choice. In this post, we’re using npm. The folder structure at the end of the installation is shown below. 

![The folder structure for scaffolding our NestJS app](https://blog.logrocket.com/wp-content/uploads/2022/09/folder-structure-scaffolding-nestjs-app.png)

Next, we can navigate into the folder by running the following command.

```bash
cd nest_vite_esbuild_demo
```

Then, go ahead and start the project:

```bash
npm run start
```

The output of running that command is shown below.

```bash
npm run start                  

> nest_vite_esbuild_demo@0.0.1 start
> nest start

[Nest] 33031  - 08/08/2022, 3:22:16 AM     LOG [NestFactory] Starting Nest application...
[Nest] 33031  - 08/08/2022, 3:22:16 AM     LOG [InstanceLoader] AppModule dependencies initialized +48ms
[Nest] 33031  - 08/08/2022, 3:22:16 AM     LOG [RoutesResolver] AppController {/}: +8ms
[Nest] 33031  - 08/08/2022, 3:22:16 AM     LOG [RouterExplorer] Mapped {/, GET} route +3ms
[Nest] 33031  - 08/08/2022, 3:22:16 AM     LOG [NestApplication] Nest application successfully started +8ms
```

As an alternative to the above, we can also start our application in development mode to watch for file changes, recompile the build, and reload the dev server by running the command below:

```bash
npm run start:dev
```

Then, navigate to [`http://localhost:3000/`](http://localhost:3000/) in the browser. Further, we can also go ahead and perform a manual installation of NestJS’s core dependencies. In this setup, we can set up our project structure as we wish, just by running the command below.

```bash
npm i --save @nestjs/core @nestjs/common reflect-metadata
```

## Exploring the NestJS boilerplate <a name="exploring-nestjs-boilerplate">

When we navigate to the `src` directory inside our project folder, we can see the default files created for us. We have:

1.  The `app.controller.ts` file, which represents our handler with just one route
2.  The `app.service.ts` file, which handles anything related to method or utility functions, so as to keep the controller slim
3.  The `app.module` file, which handles the base module for our application (a way of structuring our application components)
4.  The `app.controller.spec.ts` file, which handles testing our controller logic
5.  The `main.ts` file, which is entry point of our application and creates a Nest application instance using the core `NestFactory` function

![The default files in our src directory](https://blog.logrocket.com/wp-content/uploads/2022/09/src-directory-default-files.png) 

NestJS encourages developers to keep their application architecture as modular as possible, with each directory inside the source directory representing a single module. Each Nest application must have at least one module, a root module, which is the starting point for building the application graph. 

For example, we can run the following command to create a new module:

```bash
nest g module product_demo
```

![Our new product demo module in the src directory](https://blog.logrocket.com/wp-content/uploads/2022/09/new-product-demo-module.png) 

As you can see from the above, we have created a `product_demo` module. We can then go ahead to create the other needed files — `controller` and `services` — and also import the `product_demo` module into the app base module. 

For more information regarding NestJS fundamentals and features, we can make reference to the documentation, including [testing](https://docs.nestjs.com/fundamentals/testing), [providers](https://docs.nestjs.com/providers), [lifecycle events](https://docs.nestjs.com/fundamentals/lifecycle-events), [decorators](https://docs.nestjs.com/custom-decorators), [middleware](https://docs.nestjs.com/middleware), [modules](https://docs.nestjs.com/modules) etc., to gain mastery of the framework. Next, let us go ahead and set up Vite and esbuild on our NestJS application.

## Installing Vite and esbuild with NestJS <a name="installing-vite-esbuild-nestjs">

Vite is plugin-based and also comes with a well-optimized and fast build process, which can greatly improve your overall developer productivity and experience. It also supports TypeScript out of the box. 

Now, let’s integrate Vite into our NestJS backend app. We are going to install Vite via the plugin, which runs a Node dev server with hot module replacement. 

Run the command below as a development dependency.

```bash
npm install vite vite-plugin-node -D
```

Next, in the root of our project directory, we can create the `vite.config.ts` file, which configures our project to make use of the plugin. Let’s see the contents of that file below.

```typescript
import { defineConfig } from 'vite';
import { VitePluginNode } from 'vite-plugin-node';
export default defineConfig({
  // ...vite configures
  server: {
    // vite server configs, for details see \[vite doc\](https://vitejs.dev/config/#server-host)
    port: 3000
  },
  plugins: [
    ...VitePluginNode({
      // Nodejs native Request adapter
      // currently this plugin support 'express', 'nest', 'koa' and 'fastify' out of box,
      // you can also pass a function if you are using other frameworks, see Custom Adapter section
      adapter: 'nest',
      // tell the plugin where is your project entry
      appPath: './src/main.ts',
      // Optional, default: 'viteNodeApp'
      // the name of named export of you app from the appPath file
      exportName: 'viteNodeApp',
      // Optional, default: 'esbuild'
      // The TypeScript compiler you want to use
      // by default this plugin is using vite default ts compiler which is esbuild
      // 'swc' compiler is supported to use as well for frameworks
      // like Nestjs (esbuild dont support 'emitDecoratorMetadata' yet)
      // you need to INSTALL `@swc/core` as dev dependency if you want to use swc
      tsCompiler: 'esbuild',
    })
  ],
  optimizeDeps: {
    // Vite does not work well with optionnal dependencies,
    // mark them as ignored for now
    exclude: [
        '@nestjs/microservices',
        '@nestjs/websockets',
        'cache-manager',
        'class-transformer',
        'class-validator',
        'fastify-swagger',
      ],
  },
});
```

Next, we need to update the entry point of our app server file (`main.ts`) to export the app named `viteNodeApp` (in the Vite config `exportName` field above) or any other name we have configured in the Vite config file above. See below.

```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
if (import.meta.env.PROD) {
  async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    await app.listen(3000);
  }
  bootstrap();
}

export const viteNodeApp = NestFactory.create(AppModule);
```

Next, in our `package.json` file, we can go ahead and add an npm script to run the dev server with the regular `npm run dev` command:

```json
"scripts": {
  "dev": "vite"
}
```

As we have earlier mentioned, Vite comes with a dev server that serves our source files over native ESM. When we run our app with the Vite dev server using the `npm run dev` command after the entire setup, we’ll see the output below. ![The output after running the npm run dev command](https://blog.logrocket.com/wp-content/uploads/2022/09/output-after-running-npm-run-dev.png)  

To be sure everything is still working as expected, run the test suite with the `npm run test` command and we can see the output below. ![The output after running the npm run test command](https://blog.logrocket.com/wp-content/uploads/2022/09/output-after-running-npm-run-test.png)

The plugin also uses Vite’s server-side rendering mode to build our app. To make use of this feature, we can go ahead and add a build script to our `package.json` file (using Vite to build our app instead of Nest):

```json
"scripts": {
  "build": "vite build"
},
```

The `vite build` command bundles our code with [Rollup](https://rollupjs.org/) and spits out highly optimized assets for our production environment. When we build our app with Vite by running the `npm run build` command after the entire setup, we can see the output below. ![The output after running the npm run build command](https://blog.logrocket.com/wp-content/uploads/2022/09/output-after-running-npm-run-build.png) 

As mentioned before, Vite makes use of esbuild under the hood to transpile TypeScript to JavaScript. It is a very fast transpilation process — it can even be up to 20 times faster than regular TypeScript compilers, and HMR updates can reflect in the browser in under 50ms. 

One of the advantages of using the Vite plugin ([vite-plugin-node](https://github.com/axe-me/vite-plugin-node)) is that we can choose to use either esbuild or swc to compile our TypeScript files, though we used only esbuild in this post.

## Conclusion

In this post, we have learned how to get going with NestJS, Vite, and esbuild. As we have seen, NestJS has an interesting and rather new approach to building Node.js applications with a philosophy around OOP, FP, and FRP. These improvements greatly improve developer time and productivity in the long run, as we don’t have to bother about how to design our modules and components. NestJS solves that for us and proposes a one-module-per-folder pattern. We can also use the power of TypeScript to write our backend code. 

Vite, on the other hand, is on a whole new level in the world of build tools. It is coming at a time where popular JS-based bundlers and build tooling in the NodeJS ecosystem needed a boost in terms of performance. Vite compiles our code to native code using a completely different approach from webpack and Parcel. As we have learned, it uses the browser and native ESM for bundling. 

In all, we have combined these awesome technologies to build a simple boilerplate backend that can be a starting point for your next NestJS project.