Serving static files in Electron (React app)
Solution 1
I found another solution without using express
or serve-static
, we only
need to cusomize Electron built-in interceptFileProtocol()
to serve static contents.
Code:(main.js)
(I use the electron-quick-start as Electron template)
function createWindow () {
window = new BrowserWindow({ width: 800, height: 600 })
window.loadURL(url.format({
pathname: 'index.html', /* Attention here: origin is path.join(__dirname, 'index.html') */
protocol: 'file',
slashes: true
}))
window.on('closed', () => {
window = null
})
}
app.on('ready', () => {
protocol.interceptFileProtocol('file', (request, callback) => {
const url = request.url.substr(7) /* all urls start with 'file://' */
callback({ path: path.normalize(`${__dirname}/${url}`)})
}, (err) => {
if (err) console.error('Failed to register protocol')
})
createWindow()
})
Reference: protocol.interceptFileProtocol()
Explaination:
Normally, if you run React app as a normal website, all static contents should be served by
HTTP [GET]
method. Though they use relative paths, your HTTP server will handle the path parsing work.However, when running under Electron, things change.
Your static contents usually use relative path like
./picture.jpg
, Electron will usefile
protocol instead ofHTTP
protocol and find the file under root path likeC://.//
. So static contents like./picture.jpg
won't be loaded correctly.By customizing
interceptFileProtocol()
, all static contents' requests will be pointed to your working directory instead of Windows(or other OS) root.
Finally, I'm not sure whether it's a good solution for all Electron projects, but if you already have a React
project (or some other SPA) and want to wrap it with Electron, this solution would be fine to use.
Solution 2
As an addition to the great answer from @yeze322 above, here a working sample for all not so familiar with node and electron (like me). It took me some time to find out the correct require statements.
main.js (code from @yeze322 plus required imports)
const { app, BrowserWindow, protocol } = require('electron')
const path = require('path')
const url = require('url')
let mainWindow
function createWindow() {
mainWindow = new BrowserWindow({ width: 800, height: 600 })
mainWindow.loadURL(url.format({
pathname: 'index.html', /* Attention here: origin is path.join(__dirname, 'index.html') */
protocol: 'file',
slashes: true
}))
mainWindow.on('closed', function () {
mainWindow = null
})
}
app.on('ready', () => {
protocol.interceptFileProtocol('file', (request, callback) => {
const url = request.url.substr(7) /* all urls start with 'file://' */
callback({ path: path.normalize(`${__dirname}/${url}`) })
}, (err) => {
if (err) console.error('Failed to register protocol')
})
createWindow()
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
if (mainWindow === null) {
createWindow()
}
})
Solution 3
In your main file you have
const app = require("app")
app.on("ready", () => {
...
Here you can start the server like you would do in node.js
const serveStatic = require('serve-static')
// or
const express = require('express')
...
}
Ales Maticic
I can bootstrap a startup prototype in couple of weeks all by myself. I do everything from server administration, platform development to design presentation. My blog http://www.7loops.com/
Updated on June 15, 2022Comments
-
Ales Maticic almost 2 years
I am working on a project where I need to build a desktop app in Electron. The majority of functionality will be built in React, but there will be a part where we need to integrate a 3rd party static HTML magazine. I need some advice on how to do this. I am building a proof of concept app currently and I have based it on this https://github.com/chentsulin/electron-react-boilerplate
how would I add that on /static/ I server static HTML files. I know I could do it in express, but I really don't want to include the entire express framework just for serving static files.
I was looking at this https://www.npmjs.com/package/serve-static but have no Idea how to integrate it in my react app and bundle it into electron app.
-
Chris Dolphin over 6 yearsThis worked for me, but then I had trouble requiring my index js file in index.html using relative paths. Ended up requiring it using an absolute, by getting app path with
require('electron').remote.app.getAppPath()
-
Marcelo H. Carneiro almost 6 yearsWhere u added it @ChrisDolphin? I with a big problem here, works fine with dev mode but after pack the app doesn't work, driving me crazy
-
Marcelo H. Carneiro almost 6 yearsWorks here, i changed the url = path.join(require('electron').remote.app.getAppPath(), WEB_FOLDER, url), thanks, works when packing the app
-
Marcelo H. Carneiro almost 6 yearsWorks here, i changed the url = path.join(require('electron').remote.app.getAppPath(), WEB_FOLDER, url), thanks, works when packing the app
-
shivshankar almost 5 yearsOn development mode, serving using webpack give me error "can't find module react", mean module resolve issue while without intercept protocol it works, any idea ?
-
davidkomer over 4 yearsNothing personal - but this should really just be a comment on @yeze322's answer. I spent a bit of time looking between the two answers trying to figure out which I should use ;)
-
davidkomer over 4 yearsCouple points: 1. would be nicer to incorporate all the imports etc. like @zgue showed. 2. another problem I ran into is that it only works like this if webpack html template does not inject the hash - so make sure that's off ;)
-
Eric Burel about 4 yearsHi, I found it easier to create a custom
app
protocol so it does not interfere withfile://
, usingregisterFileProtocol
(syntax is identical tointerceptFileProtocol
). Also you may need to remove the query param of URL for URLs likeapp://foobar.js?version=2
, you should drop the?version=2
. It was useful for me to install MathJax in an Electron app for example. -
punjabi4life over 3 yearsThanks, I was able to use this to run a Blazor WebAssembly app through Electron. After making the Blazor WebAssembly app into static files.