4

I am trying to turn my react webapp into a standalone desktop application using electron. (Full disclosure, I've never used electron before)

Getting it running in development mode was amazingly easy. All of my react elements are rendered nicely, and it can still talk to my external express webserver with RESTAPI calls.

However, I have not been able to get it to display correctly when I try to build a production version.

I am running the command:

yarn react-build && yarn electron-builder

this creates my dist and build directories. When I run the executable I see my React header, but my content never loads. There are no errors in the electron devtools console, but when I clicked on build/index.html and open it in a browser, I see the same thing rendered and the console shows the error

Access to internal resource at 'file:///C:/Users/prrose/Documents/gitlab/Frontend/build/manifest.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

my index.html is in the public folder and looks like this:

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/sas-icon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="shortcut icon" href="%PUBLIC_URL%/sas-icon.ico">
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/sas-icon.ico" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>Smart Subscriber</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

my manifest.json is in the same directory and looks like this:

{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "sas-icon.ico",
      "type": "image/x-icon",
      "sizes": "48x48"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

my package.json

{
  "name": "smart-subscriber",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@ant-design/icons": "^4.0.5",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "antd": "^4.4.1",
    "axios": "^0.19.2",
    "body-parser": "^1.19.0",
    "connect-timeout": "^1.9.0",
    "cors": "^2.8.5",
    "cross-env": "^6.0.2",
    "dotenv": "^8.2.0",
    "electron-is-dev": "^1.1.0",
    "electron-log": "^3.0.8",
    "electron-packager": "^15.1.0",
    "express": "^4.17.1",
    "jszip": "^3.5.0",
    "mqtt": "^4.0.0",
    "mysql2": "^2.0.2",
    "prop-types": "^15.7.2",
    "puppeteer": "^4.0.1",
    "react": "^16.13.0",
    "react-bootstrap": "^1.0.0",
    "react-dom": "^16.13.0",
    "react-highlight-words": "^0.16.0",
    "react-router-dom": "^5.1.2",
    "react-scripts": "^3.4.3",
    "sequelize": "^5.21.2",
    "update-electron-app": "^1.2.0",
    "xml2js": "^0.4.23",
    "yarn": "^1.22.4"
  },
  "win": {
    "icon": "./public/sas-icon.ico"
  },
  "main": "public/electron.js",
  "homepage": "./",
  "scripts": {
    "react-start": "react-scripts start",
    "react-build": "react-scripts build",
    "react-test": "react-scripts test --env=jsdom",
    "react-eject": "react-scripts eject",
    "electron-build": "electron-builder",
    "release": "yarn react-build && electron-builder --publish=always",
    "build": "yarn react-build && yarn electron-build",
    "start": "concurrently  \"cross-env BROWSER=none yarn react-start\" \"wait-on http://localhost:8081 && electron .\"",
    "test": "react-scripts test --env=jsdom"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "concurrently": "^4.1.2",
    "electron": "^6.0.11",
    "electron-builder": "^21.2.0",
    "enzyme": "^3.11.0",
    "enzyme-adapter-react-16": "^1.15.2",
    "prettier": "^1.4.4",
    "react-test-renderer": "^16.13.1",
    "wait-on": "3.3.0",
    "chai": "^4.2.0",
    "chai-http": "^4.3.0",
    "mocha": "^7.1.2",
    "nodemon": "^2.0.4",
    "nyc": "^15.1.0"
  },
  "babel": {
    "presets": [
      "react"
    ]
  }
}

my electron.js (entry point) looks like:

const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

const path = require("path");
const isDev = require("electron-is-dev");
//let server = require(`${path.join(__dirname, "../public/server")}`);

let mainWindow;


function createWindow() {
  mainWindow = new BrowserWindow({ icon:'./public/sas-icon.ico', minWidth: 1250, width: 1600, height: 1000, webPreferences: { nodeIntegration: true, webSecurity: false }});
  mainWindow.loadURL(
    isDev
      ? "http://localhost:8081"
      : `file://${path.join(__dirname, "../build/index.html")}`
  );
  mainWindow.on("closed", () => (mainWindow = null));
}
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors');
app.on("ready", createWindow);

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("activate", () => {
  if (mainWindow === null) {
    createWindow();
  }
});

I tried adding webSecurity : false to the main window options, and when that failed I tracked down this github bug here, and tried

app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors');

Both give nasty warnings in the console, but do not allow index.html to render manifest.json.

Considering that this is template code.....there's got to be a way to get them to talk to eachother. How do I

  1. disable CORS to allow it to load manifest.json
  2. set an origin for manifest.json so that I can specify which CORS to allow.
  3. Bypass this problem all together....if possible.

0 Answers0