在Electron中提供静态文件(React app)

时间:2016-07-05 13:29:04

标签: javascript node.js reactjs electron

我正在开发一个项目,我需要在Electron中构建一个桌面应用程序。大多数功能都将在React中构建,但是我们需要集成第三方静态HTML杂志。我需要一些关于如何做到这一点的建议。我目前正在构建一个概念验证应用程序,我将其基于此https://github.com/chentsulin/electron-react-boilerplate

如何在/ static / I服务器静态HTML文件上添加它。我知道我可以在express中完成它,但我真的不想仅仅为了提供静态文件而包含整个快速框架。

我正在看这个https://www.npmjs.com/package/serve-static,但不知道如何将它整合到我的反应应用中并将其捆绑到电子应用中。

4 个答案:

答案 0 :(得分:12)

我发现了另一种不使用expressserve-static的解决方案,我们只是 需要定制Electron内置interceptFileProtocol()来提供静态内容。

<强>代码 :( main.js)

(我使用electron-quick-start作为电子模板)

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()
})

<强>参考protocol.interceptFileProtocol()

<强>释

  • 通常,如果您将React应用作为普通网站运行,则所有静态内容都应由HTTP [GET]方法提供。虽然它们使用相对路径,但您的HTTP服务器将处理路径解析工作。

  • 然而,当在Electron下运行时,事情会发生变化。

  • 您的静态内容通常使用./picture.jpg之类的相对路径,Electron将使用file协议而不是HTTP协议,并在根路径下查找文件,如C://.// 。因此,./picture.jpg等静态内容无法正确加载。

  • 通过自定义interceptFileProtocol(),所有静态内容的请求将指向您的工作目录而不是Windows(或其他操作系统)根目录。

最后,我不确定这对所有Electron项目是否是一个很好的解决方案,但是如果你已经有一个React项目(或其他一些SPA)并希望用Electron包装它,那么这个解决方案就是很好用。

答案 1 :(得分:3)

除了上面@ yeze322的出色答案之外,这里还有一个工作样本,适用于所有不太熟悉节点和电子的人(例如我)。我花了一些时间才能找到正确的require语句。

main.js(来自@ yeze322的代码以及所需的导入)

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()
  }
})

答案 2 :(得分:0)

在您的主文件中

const app = require("app")
app.on("ready", () => {
  ...

您可以像在node.js中一样启动服务器

  const serveStatic = require('serve-static')
  // or
  const express = require('express')
  ...
}

答案 3 :(得分:0)

在资源目录中放置第三次尝试资源可以解决问题