Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Packaged app not working #18

Closed
ruohki opened this issue Apr 15, 2020 · 9 comments
Closed

Packaged app not working #18

ruohki opened this issue Apr 15, 2020 · 9 comments
Assignees
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers

Comments

@ruohki
Copy link

ruohki commented Apr 15, 2020

Describe the bug
After packaging the app (and running it) web windows stays empty.

Failed to load resource: net::ERR_FILE_NOT_FOUND
polyfills.js:1 Failed to load resource: net::ERR_FILE_NOT_FOUND
vendor.js:1 Failed to load resource: net::ERR_FILE_NOT_FOUND
main.js:1 Failed to load resource: net::ERR_FILE_NOT_FOUND

To Reproduce
Steps to reproduce the behavior:

  1. Setup boilerplate
  2. Package
  3. Run

Desktop (please complete the following information):

  • OS: Win10
  • Nx Electron Version ^9.0.0-beta.4"

Additional context
Using a React frontend app

@patrick-entinux
Copy link

patrick-entinux commented Apr 16, 2020

@ruohki I had a similar issue with an Angular frontend app.

My issue was the default base href setting, in that project's index.html file, it's configured to:

<base href="/" />

The / tells the browser to process any js/css URL relative to the root location "/". On the web this makes sense, but in Electron we usually load files directly from the file system. So '/' means the root of the file system. I changed the line in my index.html to this, to mean relative to the index.html file, and it worked:

<base href="./" />

Not sure about React frontend app, but it may be a similar system.

@ruohki
Copy link
Author

ruohki commented Apr 16, 2020

Thing is it will change it back to /, you can however set baseHref in the option object of the workspace.json config for your react app, but this will break the dev build so its switching back and forth all the time

@patrick-entinux
Copy link

Yeah, I have that issue with Angular frontend apps too, I often need a the "/" setting for dev mode and a different setting for the packaged app.

I don't know what the "best practice" is, but I've approached this issue 2 ways before. The first way is to set the baseHref for a specific configuration in the angular.json/workspace.json:

{
  "projects": {
    "my-app": {
      "root": "apps/my-app/",
      "sourceRoot": "apps/my-app/src",
      "projectType": "application",
      "prefix": "my-app",
      "schematics": {
        "@nrwl/schematics:component": {
          "style": "scss"
        }
      },
      "architect": {
        "build": {
          "builder": "@nrwl/builders:web-build",
          "configurations": {
            "production": {
              "baseHref": "./"
            }
          }
        }
      }
    }
  }
}

Then I can run:

nx build my-app --configuration=production

The second way is to have a "build script" and pass the special baseHref as a CLI argument, something like:

# make-electron-app.sh

nx build my-app --baseHref="./"
nx build my-app-electron-main
nx run my-app-electron-main:package

I haven't built a react app in nx workspace before, but it looks like the configuration for baseHref works basically the same way as Angular apps.

Sorry, these are just some made-up examples, hope it could help give some idea to get started.

@bennymeg
Copy link
Owner

@patrick-entinux thanks for answering.

I believe that issue is related to the frontend platform rather to 'nx-electron'.
Nevertheless, could you please explain why the 'baseHref' can be different on production? And if so, is there some issue that I need to address?

@patrick-entinux
Copy link

@bennymeg I mainly only have experience on the Angular side, so apologies if I've gotten something wrong, but let me try to explain:

Nevertheless, could you please explain why the 'baseHref' can be different on production?

Actually, after thinking about it, I don't know why in this case the "./" broke the development build.

In general, for an SPA (single page application) targeted to Electron only, I believe you must use base href "./" and hash router in production. Usually the default is base href "/" and not hash routing, so you have to change this for an Electron-targeted app.

In develop mode, it might not be necessary to use "./", but I think it should still generally be fine always, even if you access your frontend app directly in the browser.

That said, I have has similar problems between develop/production in Ionic/Cordova based mobile apps, which also have some weirdness about urls, so maybe there is some situation I've missed?

More info about routing/URL resolution in Electron apps:

Usually, for an Angular or React SPA (single page application) targeted to the web, we use some routing solution like

These tools take pretty urls like /projects/1 and a server configured for SPA, and always serve the index.html file in the root folder:

my-spa-app.com
my-spa-app.com/projects/1
localhost:3000
localhost:3000/projects/1

Inside the index.html file are some lines to load some scripts:

<script src="runtime.js" defer=""></script>
<script src="polyfills.js" defer=""></script>
<script src="styles.js" defer=""></script>
<script src="vendor.js" defer=""></script>
<script src="main.js" defer=""></script>

These script sources depends on base href of "/" to resolve correctly:

URL Base HREF Setting Script SRC Resolved Script URL Result
my-spa-app.com/projects/1 / runtime.js my-spa-app.com/runtime.js Success
my-spa-app.com / runtime.js my-spa-app.com/runtime.js Success
my-spa-app.com/projects/1 ./ runtime.js my-spa-app.com/projects/1/runtime.js Fail
my-spa-app.com ./ runtime.js my-spa-app.com/runtime.js Success

