nrwl / nx

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

HMR for @nrwl/react #1881

Closed marazz1 closed 3 years ago

marazz1 commented 5 years ago

How to enable HMR for @nrwl/react. Is it possible to achieve it without custom webpack.config.json? (Like in Angular)

There should be something in docs for HMR.

In workspace.json "hmr": true

"serve": {
          "builder": "@nrwl/web:dev-server",
          "options": {
            "hmr": true,
            "buildTarget": "testapp:build"
          },
          "configurations": {
            "production": {
              "buildTarget": "testapp:build:production"
            }
          }

Expected Behavior

module.hot should not be undefined

Current Behavior

HMR doesn´t work.

Context

    "@nrwl/cypress": "8.5.1",
    "@nrwl/eslint-plugin-nx": "8.5.1",
    "@nrwl/jest": "8.5.1",
    "@nrwl/react": "8.5.1",
    "@nrwl/web": "8.5.1",
    "@nrwl/workspace": "8.5.1",
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.

BigAB commented 4 years ago

So, as...

We have decided to wait until there is a webpack solution for React Fast Refresh solution for Webpack and we'll implement HMR for our React projects with that when it arrives

Hotell commented 4 years ago

Makes sense! Thx

cafesanu commented 4 years ago

Hi @BigAB! Seems like webpack is now supported 😄 . Here is a copy-paste of the current state in https://github.com/gaearon/react-hot-loader

Thanks!

R4VANG3R commented 4 years ago

Create react app 4.0 now also released with Fast Refresh using this plugin: https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/1

pitops commented 4 years ago

any update on this?

cafesanu commented 3 years ago

@BigAB Wondering if there is any news here? This would be a great improvement for the nrwl react community 🙂

Thanks!

nemonemi commented 3 years ago

Just a reminder, would be nice to have an answer here to know of the progress.

capJavert commented 3 years ago

@nemanjamilosavljevic-newtron actually we managed to integrate https://github.com/pmmmwh/react-refresh-webpack-plugin into our nx setup (we have few react based application). It is working great so far.

We followed https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/examples/webpack-dev-server example. Only thing that was needed is to upgrade webpack to at least 4.43.0 (this is slightly higher that current nx version). But again no issues in the last month of usage.

So maybe there is no need to wait for this feature to land into NX, you can jump in right now.

nemonemi commented 3 years ago

@capJavert Thanks for responding so quickly :)

I'm new to NX so I hope you could help me with the following: Where can I find documentation on updating and configuring webpack (just update the nx cli?). https://nx.dev/react/guides/cli returns 404

capJavert commented 3 years ago

Just adjust webpack dependency version in you package.json or add it through yarn add webpack@4.43.0

nemonemi commented 3 years ago

Thank you @capJavert However, it would be nice to have this integrated.

rexebin commented 3 years ago

I have had a go to get HMR, but no luck. Stil compiles, but WDS only, no HMR. webpack.config.js is as below. I also added "react-refresh/babel" to .babelrc plugins list. No affect what so ever. I am lucky it still compiles, no idea of how babel/webpack works together.


const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = (config, context) => {
  return {
    ...config,
    mode: isDevelopment ? 'development' : 'production',
    module: {
      ...config.module,
      rules: [
        ...config.module.rules,
        // ... other rules
        {
          test: /\.([jt])sx?$/,
          exclude: /node_modules/,
          use: [
            {
              loader:
                '@nrwl/web/src/utils/web-babel-loader',
              options: {
                rootMode: 'upward',
                cwd: 'apps/myapp/src',
                isModern: true,
                envName: undefined,
                babelrc: true,
                cacheDirectory: true,
                cacheCompression: false,
                plugins: [
                  // ... other plugins
                  isDevelopment && require.resolve('react-refresh/babel'),
                ].filter(Boolean),
              },
            },
          ],
        },
      ],
    },
    plugins: [
      ...config.plugins,
      isDevelopment && new webpack.HotModuleReplacementPlugin(),
      isDevelopment && new ReactRefreshWebpackPlugin(),
    ].filter(Boolean),
  };
};
capJavert commented 3 years ago

@rexebin you are probably missing devServer.hot property for weback. Something like this will do:

// ...

webpackConfig.devServer = {
    ...webpackConfig.devServer,
    hot: true
}

// ...

More here: https://webpack.js.org/guides/hot-module-replacement/#enabling-hmr

SDemonUA commented 3 years ago

