nrwl / nx

Smart Monorepos · Fast CI
https://nx.dev
MIT License
23.39k stars 2.33k forks source link

[feature] nest hot reload #1992

Open yassernasc opened 4 years ago

yassernasc commented 4 years ago

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.

flogh commented 4 years ago

This feature would be incredible

FrozenPandaz commented 4 years ago

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.

Nightbr commented 4 years ago

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

webberwang commented 3 years ago

any updates on this?

rubennaatje commented 3 years ago

@yassernascimento Any way you could show how you did it manually?

github-actions[bot] commented 3 years ago

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! 🙏

yassernasc commented 3 years ago

@rubennaatje didn't try yet, sorry

pacexy commented 3 years ago

any news?

github-actions[bot] commented 2 years ago

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! 🙏

jensbodal commented 2 years ago

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?

mehrad-rafigh commented 2 years ago

Unstale please

MinJungHyun commented 1 year ago

please.. help

DeepaPrasanna commented 1 year ago

Are there any updates regarding this? I am facing this same issue.

antischematic commented 1 year ago

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

dan-cooke commented 7 months ago

@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

paullryan commented 6 months ago

@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();
svetlyr commented 5 months ago

@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?

itspers commented 5 months ago

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.

fourgates commented 4 months ago

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!

ardabeyazoglu commented 4 months ago

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.

paullryan commented 4 months ago

@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.

dima11221122 commented 4 months ago

I think it's related https://github.com/nrwl/nx/issues/20963

LazeKer commented 1 month ago

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