If we use "./", on some pages it will try to load runtime.js from "/projects/1/runtime.js", which does not exist. so we have to use "/".

In Electron dev mode, we usually use the dev server for Angular or React, so we load from a URL like localhost:3000 and this system still works.

However in Electron production mode, we usually serve the files directly from the file system and cannot do any "magic" in the server layer. In other words, we can only load from file:///users/patrick/Myapp.app/index.html, but we cannot use the URL file:///users/patrick/Myapp.app/projects/1, because no file exists there.

So for an SPA targeted to Electron, we usually change our Router to use the simpler hash "#" system instead:

Actually if you use the hash router in the browser, I think it should basically always work:

URL Base HREF Setting Script SRC Resolved Script URL Result
my-spa-app.com/#/projects/1 / runtime.js my-spa-app.com/runtime.js Success
my-spa-app.com / runtime.js my-spa-app.com/runtime.js Success
my-spa-app.com/#/projects/1 ./ runtime.js my-spa-app.com/runtime.js Success
my-spa-app.com ./ runtime.js my-spa-app.com/runtime.js Success

Anyways, using the hash router solves the first problem of serving files in Electron.

But there's also a second problem, the base href problem. If we still use "/" for the base href, then Electron starts trying to load the files from the root of our file system.

URL Base HREF Setting Script SRC Resolved Script URL Result
file:///users/patrick/Myapp.app/index.html/#/projects/1 / runtime.js file:///runtime.js Fail
file:///users/patrick/Myapp.app/index.html / runtime.js file:///runtime.js Fail
file:///users/patrick/Myapp.app/index.html/#/projects/1 ./ runtime.js file:///users/patrick/Myapp.app/runtime.js Success
file:///users/patrick/Myapp.app/index.html ./ runtime.js file:///users/patrick/Myapp.app/runtime.js Success

So to support Electron packaging, we have to use a base href setting of "./" AND use hash router for SPA (single page apps).


Coming back to the question:

And if so, is there some issue that I need to address?

In my my opinion, yeah, frontend code in Electron apps does require some special configuration. However, I'm not sure that nx-electron package could do anything differently. Even if nx-electron tried to modify the build config of your frontend app, it seems really "magical" and maybe confusing. Maybe on the nx-electron side you could just suggest in the documentation to use base href "./" and the hash router of your frontend app and possible give some info how to change that?

@bennymeg
Copy link
Owner

@patrick-entinux thank you for the elaborated explanation!

In general, for an SPA (single page application) targeted to Electron only, I believe you must use base href "./" and hash router in production.

I agree.

Even if nx-electron tried to modify the build config of your frontend app, it seems really "magical" and maybe confusing.

I agree, that would be confusing. What I can do is create a schematics that configure both backend electron project and a frontend project (i.e. electron-angular, electron-react, etc...). I believe that would be a good solution and would be coherent with nx.

Maybe on the nx-electron side you could just suggest in the documentation to use base href "./" and the hash router of your frontend app and possible give some info how to change that?

I will add a section about it to the documentation, and I will link it to your explanation since you have done a great job explaining it in details.

@bennymeg bennymeg self-assigned this Apr 21, 2020
@bennymeg bennymeg added documentation Improvements or additions to documentation good first issue Good for newcomers labels Apr 21, 2020
@dmitov
Copy link

dmitov commented Aug 5, 2022

For anyone who's struggling to get it working with NextJS - add assetPrefix to your next.config.js for packaged builds, like so:

const isProd = process.env.NODE_ENV === 'production'

/**
 * @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
 **/
const nextConfig = {
  nx: {
    // Set this to true if you would like to to use SVGR
    // See: https://github.com/gregberge/svgr
    svgr: false,
  },
  assetPrefix: isProd ? '.' : '',
};

Furthermore, you'd want to do nx run <frontend-app>:export and point to the exported index.html of NextJS inside the loadMainWindow method in apps/<electron-app-name>/src/app/app.ts like so:

private static loadMainWindow() {
    // load the index.html of the app.
    if (!App.application.isPackaged) {
      App.mainWindow.loadURL(`http://localhost:${rendererAppPort}`);
    } else {
      App.mainWindow.loadURL(
        format({
          pathname: join(__dirname, '..', rendererAppName, 'exported', 'index.html'),
          protocol: 'file:',
          slashes: true,
        })
      );
    }
  }

I haven't explored much more the integration between the two, but the welcome page loads fine with all styles and scripts. The nx run <frontend-app>:export limits the NextJS quite a bit (supported features), but it's still a great tool.

@talhaanees
Copy link

talhaanees commented Aug 14, 2023

For NX 15 onwards, baseHref will be in project.json file for your React app.

e.g.

"targets": {  
  "build": {
    "executor": "@nrwl/webpack:webpack",
    "configurations": {
      "production": {
        "baseHref": "./",
      }
    }
  }
}

@Bowbee
Copy link

Bowbee commented Feb 18, 2024

For anyone struggling using the @nx/vite plugin for building their frontend, you can add base: "./" to your vite.config.ts file within your frontend application.
Eg.

export default defineConfig({
  root: __dirname,
  base: './',
  ...
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

6 participants