I got messages like: [HMR] App is up to date., but no actual rerender. Making me mad...

SDemonUA commented 3 years ago

I got messages like: [HMR] App is up to date., but no actual rerender. Making me mad...

Problem hides in React version - React Fast Refresh works only with 16.9+

nemonemi commented 3 years ago

@SDemonUA React Fast Refresh is not yet ready for official use. I have it in another project on version 17.0.1 and it works when other pages were changed, but not when the index.ts gets changed. Even then, I have to jump-start the tracking by refreshing the page and, then it works. In the case of micro frontends, there's this issue https://github.com/facebook/create-react-app/issues/10385

In case you want to have HMR, then you can easily disable the fast refresh to have it working. https://github.com/facebook/create-react-app/issues/10539

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

dcastil commented 3 years ago

Not stale, I'm waiting for this! 😄

rexebin commented 3 years ago

I tried react-react-app with fast refresh and found myself constantly refreshing manually and eventually turn off fast refresh all together.

It works ok most cases but requires manual refreshing in some cases. The thing is, this small chance of non-op is making me doubtful all the time. I do not want to waste time trying to figure out why something is not working as intended, then find out a manual refresh is all I needed. Some may not have this problem.

Now I am back to NX with all the goodies Nx has to offer, feeling at home, not missing HMR, not a tiny bit.

jugglingcats commented 3 years ago

@rexebin I agree that the nagging doubt about whether refresh has happened is a pain with fast refresh. I'm using Snowpack and it works really well most of the time. There is an issue that changing a file with a React context provider often makes the context null for child components and the page then fails with an error, but I can live with that. For me the huge advantage is being able to work on something like a modal without having it disappear all the time due to a full page reload

rexebin commented 3 years ago

@jugglingcats working on a modal is really a good use case for fast refresh.

I can tell when or if the fast refresh happens from the network tab.

Maybe it is just me tiered of manual refresh just in case. No doubt Fast refresh is a good to have feature!

rexebin commented 3 years ago

@jugglingcats are you using Snowpack with NX?

jugglingcats commented 3 years ago

@rexebin yes and no. I have an nx monorepo that has shared libs and an aws lambda project, and in it there is a webapp that I run with snowpack by carefully crafting the snowpack config... NX doesn't really know anything about it

rexebin commented 3 years ago

@jugglingcats searching about snowpack and nx, found your nx-snowpack repo. From one of the post from @vsavkin, it was hinted adding Snowpack to nx project is trivial.. interesting but at the same time feel uncertain.

jugglingcats commented 3 years ago

@rexebin we are getting a bit off topic from the original post perhaps, but I am interested in the difference (if any) between Snowpack refresh (using native modules/ESM) and NX (webpack) fast refresh.

I am using snowpack dev for everyday development and webpack optimize/bundle (driven by snowpack) for production build, and it works well for me. I haven't taken the time to compare with CRA or NX with fast refresh enabled as it's not easy to switch my large-ish project between the two.

nemonemi commented 3 years ago

As mentioned by @jugglingcats, I think this thread has gotten slightly off-topic as well. @vsavkin, @FrozenPandaz It has been 2 years since this issue was first opened. It would be nice to see some progress here. Could anyone from the maintainers please make an actionable item out of this?

dustinlacewell commented 3 years ago

Can anyone provide a minimal webpack override to enable fast refresh that works?

capJavert commented 3 years ago

Firstly you need to have minimal version of webpack@4.43.0.

