Search code examples
electronserver-side-renderingnuxt3.js

Nuxt 3 + Electron no possible configuration to enable SSR


I am working on a project (just for my own interest) to make a faster searching file explorer. I am used to making my web-projects in Nuxt, so I wanted to try if I could combine electron with Nuxt to make a nice simple application.

For this project, I need to do some server side rendering (getting directories and drives from the users computer). I do this by using the integrated server api routes from nuxt. This basically works the same as a rest api, so i can just fetch from my frontend to that route.

Works verry nice in development mode in the browser! But when I want to fetch the directories from the server side api, the functionality does not work because it cannot host the server-side. Electron also relies on the 'nuxt generate' command, because electron needs an index.html. When trying to use 'nuxt build' instead, it does not create the required index.html anymore.

Any one knows a solution so this still works? You can play around at my github repository. To run the functionality in the browser, use the startup command yarn dev, and to run it using electron, use yarn generate, then use yarn start to run the application.


Solution

  • I tried multiple approaches, and after a couple of days I got it to work.

    1. My first approach, was to use import { fork, spawn } from 'child_process' (one of the fork or spawn methods from child_process) to spin up the server that allows SSR by running nuxt build (which generates .output/server/index.mjs) and run it using:

      fork(path.join(process.env.ROOT, '.output/server/index.mjs'))
      

      This worked great when running electron . in my package.json as a command, because it did spin up the server, and by using window.loadURL('http://localhost:3000') (instead of the index.html), the SSR was working and the frontend page was loaded.
      But the problem was that fork or spawn from child_process are not working after packaging the app using electron-builder. This is because the environment does not contain node anymore after building the package in an app.

    2. My second approach (after trying to make approach 1 work for 2 days) was to use const { pathToFileURL } = require('url') to load the module and to call the script in the main.js electron file. This is done by dynamically importing the script and running it by using:

      const modulePath = path.join(process.env.ROOT, '.output/server/index.mjs');
      const moduleUrl = pathToFileURL(modulePath).href;
      const { default: startServer } = await import(moduleUrl);
      
      if (typeof startServer === 'function') {
          startServer();
      }
      

      This method works in development mode, but also after packaging the application using electron-builder!. The only added configuration that you need to do is including the following text in your package.json:

      "build": {
          "extraResources": [
              ".output/server/**"
          ]
      }
      

    Conclusion: make sure you use the second approach to make SSR work with Nuxt 3 and Electron. Do not forget to run the server script first, and then create the window, so make for example a function called startWebServer and a function called createWindow to run this code:

    app.whenReady()
      .then(startWebServer)
      .then(createWindow)