likes
comments
collection
share

飞速启动nest服务,我是这样做的

作者站长头像
站长
· 阅读数 13

前言

最近在做electron的桌面端项目,由于产品功能支持断网的时候也能正常使用,因此启动electron会在本地使用nest创建一个http服务,在框架上采用了nest,打开electron应用加载首页列表接口需要等到nest启动成功,这个过程居然要5-6秒,甚至在windows上要30秒,这里可以类比做前端的首屏加载等待耗时,如此大的延时,显然是无法接受的。

飞速启动nest服务,我是这样做的

服务端的启动耗时问题

项目总计接口不超过30个,在我接触的node项目中算是比较少的了,代码量也不算多,我也是第一次关注这个问题,我猜测可能不是业务代码的问题,毕竟也没有什么特别耗时的操作,究竟是什么如此耗时呢?

于是乎我开始探究对比其他服务端的启动时间

我:A你那边的java单体项目启动时间如何呢?

A:稍等我试试,我这个项目要40秒

我:B你那边的多个服务的项目启动时间如何呢?

B:稍等我试试,我这个项目超过1分钟了

我:C你那边的koa的项目启动时间如何呢? C: 稍等我试试,10秒

一个一个都说试试,似乎很少人会关注这个问题,也确实如此,我的应用场景比较特殊。 那么有没有一种可能,我是说可能,可能一秒内就启动一个具有一定业务体量的的项目呢?

飞速启动nest服务,我是这样做的

从一nest空项目说起

首先来探究一下nest启动为什么慢? 在一番排查有发现大部分的耗时都消耗在import文件上。既然接口不多都这么慢,那么空项目又该如何呢?

先创建一个空项目

npm i -g @nestjs/cli
nest new nest-test

添加上typeorm和数据库配置(数据库这里就不贴代码了)

在main.js加上打印日志

const startTime = new Date().getTime();
import { NestFactory } from '@nestjs/core';
console.info(`NestFactory ${new Date().getTime() - startTime}`);
import { AppModule } from './app.module';
console.info(`AppModule耗时:${new Date().getTime() - startTime}`);

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  console.info(`执行至 create 耗时 ${new Date().getTime() - startTime}`);
  await app.listen(3000);
  console.info(`执行至 listen 耗时 ${new Date().getTime() - startTime}`);
}
bootstrap();

然后打包启动项目

npm run start:prod 

在mac上查看效果

飞速启动nest服务,我是这样做的

在windows上查看效果

飞速启动nest服务,我是这样做的

操作系统启动耗时
mac2.99秒
windows29.2秒

用nest就连空项目启动都这么慢,那么从业务代码入手优化空间就很有限了,如果换成其他框架呢?可是后端同学已经采用了nest开发完成了,没有这么多时间重构了,那我前端等待服务端耗时这么久,我又该如何应对?

在经过了搜索nest相关 issue无果后,是甩锅给后端?还是默默摆烂等待被喷?

飞速启动nest服务,我是这样做的

不行,我要抗争,命运不能扼住我的喉咙!

既然是import耗时太久,那么有没有可能打包成一个单文件,就不需要这么多读取文件的耗时了,灵光乍现,这等小问题岂能难倒天选之人。

飞速启动nest服务,我是这样做的

将nest打包后的文件打包成单文件

首先来看nest打包后的文件

飞速启动nest服务,我是这样做的

可以看见dist目录下包含了多个文件

拿入口文件main.js观察:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@nestjs/core");
const app_module_1 = require("./app.module");
async function bootstrap() {
    const app = await core_1.NestFactory.create(app_module_1.AppModule);
    await app.listen(3000);
}
bootstrap();

可以看到 main.js 有require("@nestjs/core"), 而 @nestjs/core 依然是要去加载node_modules中的文件,nestjs/core内部又引用了很多文件,同理还有typeorm也是,这些体量很重的框架都有大量的文件引用,那么如果能将文件都打包到一个js中,减少系统去检索和读取这些文件,似乎真的是可以提高启动速度的。

我似乎找到了方法

我要扼住命运的咽喉,它将无法使我完全屈服

尝试将node打包成单文件,有以下的方法:

  1. 使用webpack(node打包有很多的坑,webpack玩转的比较好的才建议直接使用webpack)
  2. ncc(ncc本质上也是使用webpack,不过做好了很多细节封装)

ncc

ncc(Node Compiler Collection)是一个用于将Node.js模块打包成单个文件的工具。它可以将Node.js模块及其依赖项捆绑为一个自包含的、可以直接执行的JavaScript文件。通过使用ncc,您可以轻松地将复杂的Node.js项目转换为单个文件,从而方便部署和分发。

安装

npm i -g @vercel/ncc

打包单文件

ncc build <入口文件>

尝试使用ncc效果

cd dist // 直接到nest build目录中
ncc build main.js
cd dist // 这是ncc重新打包后的目录
node ./index.js

执行ncc build后会指定的目录下生成一个新的dist目录,包含了一个index.js是build的main中所有的代码(这里我简单的 nest的dist目录直接打包了,使用的时候可以在其他目录)

飞速启动nest服务,我是这样做的 可以看打包后的新文件只有一个index.js

在mac上查看效果

飞速启动nest服务,我是这样做的

在windows上查看效果

飞速启动nest服务,我是这样做的

操作系统优化前启动耗时优化后启动耗时
mac2.99秒0.38秒
window29.2秒0.47秒

哦吼,流畅启动了,mac上快了8倍,windows快了62倍(windows应该是因为测试机不是固态硬盘所以慢了很多,因而有如此大的进步),不愧是我,有似乎已经进入了半步白银境界了!

实际项目中优化打包过程中,还需要处理不少打包细节,nest也有一些懒加载的方法,还有进一步的优化空间,业务代码还需要具体问题具体分析。 在我接触的electron项目中,由于引用一些复杂的模块,就需要额外处理,最终代码都打包到了单文件中,客户端体积还减少了20M,可谓是一举两得。

路漫漫其修远兮吾将上下而求索

如今nest启动已经踏入了秒内之境,我也还在探索能否更快的将其启动。

最后

nest打包成单文件速度确实有了质的飞跃,不过我不推荐使用nest作为桌面端项目中的本地服务框架,毕竟这个框架太重了,推荐还是使用koa或者不采用http的方式,考虑到当前项目改成其他形式的工作量比较大,并且未来还有web端也要http接口,最后还是打成单个文件处理,启动效果还是得到了产品同学的认可,如果你也在使用nest开发,不妨尝试用ncc来优化启动试试。

转载自:https://juejin.cn/post/7250080519069040701
评论
请登录