Nest项目部署的优秀方式

前一阵子搞了个nest项目,当我开发完一个功能,打算部署到服务器进行测试时,发现它跑不起来,报了一大堆错缺少了很多依赖包。
首页 新闻资讯 行业资讯 Nest项目部署的优秀方式

前言

前一阵子搞了个nest项目,当我开发完一个功能,打算部署到服务器进行测试时,发现它跑不起来,报了一大堆错缺少了很多依赖包。

我几乎找遍了全网的解决方案,他们的答案齐刷刷只有一个:nest在打包时,不会将依赖打包进去,需要在服务器上clone项目,安装依赖。

这个答案不是我想要的,在服务器上安装node_modules纯属胡闹。幸运的是,经过一番研究后,我终于解决了这个问题,本文就跟大家分享下我的实现思路与方案,欢迎各位感兴趣的开发者阅读本文。

场景概述

我们继续用文章“使用NestJS搭建服务端应用[1]”所创建的项目,以此为基础来描述这个问题,我们打开package.json文件,执行里面的build命令。

复制

{"scripts": {  "build": "nest build",}}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

一眨眼的功夫,它就打包好了,在你的项目根目录下会多出一个dist文件夹,如下如所示,这就是它所打包出来的文件。

d97d30f14a369139a219872f71be8453f33441.webp

紧接着,我们把dist目录上传到服务器,用node来执行其目录下的main.js文件,上传文件至服务器后,我发现整个文件夹竟然只有18KB,我当时惊呆了,心想js这么牛的吗!开发出来的服务端应用包体积居然这么小,同样的功能使用Java实现,打包出来的jar包都50MB起步了!

c1d8e77484c9aa7f418009ee5e6766ca6eee6e.webp

当我在服务器上运行时,我傻眼了,程序报错跑不起来🌚,这玩意儿不经夸啊。

882b52202d060974f511898dfe424f1be1ad2f.webp

定位问题

我怀着忐忑的心情打开dist的目录下的文件后,发现它只是简单的把ts编译成了js,并没有打包任何依赖包进去,他所有的依赖包都是从node_modules中引的。我们的服务器上是没有这些依赖包的,所以他就报错了。

17f005677a8f4fa6084507938a9645c1b5db98.webp

在搜索引擎上找了下解决方案,千篇一律的要在服务器上clone项目,然后在服务器上安装庞大的node_modules,简直是无稽之谈。

跟几个人交流后,他们说node项目本来就是这样啊,都是在服务器上安装依赖包的,这让我想起了好多年前看到的一个图,用在此处极为合适。

f4fc04611aa765919123157e61b5928e7f122b.webp


解决方案

我是一个追求完美的人,这么庞大的一个开源库,设计者一定不会这么傻吧,这种低级问题应该早就考虑到了才对,既然网上找不到方案,那我就读一下它的源码吧。

皇天不负有心人,当我在查阅nest-cli源码的打包模块时,在@nestjs/cli/actions/build.action.js文件中发现了它有个配置变量webpack。

2517487481879e03fba51898c3c4a29e753433.webp

随后,我在nest的官方文档中,在nest-build[2]章节找到了这个配置项的相关内容,发现他可以在打包命令后面添加--webpack参数来生成单文件main.js。

d78721d676c455e58e63389aae9ae780045a25.webp

于是,我添加了这个参数,运行打包命令后,单文件是生成了,但是依赖文件依然没打包进去。出现这种情况那就只有一种可能了:nest-cli在打包时排除屏蔽了依赖包。

顺藤摸瓜,我在@nestjs/cli/lib/compiler/defaults/webpack-defaults.js发现了猫腻,如下图所示:

它使用webpack-node-externals插件屏蔽了依赖的打包。

59eafda61ac4e98844b21259434f2cf6b9f711.webp

实现代码经过上面的分析,我们定位到了问题所在,既然它默认屏蔽了依赖的打包,那我们就自己创建一个webpack.config.js文件,忽略掉externals以及一些nest提供的插件,这个问题就完美解决了,实现代码如下所示:

  • 将externals属性置为空,就忽略掉了默认的webpack-node-externals插件

  • 使用IgnorePlugin忽略掉了nest中的一些无用依赖包

复制

/* eslint-disable @typescript-eslint/no-var-requires */const path = require("path");const webpack = require("webpack");// fork-ts-checker-webpack-plugin需要单独安装
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");module.exports = {
  entry: "./src/main",
  target: "node",
  // 置为空即可忽略webpack-node-externals插件
  externals: {},
  // ts文件的处理
  module: {rules: [  {test: /\.ts?$/,use: {  loader: "ts-loader",  options: { transpileOnly: true }},exclude: /node_modules/  }]
  },
  // 打包后的文件名称以及位置
  output: {filename: "main.js",path: path.resolve(__dirname, "dist")
  },
  resolve: {extensions: [".js", ".ts", ".json"]
  },
  plugins: [// 需要进行忽略的插件
    new webpack.IgnorePlugin({  checkResource(resource) {const lazyImports = [  "@nestjs/microservices",  "@nestjs/microservices/microservices-module",  "@nestjs/websockets/socket-module",  "cache-manager",  "class-validator",  "class-transformer"];if (!lazyImports.includes(resource)) {  return false;}try {  require.resolve(resource, {paths: [process.cwd()]  });} catch (err) {  return true;}return false;  }}),new ForkTsCheckerWebpackPlugin()
  ]};
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

⚠️注意:上述webpack配置文件要求package.json中webpack的版本号为^5.11.0",还需要安装fork-ts-checker-webpack-plugin依赖包到devDependencies中。

最后,我们修改打包命令为:

复制

{"scripts": {   "build": "nest build --webpack --webpackPath=./webpack.config.js",}}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

执行上述命令后,我们发现依赖包已经打入main.js了,文件体积也上升到了3.6mb。

682150c122b20abe2db652e4a0d41c5fa48a9c.webp

最后,我们用node来运行这个js文件,也没有了报错,顺利的跑起来了。

e81751c629e80ac09e0973a6746c8ee3e5d6e5.webp

我们再拿postman来测试下接口能否正常访问,如下所示,也都可以正常访问。

282413e382017cae808723d0b2e30f3e47459f.webp

小tips:在服务器上运行node项目时,通常会使用pm2来执行。对此感兴趣的开发者,请自行了解。

示例代码

本文中所列举的完整代码请移步:

  • webpack.config.js[3]

  • package.json[4]

参考资料

[1]使用NestJS搭建服务端应用: https://juejin.cn/post/7053840108331466783

[2]nest-build: https://docs.nestjs.com/cli/usages#nest-build

[3]webpack.config.js: https://github.com/likaia/nest-project/blob/436b8ebdfe1c9b5f69a27e2dfdbc001ba6d78753/webpack.config.js

[4]package.json: https://github.com/likaia/nest-project/blob/436b8ebdfe1c9b5f69a27e2dfdbc001ba6d78753/package.json#L9

[5]个人网站: https://www.kaisir.cn/


15    2022-02-18 07:27:01    Nest 项目