electron / forge

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

ReactRefresh - Addition of Hot Reloading creates preload.js error #3115

Open ynnelson opened 1 year ago

ynnelson commented 1 year ago

Pre-flight checklist

Electron Forge version

6.0.3

Electron version

21.3.1

Operating system

macOS 12.4

Last known working Electron Forge version

No response

Expected behavior

Expected not to have issues after adding React Refresh and to not have the entire window refresh every time. I expected to only have the one component refreshed and not the whole window.

I am trying to understand how to run React Refresh within Electron Forge properly, I searched the existing issues and this is where I got my forge.config.ts file updates from aka setting liveReload to false but I seem to still be getting some errors.

I'd appreciate some guidance to get it to work appropriately. Also before adding React Refresh I did not get the __dirname is not defined error or the Unable to load preload script error.

Actual behavior

When I do yarn run start I get the below errors in the console: image

Steps to reproduce

package.json

{
  "name": "client-desktop-phoenix-edition",
  "productName": "client-desktop-phoenix-edition",
  "version": "1.0.0",
  "description": "My Electron application description",
  "main": ".webpack/main",
  "scripts": {
    "start": "electron-forge start",
    "package": "electron-forge package",
    "make": "electron-forge make",
    "publish": "electron-forge publish",
    "lint": "eslint --ext .ts,.tsx ."
  },
  "keywords": [],
  "author": {
    "name": "",
    "email": ""
  },
  "license": "MIT",
  "devDependencies": {
    "@electron-forge/cli": "^6.0.3",
    "@electron-forge/maker-deb": "^6.0.3",
    "@electron-forge/maker-rpm": "^6.0.3",
    "@electron-forge/maker-squirrel": "^6.0.3",
    "@electron-forge/maker-zip": "^6.0.3",
    "@electron-forge/plugin-auto-unpack-natives": "^6.0.3",
    "@electron-forge/plugin-electronegativity": "^6.0.3",
    "@electron-forge/plugin-local-electron": "^6.0.3",
    "@electron-forge/plugin-webpack": "^6.0.3",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
    "@types/react": "^18.0.26",
    "@types/react-dom": "^18.0.9",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "@vercel/webpack-asset-relocator-loader": "1.7.3",
    "css-loader": "^6.0.0",
    "electron": "21.3.1",
    "eslint": "^8.0.1",
    "eslint-plugin-import": "^2.25.0",
    "fork-ts-checker-webpack-plugin": "^7.2.13",
    "node-loader": "^2.0.0",
    "react-refresh": "^0.14.0",
    "style-loader": "^3.0.0",
    "ts-loader": "^9.2.2",
    "ts-node": "^10.0.0",
    "typescript": "~4.5.4"
  },
  "dependencies": {
    "electron-squirrel-startup": "^1.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.4.5"
  }
}

forge.config.ts

import type { ForgeConfig } from '@electron-forge/shared-types';
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
import { MakerZIP } from '@electron-forge/maker-zip';
import { MakerDeb } from '@electron-forge/maker-deb';
import { MakerRpm } from '@electron-forge/maker-rpm';
import { WebpackPlugin } from '@electron-forge/plugin-webpack';

import { mainConfig } from './webpack.main.config';
import { rendererConfig } from './webpack.renderer.config';

const config: ForgeConfig = {
  packagerConfig: {
    asar: true // or an object containing your asar options
  },
  rebuildConfig: {},
  makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})],
  plugins: [
    new WebpackPlugin({
      devServer: { liveReload: false },
      mainConfig,
      renderer: {
        config: rendererConfig,
        entryPoints: [
          {
            html: './src/index.html',
            js: './src/renderer.ts',
            name: 'main_window',
            preload: {
              js: './src/preload.ts',
            },
          },
        ],
      },
    }),
    // Electronegativity Plugin 
    // https://www.electronforge.io/config/plugins/electronegativity
    // Check for misconfigurations and security anti-patterns with the Electronegativity tool.
    {
      name: '@electron-forge/plugin-electronegativity',
      config: {
        isSarif: true
      }
    },
    // Auto Unpack Native Modules Plugin
    // https://www.electronforge.io/config/plugins/auto-unpack-natives
    // Reduce loading times and disk consumption by unpacking native Node modules from your Forge app's ASAR archive.
    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {}
    },
    // Local Electron Plugin
    // https://www.electronforge.io/config/plugins/local-electron
    // Integrate a local build of Electron into your Forge app.
    // This plugin allows you to both run and build your app using a local build of Electron.
    // {
    //   name: '@electron-forge/plugin-local-electron',
    //   config: {
    //     electronPath: '/Users/me/projects/electron/out/Testing', // path to Electron binary
    //   },
    // }

  ],
};

export default config;

wepbpack.plugin.ts

import type IForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import type ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const ForkTsCheckerWebpackPlugin: typeof IForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const webpack = require('webpack');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ReactRefreshWebpackPlugin: typeof ReactRefreshPlugin = require("@pmmmwh/react-refresh-webpack-plugin");

export const plugins = [
  new ForkTsCheckerWebpackPlugin({
    logger: 'webpack-infrastructure',
  }),
  new ReactRefreshWebpackPlugin()
];

Additional information

No response

erikian commented 1 year ago

I had this issue as well, looks like the plugin is bundling the preload script with the same webpack configuration used by the main script by default (https://github.com/electron/forge/pull/2679), so react-refresh-webpack-plugin and its dependencies end up in the bundled preload.js.

Since I'm not using the preload script (yet), adding an empty object as the preload webpack configuration worked for me:

new WebpackPlugin({
  devServer: { liveReload: false },
  mainConfig,
  renderer: {
    config: rendererConfig,
    entryPoints: [
      {
        html: './src/index.html',
        js: './src/renderer.ts',
        name: 'main_window',
        preload: {
          js: './src/preload.ts',
          config: {} // => add this
        },
      },
    ],
  },
}),

Maybe the main, renderer, and preload files should be moved to separate folders inside /src and the webpack configs for each of them should only look for files inside that folder to avoid this? šŸ¤”

Rychu-Pawel commented 1 year ago

I'm using preload script to load react. Any way to workaround this issue when using preload script? šŸ˜’

erikian commented 1 year ago

@Rychu-Pawel try this:

preload: {
  js: './src/preload.ts',
  config: {
    ...rendererConfig,
    plugins: [],
  },
}
Rychu-Pawel commented 1 year ago

@erikian this works like a charm!! Thank you so much šŸ» my life is going to get so much easier now šŸŒ…šŸŒ“ šŸø