Webpack打包NestJS单文件后运行报错:找不到@nestjs/core模块
NestJS Webpack打包单文件运行时提示模块找不到
尝试使用Webpack将NestJS应用打包为可直接交付的单文件,构建成功生成main.js,但在本机非项目目录或其他机器运行该文件时,出现如下错误:
node main.js node:internal/modules/cjs/loader:936 throw err; ^ Error: Cannot find module '@nestjs/core' Require stack: - C:\Users\xxx\Desktop\Temp\main.js [90m at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)[39m [90m at Function.Module._load (node:internal/modules/cjs/loader:778:27)[39m [90m at Module.require (node:internal/modules/cjs/loader:1005:19)[39m [90m at require (node:internal/modules/cjs/helpers:102:18)[39m at Object.__decorate (C:\Users\xxx\Desktop\Temp\main.js:8:18) at __webpack_require__ (C:\Users\xxx\Desktop\Temp\main.js:3635:42) at C:\Users\xxx\Desktop\Temp\main.js:3648:16 at C:\Users\xxx\Desktop\Temp\main.js:3656:3 at Object.<anonymous> (C:\Users\xxx\Desktop\Temp\main.js:3658:12) [90m at Module._compile (node:internal/modules/cjs/loader:1105:14)[39m { code: [32m'MODULE_NOT_FOUND'[39m, requireStack: [ [32m'C:\\Users\\xxx\\Desktop\\Temp\\main.js'[39m ] ------- \Desktop\Temp\main.js:3658:12) [90m at Module._compile (node:internal/modules/cjs/loader:1105:14)[39m { code: [32m'MODULE_NOT_FOUND'[39m, requireStack: [ [32m'C:\\Users\\xxx\\Desktop\\Temp\\main.js'[39m ]
当前配置
webpack.config.js
const path = require('path'); const webpack = require('webpack'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const WebPackIgnorePlugin = { checkResource: function (resource) { const lazyImports = [ '@nestjs/microservices', '@nestjs/microservices/microservices-module', 'cache-manager', 'class-transformer', 'class-validator', 'fastify-static', ]; if (!lazyImports.includes(resource)) return false; try { require.resolve(resource); } catch (err) { return true; } return false; }, }; module.exports = { mode: 'production', target: 'node', entry: { server: './src/main.ts', }, devtool: 'source-map', module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, resolve: { extensions: ['.tsx', '.ts', '.js'], }, node: { __dirname: false, }, plugins: [ new CleanWebpackPlugin(), new webpack.IgnorePlugin(WebPackIgnorePlugin), ], optimization: { minimize: false, }, performance: { maxEntrypointSize: 1000000000, maxAssetSize: 1000000000, }, output: { filename: '[name].js', path: path.resolve(__dirname, 'prod'), }, };
package.json
"scripts": { "prebuild": "rimraf dist", "build": "nest build --webpack", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start --entryFile ./my-app/src/main.js", "start:dev": "nest start --entryFile ./my-app/src/main.js --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest", "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { "@nestjs/common": "^8.0.0", "@nestjs/core": "^8.0.0", "@nestjs/platform-express": "^8.0.0", "@stablelib/aes-kw": "^1.0.1", "bcryptjs": "^2.4.3", "core-js": "^3.18.1", "csv-parser": "^3.0.0", "ec-key": "^0.0.4", "express": "^4.17.3", "fast-xml-parser": "^3.20.3", "futoin-hkdf": "^1.4.2", "net-snmp": "^3.5.5", "object.pick": "^1.3.0", "path": "^0.12.7", "pkcs11js": "^1.3.0", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", "serialport": "^10.4.0", "sqlite3": "^5.0.2", "ssh2": "^1.11.0", "sshpk": "^1.17.0", "strftime": "^0.10.1", "tftp": "^0.1.2", "tsconfig-paths-webpack-plugin": "^4.0.0", "webpack-cli": "^4.10.0", "winston": "^3.3.3", "winston-transport": "^4.4.0" }, "devDependencies": { "@nestjs/cli": "^8.0.0", "@nestjs/schematics": "^8.0.0", "@nestjs/testing": "^8.0.0", "@types/express": "^4.17.13", "@types/jest": "27.5.0", "@types/node": "^16.0.0", "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", "jest": "28.0.3", "prettier": "^2.3.2", "source-map-support": "^0.5.20", "supertest": "^6.1.3", "ts-jest": "28.0.1", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", "tsconfig-paths": "4.0.0", "typescript": "^4.3.5", "webpack": "^5.74.0", "webpack-merge": "^5.8.0" }, "jest": { "moduleFileExtensions": [ "js", "json", "ts" ], "rootDir": "src", "testRegex": ".*\\.spec\\.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" }, "collectCoverageFrom": [ "**/*.(t|j)s" ], "coverageDirectory": "../coverage", "testEnvironment": "node" }
构建输出
> npm run build > my-app@0.0.1 prebuild > rimraf dist > my-app@0.0.1 build > nest build --webpack webpack 5.73.0 compiled successfully in 10253 ms
解决方案
问题根源在于Webpack默认对Node.js环境的模块标记为external,即不打包进最终文件,运行时依赖本地node_modules加载。要生成可独立运行的单文件,需修改配置将普通依赖全部打包,同时处理原生模块的特殊情况:
修改webpack.config.js,配置externals排除原生模块
对于包含原生代码的模块(如sqlite3、serialport等),无法直接打包进单文件,需保留为external;其余依赖全部打包:module.exports = { // ... 现有配置 externals: [ function ({ request }, callback) { // 列出需要保留为external的原生模块 const nativeModules = ['sqlite3', 'serialport', 'pkcs11js', 'ssh2', 'net-snmp']; if (nativeModules.includes(request)) { return callback(null, `commonjs ${request}`); } callback(); } ], // ... 现有配置 };调整ts-loader规则,处理依赖中的TS文件
部分依赖为TS编写,默认配置排除了node_modules,需调整规则确保这些文件被编译:const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); module.exports = { // ... 现有配置 resolve: { extensions: ['.tsx', '.ts', '.js'], plugins: [new TsconfigPathsPlugin()] }, module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', // 仅排除不需要编译的第三方模块 exclude: /node_modules\/(?!(@nestjs|rxjs)\/)/, }, ], }, // ... 现有配置 };指定webpack配置文件执行构建
修改package.json的build脚本,确保Nest CLI使用自定义配置:"build": "nest build --webpack --webpackPath webpack.config.js"原生模块的交付处理
标记为external的原生模块,需将对应的node_modules目录下的模块文件夹随打包文件一起交付,或在目标机器上通过npm install --production安装这些依赖。
验证
重新执行npm run build,将生成的prod/server.js(可修改output.filename为main.js)复制到目标目录,同时复制原生模块的文件夹,运行node server.js即可正常启动应用。
内容的提问来源于stack exchange,提问作者ATT
相关产品推荐
相关产品推荐

