nest: Nx & nestjs@6.0.0 errors using "ng build --prod"
I’m submitting a…
[x] Bug report
Current behavior
Nx project with a bare-bones nestjs@6.0.0 app does not compile when using the --prod flag.
Does not compile
ng build --prod
Compiles
ng serveng buildwithout the--prodflag- nestjs@5.7.4 works with the
--prodflag
Expected behavior
Should compile
Minimal reproduction of the problem with instructions
Nx & nestjs@6.0.0 bug reproduction
Environment
- Nest: 6.0.0
- Node: 10.15.3
- Nx: 7.7.1
- Platform: Linux
Build log
$ ng build --prod
Starting type checking service...
Using 6 workers with 2048MB memory limit
Hash: de380795417288d36cc2
Version: webpack 4.29.0
Time: 13666ms
Built at: 03/17/2019 12:50:11 PM
Asset Size Chunks Chunk Names
main.js 1.14 MiB 0 main
main.js.map 1.65 MiB 0 main
Entrypoint main = main.js main.js.map
[0] ./node_modules/tslib/tslib.es6.js 10.1 KiB {0} [built]
[16] ./node_modules/@nestjs/common/index.js 695 bytes {0} [built]
[81] ./node_modules/@nestjs/core/constants.js 486 bytes {0} [built]
[88] ./apps/api/src/app/app.service.ts 395 bytes {0} [built]
[145] ./node_modules/@nestjs/core/helpers/index.js 236 bytes {0} [built]
[149] ./node_modules/@nestjs/core/nest-application-context.js 10.9 KiB {0} [built]
[151] ./node_modules/reflect-metadata/Reflect.js 50 KiB {0} [built]
[302] ./node_modules/@nestjs/core/services/index.js 236 bytes {0} [built]
[307] ./node_modules/@nestjs/core/nest-application.js 14.5 KiB {0} [built]
[313] ./node_modules/@nestjs/core/index.js 972 bytes {0} [built]
[329] ./apps/api/src/app/app.module.ts 485 bytes {0} [built]
[330] ./apps/api/src/app/app.controller.ts 913 bytes {0} [built]
[331] multi ./apps/api/src/main.ts 28 bytes {0} [built]
[332] ./apps/api/src/main.ts 992 bytes {0} [built]
[333] ./node_modules/@nestjs/core/adapters/index.js 231 bytes {0} [built]
+ 555 hidden modules
WARNING in ./node_modules/@nestjs/common/utils/load-package.util.js 8:39-59
Critical dependency: the request of a dependency is an expression
@ ./node_modules/@nestjs/core/nest-application.js
@ ./node_modules/@nestjs/core/index.js
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
WARNING in ./node_modules/@nestjs/core/helpers/load-adapter.js 8:15-39
Critical dependency: the request of a dependency is an expression
@ ./node_modules/@nestjs/core/nest-factory.js
@ ./node_modules/@nestjs/core/index.js
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
WARNING in ./node_modules/optional/optional.js 6:15-30
Critical dependency: the request of a dependency is an expression
@ ./node_modules/@nestjs/core/nest-application.js
@ ./node_modules/@nestjs/core/index.js
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
ERROR in ./node_modules/@nestjs/core/nest-application.js
Module not found: Error: Can't resolve '@nestjs/microservices' in '/home/z/Work/nx-nest/node_modules/@nestjs/core'
@ ./node_modules/@nestjs/core/nest-application.js 148:124-156
@ ./node_modules/@nestjs/core/index.js
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
ERROR in ./node_modules/@nestjs/core/nest-factory.js
Module not found: Error: Can't resolve '@nestjs/microservices' in '/home/z/Work/nx-nest/node_modules/@nestjs/core'
@ ./node_modules/@nestjs/core/nest-factory.js 56:136-168
@ ./node_modules/@nestjs/core/index.js
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
ERROR in ./node_modules/@nestjs/common/cache/cache.providers.js
Module not found: Error: Can't resolve 'cache-manager' in '/home/z/Work/nx-nest/node_modules/@nestjs/common/cache'
@ ./node_modules/@nestjs/common/cache/cache.providers.js 10:116-140
@ ./node_modules/@nestjs/common/cache/cache.module.js
@ ./node_modules/@nestjs/common/cache/index.js
@ ./node_modules/@nestjs/common/index.js
@ ./apps/api/src/app/app.module.ts
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
ERROR in ./node_modules/@nestjs/common/pipes/validation.pipe.js
Module not found: Error: Can't resolve 'class-transformer' in '/home/z/Work/nx-nest/node_modules/@nestjs/common/pipes'
@ ./node_modules/@nestjs/common/pipes/validation.pipe.js 52:119-147
@ ./node_modules/@nestjs/common/pipes/index.js
@ ./node_modules/@nestjs/common/index.js
@ ./apps/api/src/app/app.module.ts
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
ERROR in ./node_modules/@nestjs/common/serializer/class-serializer.interceptor.js
Module not found: Error: Can't resolve 'class-transformer' in '/home/z/Work/nx-nest/node_modules/@nestjs/common/serializer'
@ ./node_modules/@nestjs/common/serializer/class-serializer.interceptor.js 33:131-159 34:8-36
@ ./node_modules/@nestjs/common/serializer/index.js
@ ./node_modules/@nestjs/common/index.js
@ ./apps/api/src/app/app.module.ts
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
ERROR in ./node_modules/@nestjs/common/pipes/validation.pipe.js
Module not found: Error: Can't resolve 'class-validator' in '/home/z/Work/nx-nest/node_modules/@nestjs/common/pipes'
@ ./node_modules/@nestjs/common/pipes/validation.pipe.js 51:115-141
@ ./node_modules/@nestjs/common/pipes/index.js
@ ./node_modules/@nestjs/common/index.js
@ ./apps/api/src/app/app.module.ts
@ ./apps/api/src/main.ts
@ multi ./apps/api/src/main.ts
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 14
- Comments: 35 (5 by maintainers)
What if I want to build a dockerfile for the Backend? I don’t want all installs of my package.json in the docker image, so I think bundling the nest.js’ dependencies should be possible.
Starting the resulting container will result in this output:
“externalDependencies”: “none” seems like the option I need, but if fails the build. Anybody got an idea how to handle this?
So basically I have dig into this issue a little bit and I have some takeaways to share. Firstly, this issue is not caused by 6.0.0 release - it wasn’t working properly in 5.x either. However, in 5.x you were able to compile your
prodapp unless you usedValidationPipeorCacheModule- then, it apparently stopped to work. This has changed though, because we are no longer using expressions (variables) insiderequire()function, but we’re rather passing a loader function that has dependency defined statically.Hence, this for instance:
leads to compilation errors, because webpack traverse modules graph and tries to resolve
cache-managerdependency even though(!)CacheModulemight not be used (tree-shaking is being performed later on, once bundle is created). Consequently, it breaks Nest idea of lazyrequire()calls, because webpack tries to load them all during the bundling process.How to fix this? The easiest solution would be to use
webpack-node-externalspackage to avoid bundlingnode_modules(bundle & tree-shake only user code). Usage is pretty simple:And it should be fine in 99% cases. However, sometimes you may prefer to bundle entire application (one file, smaller size, somewhat lower memory consumption, slightly faster bootstrap time [serverless]) - in this case, you could use
webpack.IgnorePluginplugin.This workaround would ignore whitelisted packages IF they aren’t present (
require.resolve()throws an error). Otherwise, it would bundle them as well. This example would work, but the problem here is that you basically have to hardcode these whitelisted packages in the actual builder (Nx node builder) in this case. Perhaps, there is a way to just conditionally provide additional plugin to determine webpack behavior determine on the framework which is being used. CC @FrozenPandazI’m just a humble member of the Nest community. Though, I do think we need to sympathize with the complexity of integrating many 3rd party systems together (such as Nest does), and how there can be problems that may not have eloquent solutions. Bundling and tree shaking code has been something the industry has been struggling with since the inception of modern Javascript (ES6+). Webpack and Rollup seem to be the current front running technologies of the industry. Historically, there was no exiting Javascript framework that managed to solve the bundling/tree shaking problem, due to the fact there were various competing Javascript module systems (Commonjs vs AMD vs ES6). Furthermore, there are framework specific module systems, such as Google’s Angular module system, which is what Nest’s own module system is inspired after. The Angular team took on the challenge to design a module system that would allow for the construction of a deterministic abstract syntax tree (AST). It contains the information needed to appropriately tree shake out unused code and determine what should actually be bundled. The industry has come a long way in a short amount of time, but there are still long standing problems to be resolved.
This of course leads us to the issue of this thread. The problem lies deeper than just at the framework level (Nest), or at the bundling level (Webpack). Therefore, we should be sympathetic to the fact that we may need some explicit configuration for the time being. The industry as a whole needs more time to mature. Until then, all of us require some proficiency with configuring bundling systems like Webpack.
got the same issue… and working with Nx workspace to manage multiples nestjs application… Any way to bundle all deps in dist folder of each nestjs application? Or a way to build correct package.json files with only required deps of each nestjs application??
@FrozenPandaz
See my response here, especially this part:
Basically, Nest in some cases is using
require()calls lazily. For instance, if you don’t use eitherRedisClientorRedisServer, therequire('redis')expression won’t be evaluated = the package won’t have to be installed. This allows us to avoid creating 10 packages for every existing transport strategy just to put 2 classes in there. Also, if someone doesn’t use redis strategy, he won’t be forced to installredis.Another, more important example is
ValidationPipewhich dynamically loads bothclass-validatorandclass-transformer. Validation is considered as a crucial feature and is being using among lots of applications. However, we cannot put these 2 libraries into internaldependenciesbecause they also expose decorators to developers that have to be used from outside Nest internal scope. Hence, we have to keep them as peer dependencies. In this case, we would have to again extractValidationPipe(1 class) to a separate package.The solution that I have included in my post (with
webpack.IgnorePlugin()) generally allow you to still bundle + perform tree-shaking for everything (including lazyrequire()calls). It would obviously consume error messages about missing Nest-lazy-loaded packages (if they ARE actually missing), but it shouldn’t be a big deal since this build is being used inprodmode only(correct?). Also, during the tree-shaking step, webpack would get rid of this code that is not being used anyway so it wouldn’t affect the final bundle either.So reassuming, if we still want to have tree-shaking + bundling, the only thing is to put this
webpack.IgnorePlugin()solution (described here) as a custom webpack configuration (available in Nx 7.7, correct?) only for Nest apps.I would like to deploy a standalone bundle without any node_modules.
If I understand correctly, the intended way of doing so would be to add
"externalDependencies": "none". But it leads me to the same errors that ZenSoftware described. (I am using nest v6.2.4 in a Nx project).Can someone confirm my following understanding of the work around suggested above:
Did I miss something or is there any plan to correct the
"externalDependencies": "none"error?I created a PR to revert the change for now. I still suggest people look into bundling in their dependencies but I guess it’s hard to provide something that works for NestJS out of the box.
@xmlking Yes, that is correct! I recommend the following setting instead:
@kamilmysliwiec Maybe the
webpackteam can help suggest a better way to handle such module references.I tried with externalDependencies but I’ve got this error:
i’m trying to bundle my apps with webpack to reduce package size as i’m using aws lambda functions and i don’t manage to make it work using the suggested solution …
i’m adding the @nest/graphql module to the app and there are quite lot warning and errors when building the app :
this is my webpack config :
im just using the graphql example from nestJS and is worth mentioning that without adding ‘.mjs’ to the extensions list webpack will also complain: https://github.com/graphql/graphql-js/issues/1272
thanks !
testing with
nxwebpackConfigoption, https://github.com/xmlking/ngx-starter-kit/blob/develop/angular.json#L255@FrozenPandaz is this correct way to customize webpack ?
Edit: The following is a messy solution. Simply setting
"externalDependencies": "all"in theangular.jsonfile does the same thing. Nice find @xmlking! ^_^Thanks @kamilmysliwiec for all the hard work. The community loves you for it ^_^
My build process is a bit more convoluted than I was hoping for, but I ended up using @kamilmysliwiec recommendation to use webpack-node-externals.
npm i -D @angular-builders/custom-webpacknpm i -D webpack-node-externalswebpack.partial.jsat the root of your project with the following:angular.jsonfile. (Note that this is presuming your Nest app in Nx is named “api”)ng run api:custom --configuration=productionto build the Nest app without node_modulesI have just published a repo which demonstrates how one can bundle Nest and containerize it for Docker. It attempts to address the issues that most people are having here. You can find it here, cheers!
💥 Nest 🔰 Webpack 🔰 Docker 💥
looks like nx already support excluding some or all node modules from bundling
externalDependencies: 'all' | 'none' | string[];herefor my case
"externalDependencies": "all"worked.@FrozenPandaz can I somehow help with this issue? It seems that Nx builder is trying to bundle all dependencies, even lazy loaded ones. For instance, this
require(cache.providers.tsfile incommon):shouldn’t be bundled if
CacheModuleis not being used.