1

I've built a React app that works fine on Chrome. Now I wanted to convert it into an Electron app. The assets located in the /public directory (pictures, icons, JSON files) cannot be loaded in the electron app.
The browser console displays errors while loading these files:
Failed to load resource: net::ERR_FILE_NOT_FOUND.
When I insert an asset picture from the public directory directly in the generated index.html file like

<img src="pic.png" alt=" pic"/>

it works, but loading it the same way from react components doesn't work. The asset files are being loaded from the root (e.g. file://pic.png)

Here is the project structure:

project structure screenshot

package.json:

  "homepage": "./",
  "main": "src/electron-starter.js",
  "build": {
    "appId": "com.myapp",
    "productName": "App",
    "files": [
      "build/**/*",
      "src/electron-starter.js"
    ],
    "directories": {
      "buildResources": "public"
    },
    "win": {
      "target": "NSIS"
    },
    "linux": {
      "target": [
        "AppImage",
        "deb"
      ],
      "category": "Audio"
    },
    "dmg": {
      "contents": [
        {
          "x": 110,
          "y": 150
        },
        {
          "x": 240,
          "y": 150,
          "type": "link",
          "path": "/Applications"
        }
      ]
    }
  }

createWindow function inside electron-starter.js:

function createWindow () {

    const mainWindow = new BrowserWindow({
        width: 1200,
        height: 700,
        webPreferences: {
            nodeIntegration: true
        }
    })

    if (process.env.ELECTRON_START_URL) {
        mainWindow.loadURL(process.env.ELECTRON_START_URL);
    } else {
        mainWindow.loadURL(url.format({
            pathname: path.join(__dirname, '../build/index.html'),
            protocol: 'file',
            slashes: true
        }))
    }

    mainWindow.webContents.openDevTools()
}

Thank's in advance for your help!

Ahwar
  • 1,746
  • 16
  • 30
Sparkle_924
  • 31
  • 1
  • 5
  • Check this https://stackoverflow.com/questions/60273475/cant-add-icon-to-electron-app-with-electron-builder/60319954#60319954 – tpikachu Jul 11 '20 at 14:32

2 Answers2

2

It turns out that Electron doesn't use React's /public directory. So I moved the required assets into /src/assets and imported them directly inside the component classes. Example:

import logo from "../assets/logo.png";

class MyComponent extends React.Component {
    render() {
        <img src={logo} alt="my_logo"/>
    }
}

I've also added <base href="./"/> to the header of the index.html file.

Sparkle_924
  • 31
  • 1
  • 5
  • For anyone still experiencing the same error after implementing this solution, you might need to also modify your `d.ts` file as described in [this answer](https://stackoverflow.com/a/51163365/15959847). – McKinley Aug 02 '22 at 13:20
0

i have this example, and you charge an path with "../" this example if you can enter with path don't need include ".." i hope you can resolve

import { ipcMain, dialog } from 'electron'
import isImage from 'is-image'
import filesize from 'filesize'
import fs from 'fs'
import path from 'path'

function setMainIpc (win) {
  ipcMain.on('open-directory', (event) => {
    dialog.showOpenDialog(win, {
      title: 'Select new location',
      buttonLabel: 'open dir',
      properties: ['openDirectory']
    },
    (dir) => {
      if (dir) {
        loadImages(event, dir[0])
      }
    })
  })

  ipcMain.on('load-directory', (event, dir) => {
    loadImages(event, dir)
  })

  ipcMain.on('open-save-dialog', (event, ext) => {
    dialog.showSaveDialog(win, {
      title: 'save image modify',
      buttonLabel: 'save imagen',
      filters: [{name: 'Images', extensions: [ext.substr(1)]}]
    }, (file) => {
      if (file) {
        event.sender.send('save-image', file)
      }
    })
  })

  ipcMain.on('show-dialog', (event, info) => {
    dialog.showMessageBox(win, {
      type: info.type,
      title: info.title,
      message: info.message
    })
  })
}

function loadImages (event, dir) {
  const images = []

  fs.readdir(dir, (err, files) => {
    if (err) throw err

    for (var i = 0, length1 = files.length; i < length1; i++) {
      if (isImage(files[i])) {
        let imageFile = path.join(dir, files[i])
        let stats = fs.statSync(imageFile)
        let size = filesize(stats.size, {round: 0})
        images.push({filename: files[i], src: `plp://${imageFile}`, size: size})
      }
    }

    event.sender.send('load-images', dir, images)
  })
}

module.exports = setMainIpc