Open yassernasc opened 4 years ago
This feature would be incredible
Hi, sorry about this.
This was mislabeled as stale. We are testing ways to mark not reproducible issues as stale so that we can focus on actionable items but our initial experiment was too broad and unintentionally labeled this issue as stale.
Hey, would love to see a solution for this. BTW I found this on Stackoverflow -> https://stackoverflow.com/questions/60476245/how-to-setup-webpacks-hmr-in-nestjs-project-in-nx-monorepo
any updates on this?
@yassernascimento Any way you could show how you did it manually?
This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! 🙏
@rubennaatje didn't try yet, sorry
any news?
This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! 🙏
I’ve tried a few times to get this working and it’s just no go. I’m not even sure how well the feature works outside of the nest cli, does anyone have any experience?
Unstale please
please.. help
Are there any updates regarding this? I am facing this same issue.
Until this is added here's how to get HMR working with Nx 16.1.4 and NestJS 10.
Create a webpack.hmr.config.js
file like this:
const { composePlugins, withNx } = require('@nx/webpack');
const nodeExternals = require('webpack-node-externals');
const webpack = require('webpack')
// Set true if you don't want type checking
const skipTypeChecking = false
// Nx plugins for webpack.
module.exports = composePlugins(withNx({ skipTypeChecking }), (config) => {
// Update the webpack config as needed here.
// e.g. `config.plugins.push(new MyPlugin())`
return {
...config,
entry: ['webpack/hot/poll?100', ...config.entry.main],
externals: [
nodeExternals({
allowlist: ['webpack/hot/poll?100'],
}),
],
plugins: [
...config.plugins,
new webpack.HotModuleReplacementPlugin(),
new webpack.WatchIgnorePlugin({
paths: [/\.js$/, /\.d\.ts$/],
}),
],
};
});
Set your project.json
like this
{
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"target": "node",
"compiler": "tsc",
"outputPath": "dist/apps/your-nest-app",
"main": "apps/your-nest-app/src/main.ts",
"tsConfig": "apps/your-nest-app/tsconfig.app.json",
"assets": [
"apps/your-nest-app/src/assets"
],
"isolatedConfig": true
},
"configurations": {
"development": {
"webpackConfig": "apps/your-nest-app/webpack.hmr.config.js"
},
"production": {
"webpackConfig": "apps/your-nest-app/webpack.config.js",
"generatePackageJson": true
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"watch": false,
"options": {
"buildTarget": "your-nest-app:build"
},
"configurations": {
"development": {
"buildTarget": "your-nest-app:build:development"
},
"production": {
"buildTarget": "your-nest-app:build:production"
}
}
}
}
}
Make sure watch
is set to false
. Then set up your main.ts
like this
declare const module: any;
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}
}
bootstrap();
Now you can run nx serve your-nest-app
and it will reload with HMR.
Don't upgrade past nx 16.1.4 until these issues are fixed: https://github.com/nrwl/nx/issues/17070 https://github.com/nrwl/nx/issues/17868
@antischematic unfortunately this no longer works
nest: 10.3.2
nx: 18.0.6
And it appears those linked issues are fixed
I am currently getting this error
TypeError [ERR_INVALID_ARG_TYPE]: The "paths[1]" argument must be of type string. Received undefined
at validateString (node:internal/validators:162:11)
at resolve (node:path:1101:7)
at /home/dan/dev/templi/templi/node_modules/@nx/webpack/src/plugins/nx-webpack-plugin/lib/normalize-options.js:79:59
at Array.map (<anonymous>)
at normalizeAssets (/home/dan/dev/templi/templi/node_modules/@nx/webpack/src/plugins/nx-webpack-plugin/lib/normalize-options.js:75:19)
at normalizeOptions (/home/dan/dev/templi/templi/node_modules/@nx/webpack/src/executors/webpack/lib/normalize-options.js:24:76)
at webpackExecutor (/home/dan/dev/templi/templi/node_modules/@nx/webpack/src/executors/webpack/webpack.impl.js:58:62)
at webpackExecutor.next (<anonymous>)
at /home/dan/dev/templi/templi/node_modules/@nx/js/src/executors/node/node.impl.js:191:44
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'ERR_INVALID_ARG_TYPE'
}
Not sure if this belongs in a separate issue - i'm not 100% sure whats going on there
@dan-cooke I got it to work with nest 10.3.7 and nx 18.2.1 with the following
webpack.hmr.config.js
const { composePlugins, withNx } = require('@nx/webpack');
const nodeExternals = require('webpack-node-externals');
const webpack = require('webpack')
// Set true if you don't want type checking
const skipTypeChecking = false
// Nx plugins for webpack.
module.exports = composePlugins(withNx({ skipTypeChecking }), (config) => {
// Update the webpack config as needed here.
// e.g. `config.plugins.push(new MyPlugin())`
return {
...config,
entry: ['webpack/hot/poll?100', ...config.entry.main],
externals: [
nodeExternals({
main: './src/main.ts',
tsConfig: './tsconfig.app.json',
assets: ['./src/assets'],
optimization: false,
outputHashing: 'none',
allowlist: ['webpack/hot/poll?100'],
}),
],
plugins: [
...config.plugins,
new webpack.HotModuleReplacementPlugin(),
new webpack.WatchIgnorePlugin({
paths: [/\.js$/, /\.d\.ts$/],
}),
],
};
});
project.json
{
"name": "your-nest-app",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "your-nest-app/src",
"projectType": "application",
"tags": [],
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": [
"{options.outputPath}"
],
"defaultConfiguration": "production",
"options": {
"target": "node",
"compiler": "tsc",
"outputPath": "dist/your-nest-app",
"main": "your-nest-app/src/main.ts",
"tsConfig": "your-nest-app/tsconfig.app.json",
"assets": [
"your-nest-app/src/assets"
],
"isolatedConfig": true
},
"configurations": {
"development": {
"webpackConfig": "your-nest-app/webpack.hmr.config.js"
},
"production": {
"webpackConfig": "your-nest-app/webpack.config.js",
"generatePackageJson": true
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"options": {
"buildTarget": "your-nest-app:build"
},
"configurations": {
"development": {
"watch": true,
"buildTarget": "your-nest-app:build:development"
},
"production": {
"buildTarget": "your-nest-app:build:production"
}
}
}
}
}
main.ts
/**
* This is not a production server yet!
* This is only a minimal backend to get started.
*/
declare const module: any;
import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app/app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
const port = process.env.PORT || 3000;
await app.listen(port);
Logger.log(
`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`
);
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}
}
bootstrap();
@paullryan your setup works, but the app seems to be restarting twice: Once after the HMR updated the module, and a second time after it. Same config as yours. Do you have any suggestions?
For me API is not available in browser till this second reload happens (Maybe due to fact that im using proxy in angular app..). And this 2 reloads take more time than one without HMR - so disabled it at all.
It is quite obvious than whole this NX moved away from Angular to some 'cloud-things' and adding executors for Rust and they have no intention to support useful things like Nestjs. There will be no SWC and no HMR.
I'm on nx 19 and nestjs 10. I am also seeing the double refresh. The first refresh is super fast though! Would be great if there were a fix for HMR!
I can confirm the trick from @paullryan works on latest nx 19 and nestjs, with double refresh problem. I tried playing with webpack config a bit with no luck. Debounce did not help either.
EDIT: I noticed that module.hot.dispose()
is called only once on file change, however the app restarts a second time.
@svetlyr sorry I'm not using this that heavily at the moment so am unsure about getting the double restart to stop, I did notice that as well. I'm guessing it needs to be addressed deeper in the hot implementation for this module as it's probably doing a small (manifest) change that is causing the second restart. @ndcunningham that's where I'd start in fixing that portion of the hot reload.
I think it's related https://github.com/nrwl/nx/issues/20963
I managed to make it work by combining this issue's feedback and NestJS documentation: https://docs.nestjs.com/recipes/hot-reload
The trick for HMR is to not "serve" it directly but build it in watch mode (the double refresh probably come from the serve).
webpack.hmr.config.js
const { composePlugins, withNx } = require('@nx/webpack')
const { WebpackPnpExternals } = require('webpack-pnp-externals')
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin')
const webpack = require('webpack')
// Set true if you don't want type checking
const skipTypeChecking = false
// Nx plugins for webpack.
module.exports = composePlugins(withNx({ skipTypeChecking }), (config, { options, context }) => {
config.entry = ['../../node_modules/webpack/hot/poll?100', ...config.entry.main]
config.externals = [
...config.externals,
WebpackPnpExternals({
exclude: ['../../node_modules/webpack/hot/poll?100'],
}),
]
config.plugins = [
...config.plugins,
new webpack.HotModuleReplacementPlugin(),
new webpack.WatchIgnorePlugin({
paths: [/\.js$/, /\.d\.ts$/],
}),
new RunScriptWebpackPlugin({ name: options.outputFileName, autoRestart: false }),
]
return config
})
I use yarn berry, so webpack-pnp-externals
instead of webpack-node-externals
, see NestJs documentation
project.json
{
"name": "api",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/api/src",
"projectType": "application",
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
...
},
"configurations": {
"hmr": {
"watch": true,
"sourceMap": true,
"webpackConfig": "apps/api/webpack.hmr.config.js"
},
"development": {
"sourceMap": true,
"webpackConfig": "apps/api/webpack.config.js"
},
"production": {
"generatePackageJson": true,
"optimization": true,
"webpackConfig": "apps/api/webpack.config.js"
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"options": {
"buildTarget": "api:build"
},
"configurations": {
"development": {
"buildTarget": "api:build:development"
},
"production": {
"buildTarget": "api:build:production"
}
}
},
},
}
Notice that I created a separate build config with the watch
option
To start it:
nx build api --configuration=hmr
Expected Behavior
Out-of-box webpack hot reload on created nest apps.
Current Behavior
Needed to add webpack manually following the tutorial: https://docs.nestjs.com/techniques/hot-reload.