Skip to content

NestJs HMR not working with "type": "module" #14331

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
hnviradiya opened this issue Dec 15, 2024 · 5 comments
Open
1 task done

NestJs HMR not working with "type": "module" #14331

hnviradiya opened this issue Dec 15, 2024 · 5 comments
Labels
needs triage This issue has not been looked into

Comments

@hnviradiya
Copy link

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

Refer this #14312 as this is duplicate of that and action suggested on that has already been taken but it didn't help.

I have a issue with HMR when I use "type": "module" in package.json. Below is the full description.

I followed NestJs HMR using webpack using following url.

https://docs.nestjs.com/recipes/hot-reload

It works fine when we use "type": "commonjs" in package.json.

Unfortunately I have monorepo with client app that uses "type": "module"

When I run nest build --webpack --webpackPath webpack-hmr.config.js --watch

I get below error.

 Error  require() of ES Module my-project\webpack-hmr.config.js from \node_modules\@nestjs\cli\actions\build.action.js not supported.
webpack-hmr.config.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which declares all .js files in that package scope as ES modules.
Instead either rename webpack-hmr.config.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change "type": "module" to "type": "commonjs" in package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).

That is because I used require and module.exports with "type": "module"

const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');

module.exports = function (options, webpack) {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      new webpack.WatchIgnorePlugin({
        paths: [/\.js$/, /\.d\.ts$/],
      }),
      new RunScriptWebpackPlugin({ name: options.output.filename, autoRestart: false }),
    ],
  };
};

So I converted them to import and export default as below

import nodeExternals from 'webpack-node-externals';
import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin';

export default (options, webpack) => {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      new webpack.WatchIgnorePlugin({
        paths: [/\.js$/, /\.d\.ts$/],
      }),
      new RunScriptWebpackPlugin({ name: options.output.filename, autoRestart: false }),
    ],
  };
};

Now I get following and for that part I am not sure how to solve it as I don't seem to find way to work with module type with webpack nest cli.

 Error  require() of ES Module webpack-hmr.config.js from \node_modules\@nestjs\cli\actions\build.action.js not supported.
Instead change the require of webpack-hmr.config.js in \node_modules\@nestjs\cli\actions\build.action.js to a dynamic import() which is available in all CommonJS modules.

Have posted same on stackoverflow and also asked chatgpt if there is way to work with this but couldn't find any.
https://stackoverflow.com/questions/79269058/nestjs-hmr-not-working-with-type-module

Tried Discord too. But question simlpy got skipped. Probably there is no answer available to this yet and needs support from NestJs team itself.
https://discord.com/channels/520622812742811698/1316338004725596161

Describe the solution you'd like

Webpack HMR should work with "type": "module" in package.json

Teachability, documentation, adoption, migration strategy

user should be able to use es module based webpack config.

import nodeExternals from 'webpack-node-externals';
import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin';

export default (options, webpack) => {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      new webpack.WatchIgnorePlugin({
        paths: [/\.js$/, /\.d\.ts$/],
      }),
      new RunScriptWebpackPlugin({ name: options.output.filename, autoRestart: false }),
    ],
  };
};

What is the motivation / use case for changing the behavior?

HMR is quite important to be productive as it saves lots of time. Currently big server side code takes lots of time to reload entire node server.

@hnviradiya hnviradiya added needs triage This issue has not been looked into type: enhancement 🐺 labels Dec 15, 2024
@jadejr
Copy link

jadejr commented Jan 14, 2025

It sounds like you didn't read the other suggestion about renaming the file to cjs? Did you? Did it not work?

@hnviradiya
Copy link
Author

hnviradiya commented Jan 24, 2025

@jadejr I got below error converting to cjs

file:///C:/Projects/GitLab/my-project/dist/main.js:334
module.exports = require("@elastic/elasticsearch");
^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and 'C:\Projects\GitLab\my-project\package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at Object.<anonymous> (file:///C:/Projects/GitLab/my-project/dist/main.js:334:1)
    at __webpack_require__ (file:///C:/Projects/GitLab/my-project/dist/main.js:425:33)
    at fn (file:///C:/Projects/GitLab/my-project/dist/main.js:566:21)
    at Module.<anonymous> (file:///C:/Projects/GitLab/my-project/dist/main.js:192:80)
    at __webpack_require__ (file:///C:/Projects/GitLab/my-project/dist/main.js:425:33)
    at file:///C:/Projects/GitLab/my-project/dist/main.js:1380:37
    at file:///C:/Projects/GitLab/my-project/dist/main.js:1382:12
    at ModuleJob.run (node:internal/modules/esm/module_job:271:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:547:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:116:5)

Node.js v22.12.0

Below is my import in ts file.

import { Client } from '@elastic/elasticsearch';

@Kjaer
Copy link

Kjaer commented Mar 21, 2025

Does webpack even allow ESM bundling by default? I think your webpack configuration also need to use esbuild loader, then you can use type: module in your package.json.

https://github.com/privatenumber/esbuild-loader

(Sorry for shallow answer here, I just want to point out missing things I see in a glance. I assume your webpack config is a Typescript file, no?)

@jadejr
Copy link

jadejr commented Apr 24, 2025

@Kjaer swc seems recommended around here since it can handle typescript decorator metadata while esbuild won't. There's already an option to use the swc loader with the current webpack setup, although I've never used it.

@themuku
Copy link

themuku commented Apr 24, 2025

Problem
HMR doesn't work when using "type": "module" in package.json because the NestJS CLI attempts to require() the webpack-hmr.config.js file. When "type": "module" is present, .js files are treated as ES Modules, and using require() to load them causes an error.

Error Message

Error  require() of ES Module webpack-hmr.config.js from \node_modules\@nestjs\cli\actions\build.action.js not supported.

Current Workaround

  1. Rename webpack-hmr.config.js to webpack-hmr.config.cjs
  2. Change CLI call to:
    nest build --webpack --webpackPath webpack-hmr.config.cjs --watch
    
  3. Use CommonJS syntax (require, module.exports) inside the .cjs file

Alternatively, you can move the config file to a subdirectory with its own package.json containing "type": "commonjs", which also works.

Suggested Solution
Allow NestJS CLI to load webpack configs using dynamic import() when the config is an ES Module. This would support modern project setups where "type": "module" is required (for example, in monorepos with frontend tooling that uses ESM).

Motivation
Hot Module Replacement is an important productivity feature. Without support for ESM in Webpack configs, developers are forced to downgrade their project setup or disable HMR, which negatively impacts developer experience in modern JavaScript projects.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs triage This issue has not been looked into
Projects
None yet
Development

No branches or pull requests

5 participants