reactjselectronelectron-react-boilerplate

Hash routing in production throwing file not found error


I am using the electron-react-boilerplate and want to open a component in a new BrowserWindow. There are multiple questions and answers on how to do this, but none of them are working after packaging the app.

Questions / Answers I've Found:

In my component I have tried to use the following lines to open a new window to a different route.

wind.loadURL(`file://${__dirname}/app.html#/video`)

wind.loadURL(`file://${Path.join(__dirname, '../build/app.html#/video')}`)

wind.loadURL(`file://${Path.join(__dirname, '../build/index.html#/video')}`)

The first one works when running yarn dev, but not in production. They all throw ERR_FILE_NOT_FOUND for the respective paths.

This is how my routes are set up:

export default function Routes() {
  return (
    <App>
      <HashRouter>
        <Route exact path={routes.HOME} component={HomePage} />
        
        <Route path={routes.VIDEO} component={VideoPage} />
      </HashRouter>
    </App>
  );
}

Is there an easy way to allow routing when opening a new BrowserWindow using React's router?


Solution

  • Great timing. I was in the same boat the past few days, just figured it out. Except, I didn't change to HashRouter like you did. Rather I left all the routing stuff as the default electron-react-boilerplate comes with, like ConnectedRouter. Maybe either way works.

    https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/1853#issuecomment-674569009

    __dirname only works in dev. I used DebugTron to check what URLs were being loaded for each resource, and it was file://path/to/app.asar/something. Then I figured out how to get the path to the asar. This worked for me in both dev and prod, regardless of where the application is located. You also need to set nodeIntegration: true. Tested on macOS.

    const electron = require("electron")
    //...
    win.loadURL(`file://${electron.remote.app.getAppPath()}/app.html#/yourroutename`)
    

    Fuller example in case anyone is also wondering how to load another page and pass arguments to it:

    import routes from '../constants/routes.json'
    const electron = require("electron")
    // ...
    var win = new BrowserWindow({
      width: 400, height: 400,
      webPreferences: { nodeIntegration: true }
    })
    win.loadURL(`file://${electron.remote.app.getAppPath()}/app.html#${routes["ROOM"]}?invitationCode=${encodeURIComponent(code)}`)
    win.show()
    

    and in the component the route loads:

    const queryString = require('query-string')
    // ...
    constructor(props) {
      super(props)
      const params = queryString.parse(location.hash.split("?")[1])
      this.invitationCode = params.invitationCode
    }