NestJS 项目打包的实现步骤
作者:养老不躺平
最近在用nest做一些工具,开发阶段挺好用,等到打包时遇到了各种各样的问题,在这里简单总结下。
一、nest build
如果使用nest build进行打包,你将会得到一份和原目录相同的目录结构输出。
为什么?
因为NestJS CLI仅做如下处理:
- 读取配置文件:读取nest-cli.json等配置文件,确定构建选项和输出目录。
- TypeScript编译
- 部分文件处理:复制静态资源,处理路径映射
- 优化操作:代码压缩 以及生成source map
可以看到,NestJS CLI 并没有像webpack一样,将不同文件打包成一个,而是保留了原有目录结构。
二、关于.map文件
上面我们提到,会生成.map文件。有些同学可能会有疑问,.map 不是在浏览器中使用的么?服务端项目为什么还需要.map文件?这就要讲到.map文件的使用场景:
错误调试与堆栈跟踪
当服务端运行时出现错误,Node.js会生成错误堆栈信息。如果没有Source map,错误信息会指向编译后的JavaScript代码的行号,而不是原始的TypeScript代码。这使得定位和修复问题变得非常困难。
性能分析
在进行性能分析时,source map可以帮助开发者识别哪些原始TypeScript代码段在运行时消耗了最多资源。这对于优化关键路径和提高应用性能至关重要。
- 开发体验优化
在开发环境中,使用source map可以获得更好的开发体验。例如,当使用Node.js的调试器或日志记录时,可以直接看到和引用原始的TypeScript代码,而不是编译后的JavaScript代码。
- 日志记录增强
在日志系统中,可以通过source map将日志中记录的代码位置转换回原始TypeScript文件位置,使日志信息更有意义和可操作。
三、为什么不将依赖包打包进最终结果中?
nest项目打包,建议采用分离依赖的方式,即打包后单独安装依赖。
优势:
- 镜像体积更小(如果采用docker方式的话):只包含编译后的代码
- 缓存友好:Docker构建时可以分层缓存
- 部署灵活:可以在目标环境安装特定版本的依赖
- 标准实践:符合Node.js生态的常见做法
- 体积臃肿:node_modules会非常大
- 路径问题:可能出现模块解析错误
- 平台兼容性:native依赖可能不兼容目标平台
webpack打包示例:
const path = require('path'); const nodeExternals = require('webpack-node-externals'); const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { entry: './src/main.ts',// 入口问啊进 target: 'node', mode: process.env.NODE_ENV || 'production', output: { path: path.resolve(__dirname, 'dist'), //输出目录 filename: 'bundle.js',// 输出结果 }, resolve: { extensions: ['.ts', '.js'],// 支持的文件扩展名 plugins: [ new TsconfigPathsPlugin({// 支持tsconfig路径映射 configFile: './tsconfig.json', }), ], }, module: { rules: [ { test: /\.ts$/, // 处理TypeScript文件 use: { loader: 'ts-loader', options: { transpileOnly: true, // 只编译,不做类型检查 }, }, exclude: /node_modules/, //排除 node_modules }, ], }, externals: [nodeExternals()], // 排除所有 node_modules 依赖;不打包 [node_modules](),运行时从外部加载,这就是为什么你需要在部署环境安装依赖的原因 plugins: [ new CleanWebpackPlugin(), // 清理dist目录 new ForkTsCheckerWebpackPlugin(),// 在单独进程中进行类型检查 new CopyPlugin({ //将静态文件复制到dist目录 patterns: [ { from: path.resolve(__dirname, 'public'), to: path.resolve(__dirname, 'dist/public'), }, { from: path.resolve(__dirname, 'package.json'), to: path.resolve(__dirname, 'dist/package.json'), }, { from: path.resolve(__dirname, '.env'), to: path.resolve(__dirname, 'dist'), }, ], }), ], optimization: { minimize: process.env.NODE_ENV === 'production', minimizer: [ new TerserPlugin({ terserOptions: { compress: { drop_console: process.env.NODE_ENV === 'production',// 生产环境移除 console }, }, }), ], }, devtool: process.env.NODE_ENV === 'production' ? 'source-map' : 'eval-cheap-module-source-map', };
四、为什么静态文件没有打包到最终的boundle.js中
- 在Node.js应用中,静态文件和配置文件通常保持独立,便于在运行时直接读取或修改,而不是打包进最终结果中
- webpack默认只会打包通过import或require引入的JavaScript/TypeScript模块。
- .env问啊进包含环境变量,通常需要在运行时读取,保持其独立文件形式更灵活;public目录下的文件通常是静态资源,需要通过路径访问。
- 如果需要使用,可以在webpack打包时,将.env文件等复制到dist目录下。
五、fetch api
如果你在代码中使用了fetch api,开发环境没有问题,但是打包后将报错fetch is not defined。因为Node18以下版本中,默认不包含浏览器的原生fetch API,如需使用,需要引入node-fetch。18以上就可以正常使用了。
到此这篇关于NestJS 项目打包的实现步骤的文章就介绍到这了,更多相关NestJS 项目打包内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!