Minimal config would be (pretty much following install instructions at @pmmmwh/react-refresh-webpack-plugin:

const getWebpackConfig = require('@nrwl/react/plugins/webpack')
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

function getCustomWebpackConfig(webpackConfig) {
    const config = getWebpackConfig(webpackConfig)
    const isProduction = webpackConfig.mode === 'production'

    if (!isProduction) {
        webpackConfig.devServer = {
            ...webpackConfig.devServer,
            hot: true
        }

        config.plugins.push(new ReactRefreshPlugin())
    }

    return config
}

module.exports = getCustomWebpackConfig

Also you need to add react-refresh/babel plugin for production in your .babelrc.js or similar, example:

const commonPlugins = [/* your plugins here if you have any */]

module.exports = {
    presets: ['@nrwl/react/babel'],
    env: {
        development: {
            plugins: [...commonPlugins, 'react-refresh/babel']
        },
        production: {
            plugins: [...commonPlugins]
        }
    }
}
nemonemi commented 3 years ago

Thanks for the code example, @capJavert! However, for me the HMR works only for "upper" components, but not for the deeply nested components. On those, the full page reload is happening.

@vsavkin, @FrozenPandaz could you please address this request by at least providing proper documentation on how to handle this use case?

xiongemi commented 3 years ago

@nemonemi i tried with the custom webpack on a simple app: https://github.com/xiongemi/nx-react-counter-custom-webpack and it seems to work fine for me for nested components. when I update a nested component, it does not trigger page reload. In the console, it says HMR is updating the components.

[HMR] Checking for updates on the server...
log.js:24 [HMR] Updated modules:
log.js:24 [HMR]  - ../../../libs/ui/src/lib/counter/counter.tsx
log.js:24 [HMR] App is up to date.

This is what my custom webpack looks like: https://github.com/xiongemi/nx-react-counter-custom-webpack/pull/1/files

Maybe disable the liveReload in your webpack file?

webpackConfig.devServer = {
      ...webpackConfig.devServer,
      liveReload: false,
      hot: true,
    };
nemonemi commented 3 years ago

Actually, I found what the problem was, and it was having multiple named exports in a component, which is a known behavior limit of the HMR library.

rexebin commented 3 years ago

I can confirm following the configuration showing at https://github.com/xiongemi/nx-react-counter-custom-webpack, I am able to get the HMR working in my Nx React Typescript project.

Nice console logs clearly showing the update progress like below:

[WDS] App updated. Recompiling... reloadApp.js:19 [WDS] App hot update... log.js:24 [HMR] Checking for updates on the server... log.js:24 [HMR] Updated modules: log.js:24 [HMR] - ../../../libs/[path of changed file here] log.js:24 [HMR] App is up to date.

I need to install three packages to get it working:


"webpack": "^4.46.0"(webpack 5 doesn't work),
"react-refresh": "^0.10.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3"
rexebin commented 3 years ago

Actually, I found what the problem was, and it was having multiple named exports in a component, which is a known behavior limit of the HMR library.

Good to know, worth it to keep one export per file.

nemonemi commented 3 years ago

Also, I found that no additional configuration of the .babelrc files is necessary. This is my application's .babelrc file:

{
  "presets": ["@nrwl/react/babel"],
  "plugins": [
    [
      "styled-components",
      {
        "pure": true,
        "ssr": true
      }
    ]
  ]
}

@vsavkin Please add this as a default for React projects! It is hard to imagine anyone who doesn't want to have this improvement to the developer experience.

rexebin commented 3 years ago

After two weeks of using the shining new HMR above, I am back to report that I am very happy with the solution. Most important of all is that nx tells me when exactly the app is hot loaded and up to date, making it better than react-react-app, which is silence on hot reload in the console(last time I tried, two months back).

A few things to note:

  1. as mentioned above, I stick to one export per file to make HMR work consistently
  2. when adding/removing hooks, HMR fails and an error message appears. make sense, nothing to complain
  3. react-refresh catches all console error messages and make them full screen, at first it is kinda annoying because of some vendor error, then I realised that it is there for a good reason, it forces me to fix the errors even if it is from third-party libraries, from which I always learn something new.
nemonemi commented 3 years ago

I'd like to add that I've tested the native HMR support by generating a new workspace with the latest version, and there it worked.

At the moment I am unable to migrate my project to the latest version of NX because of some issues with Yarn2, but it is worth investigating if HMR is supported natively by the NX with the latest versions.

p.s. I've checked the releases, and nowhere it is mentioned that they did anything in this direction, however, it works.

xiongemi commented 3 years ago

the react fast fresh is added in or https://github.com/nrwl/nx/pull/5612, which is merged in https://github.com/nrwl/nx/releases/tag/12.3.5. if you got an exiting nx repo, after you migrate a version >= 12.3.5 , you could turn it on by add "hmr": true in workspace.json -> projects -> -> targets -> serve -> options, like:

"serve": {
          "executor": "@nrwl/web:dev-server",
          "options": {
            "buildTarget": "react:build",
            "hmr": true,
          },

so when you run nx serve <your react app name>, you will have hmr enabled.

or you could just run serve command with hmr flag passed in like nx serve <your react app name> --hmr.

FrozenPandaz commented 3 years ago

Closing this issue as it's now implemented in https://github.com/nrwl/nx/pull/5612 :tada:

github-actions[bot] commented 1 year ago

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.