DEV Community

kenji ding
kenji ding

Posted on

Deploying a full web service on EC2 using Docker (1) Lightweight Deployment of Nest.js

Note: This is an article series on deploying web projects on AWS, including:

  1. Lightweight construction of backend Nest.js through Docker deployment of the entire web application service (1).
  2. Lightweight construction of frontend Next.js through Docker deployment of the entire web application service (2).
  3. Setting up an AWS EC2 server through Docker deployment of the entire web application service (3).
  4. Deploying frontend and backend services through Docker-compose in Docker deployment of the entire web application service (4).
  5. Distributing API routes and hosting Next.js static resources through Nginx in Docker deployment of the entire web application service (5).
  6. Automating CI/CD deployment through Git Action in Docker deployment of the entire web application service (6).

1、Introduce

As we all know, Nest.js by default only compiles TypeScript files instead of bundling all resources into bundles and chunks like in frontend projects. For example, to run the build command in the terminal: “npm run build”.

Comparing the compiled dist directory with the source code, we can see that Nest.js simply converts TypeScript files to JavaScript.

Image description

The compiled JavaScript source code only contains your business logic. If you upload them to a server and try to run them, you will encounter errors because the JS business code does not include the @nestjs/xxx related code.

Image description

This means that on the server, you still need to install the dependencies and devDependencies specified in your package.json using pnpm i or npm i. However, installing dependencies with npm i can be very disk-intensive. If your server has limited memory, you may encounter disk space issues during dependency installation. This is because the node_modules folder contains a lot of unused code without tree-shaking from bundling tools like webpack, turbopack, or rollup, leading to disk space waste.

The best practice for lightweight deployment is to use webpack in your CI/CD pipeline to bundle your code and then deploy only the bundle to the server.

2、How to implement this:

2.1、You can enable webpack bundling by modifying nest-cli.json.

{
  "compilerOptions": {
    "deleteOutDir": true,
    "webpack": true //enable webpack
  }
}
Enter fullscreen mode Exit fullscreen mode

After modifying nest-cli.json and bundling again, although it has been bundled into a single bundle (as shown in the screenshot below), the source code of @nestjs/core and other dependencies is still not included in the bundle. Instead, they are transformed into the commonjs format used by Node.js. The bundling process only applies to your project’s business logic. In other words, this code still cannot be directly run on the server. You still need to run pnpm i to install dependencies before you can run it.

Image description

2.2. Customize webpack.config.js to implement packaging

1、In order to address the issue mentioned above, which is the failure to include dependencies like @nestjs/core in the bundle, we need to create a webpack.config.js file in the root directory and utilize webpack.IgnorePlugin to achieve this.

const path = require('path');
const webpack = require('webpack');
// Improving TypeScript build performance
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
// Note: These libraries do not need to be bundled into the bundle. 
// Exclude them using `webpack.IgnorePlugin` as shown below.
const lazyImports = [
  '@nestjs/microservices',
  '@nestjs/microservices/microservices-module',
  '@nestjs/websockets/socket-module',
  'cache-manager',
  'class-validator',
  'class-transformer'
];

module.exports = {
  entry: './src/main',
  output: {
    // output name
    path: path.resolve(__dirname, 'nest-blog'),
    // output filename
    filename: 'main.js'
  },
  target: 'node',
  // Setting it to empty will ignore the `webpack-node-externals` plugin.
  externals: {},
  // Handling TypeScript files
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: {
          loader: 'ts-loader',
          options: { transpileOnly: true }
        },
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.ts', '.json']
  },
  plugins: [
    new webpack.IgnorePlugin({
      checkResource(resource) {
        if (!lazyImports.includes(resource)) {
          return false;
        }
        try {
          require.resolve(resource, {
            paths: [process.cwd()]
          });
        } catch (err) {
          return true;
        }
        return false;
      }
    }),
    new ForkTsCheckerWebpackPlugin()
  ]
};
Enter fullscreen mode Exit fullscreen mode

2、Then add a new script in package.json to make Nest use the above webpack.config.js configuration when building.

"scripts": {
    "build:bundle": "NODE_ENV=production && nest build --webpack --  webpackPath=./webpack.config.js",
    .....
},
Enter fullscreen mode Exit fullscreen mode

3、Run pnpm build:bundle again.

Finally, a bundle file nest-blog/main.js will be generated. This main.js no longer has dependencies like @nestjs/core; all related dependencies are bundled into this main.js. The remaining dependencies are Node.js native modules, so it can be directly run in a Node.js environment. Now you can simply upload this bundle to the server and run it without installing any dependencies.

Image description

4. Deployment

After uploading /nest-blog/main.js` to the server, you only need to run the following command in the terminal to start the Nest.js service.

shell
node ./nest-blog/main.js

Image description

5、Finally

Comparing with traditional deployment, Nest.js lightweight deployment only requires deploying a single bundle file. You don’t need to install a large number of dependencies using pnpm i on the server. This approach saves disk space and is much more convenient.

Next Article: Lightweight construction of frontend Next.js through Docker deployment of the entire web application service (2).

Top comments (0)