electron / forge

:electron: A complete tool for building and publishing Electron applications
https://electronforge.io
MIT License
6.49k stars 519 forks source link

Hot reloading / React Refresh no longer works with default settings #2560

Open lostfictions opened 3 years ago

lostfictions commented 3 years ago

Pre-flight checklist

Electron Forge version

6.0.0-beta.61

Electron version

v15.1.0

Operating system

Ubuntu 20.04 x64

Last known working Electron Forge version

6.0.0-beta.54

Expected behavior

In 6.0.0-beta.54, I had a working setup using react-refresh-webpack-plugin, which is currently the recommended (and least intrusive) way to add HMR to a React app. Using this plugin, React components can be edited and will hot-reload with minimum latency and without losing their state.

Actual behavior

I recently created a new electron-forge project, using version 6.0.0-beta.61. Using the same approach, hot reloading doesn't work. Instead, the entire application will perform a full, hard reload on every change -- in fact, it'll even sometimes reload when editing entirely unrelated files (for example, files that are in the source tree but not part of Webpack's require tree).

After pulling my hair out and digging into electron-forge internals trying to understand what was happening, I finally discovered that setting liveReload to false in the forge config in package.json fixes the issue:

 "config": {
    "forge": {
      "plugins": [
        [
          "@electron-forge/plugin-webpack",
          {
            "devServer": { "liveReload": false },       // <- this line fixes the issue
            "mainConfig": "./webpack.main.config.js",
            "renderer": {
              "config": "./webpack.renderer.config.js",
              "entryPoints": [
                {
                  "html": "./src/index.html",
                  "js": "./src/renderer.tsx",
                  "name": "main_window"
                }
              ]
            }
          }
        ]
      ]
    }
  },

This allows hot reloading to take place without webpack-dev-server forcing a full refresh on every edit. It'll still perform a complete refresh when a hot update doesn't succeed, which is the expected behaviour.

I've set up webpack-dev-server with HMR before and don't recall having to set liveReload to false, which maybe points to an issue in electron-forge's internal configuration. What's more, I suspect this is not a React-specific issue and is suboptimal for any framework or setup where a full renderer reload on every change is not desired. It might be worth offering a higher-level configuration option for hot reloading, autodetecting common hot reload scenarios, or even just documenting this setting very clearly.

Steps to reproduce

Additional information

No response

ehaskins commented 2 years ago

I've create a minimal reproduction at https://github.com/ehaskins/electron-forge-2560-hmr-broken-reproduction.

Steps to reproduce repro repository:

  1. npx create-electron-app my-new-app --template=typescript-webpack
  2. Add to end of `src/renderer.ts'

    async function render() {
      let app = await import("./app");
    }
    
    render();
    
    if (module.hot) {
      module.hot.accept("./app", () => render());
    }
  3. Add new file src/app.ts
      export {}
      console.log('๐Ÿ‘‹ This message is being logged by "app.js", included via webpack');

Steps to reproduce bug

  1. npm start
  2. Enable "Preserve Log" in dev tools console
  3. Change message in src/app.ts
  4. Observe live reload instead of hot reload
[webpack-dev-server] App updated. Recompiling...
index.js?387e:548 [webpack-dev-server] "C:\src\my-new-app\.webpack\renderer\main_window\index.html" from static directory was changed. Reloading...
โ€‹ [webpack-dev-server] Nothing changed.
Navigated to http://localhost:3000/main_window
log.js?10ae:24

Expected behavior, and behavior when disabling live reload

[webpack-dev-server] App updated. Recompiling...
index.js?387e:548 [webpack-dev-server] App hot update...
log.js?10ae:24 [HMR] Checking for updates on the server...
app.ts?066e:2 ๐Ÿ‘‹ This message is being logged by "app.js", included via webpack
log.js?10ae:24 [HMR] Updated modules:
log.js?10ae:24 [HMR]  - ./src/app.ts
log.js?10ae:24 
chetbox commented 2 years ago

Thank you for this. You helped me to get hot reloading working again rather than the whole window refreshing.

I set devServer: { hot: true, liveReload: false } in the plugin config for @pmmmwh/react-refresh-webpack-plugin:

  plugins: [
    [
      '@pmmmwh/react-refresh-webpack-plugin',
      {
        devServer: { hot: true, liveReload: false }, // Required for @pmmmwh/react-refresh-webpack-plugin
        // ...
damienallen commented 2 years ago

I'm migrating from pre-beta.58 with react-refresh and ran into this issue.

While the proposed solution does work, I still get one full reload after making the first change (after yarn start). From that point forwards, it seems to work flawlessly, even after a hard reload of the browser window. However, I can definitely work with this and am very happy to have this working again!

MauricePasternak commented 2 years ago

For anyone else finding this issue (manifesting as your code editor losing focus after every change) and using the Electron-Typescript-Webpack template on a Linux operating system, another way to implement @chetbox 's nice solution is to do the following steps:

1) Install https://www.npmjs.com/package/@pmmmwh/react-refresh-webpack-plugin

yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh

2) In package.json:

  "config": {
    "forge": {
      "plugins": [
        [
          "@electron-forge/plugin-webpack",
          {
            "devServer": { "liveReload": false },  // <- this line is needed; remove this comment
            "mainConfig": "./webpack.main.config.js",
            "renderer": {
              "config": "./webpack.renderer.config.js",
              "entryPoints": [
                {
                  "html": "./src/index.html",
                  "js": "./src/renderer.ts",
                  "name": "main_window",
                  "preload": {
                    "js": "./src/preload.ts"
                  }
                }
              ]
            }
          }
        ]
      ],
...

3) In webpack.plugins.js:

const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");

module.exports = [new ForkTsCheckerWebpackPlugin(), new ReactRefreshWebpackPlugin()];

I found this allowed me to change code without my editor's window losing focus and the state of the Electron application was preserved (insofar as a quick useState example indicated). If you wish to reset the state while developing, refresh the electron window (Ctrl + R on Linux & Windows in case you're using a frameless electron app like I am).

NiftyliuS commented 2 years ago

@MauricePasternak well played! much thanks!

I followed steps:

  1. https://www.electronforge.io/templates/typescript-+-webpack-template
  2. https://www.electronforge.io/guides/framework-integration/react-with-typescript

then added your solution:

I made a sample just in case ( Branch with hot reload )

1lilyal1 commented 1 year ago

if I add - "devServer": { "LiveReload": false }, then "preload, main" will stop restarting. So I need to press CTRL+R, which is inconvenient. Are there any solutions for this?

IsaiahByDayah commented 1 year ago

As of @electron-forge @6.0.5 I managed to get this working with @MauricePasternak's solution + @erikian's preload config fix here ๐Ÿ‘๐Ÿพ

nojitsi commented 1 year ago

Confirming, the mentioned solution works for me too, with webpack and node integration setting.