React项目集成Electron-APP
·
React项目集成Electron-APP,打包好的react项目直接使用index.html loadurl 出现js,css等资源找不到的情况解决方案
概要
最近做了一个项目,是已有的react项目,需要改造成electron-app,再加上一些客户端的功能,例如打开点击图标打开某个具体的应用,或者打开某个目录。
首先,需要新建一个electron-app, 这个目录可以新建,与原先的的React项目可以分开。关于如何新建electron-app这里不做赘述。
在你的electron-app的main.js里写下如下内容:
const win = new BrowserWindow({
width: 1920,
height: 1080,
minHeight: 632,
minWidth: 960,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
webSecurity: false // 禁用webSecurity,避免CORS错误
}
});
win.loadURL(entryPath );
其中serverurl是你的项目地址,例如,一下的dist文件是我的react项目打包后的文件
const entryPath = path.resolve(__dirname, '../dist/index.html')
win.loadFile(entryPath)
如果你的项目地址支持,可以直接上线,那serverURL就会是 htttp://xx.xx.xx.xx:xxxx
由于我自身的项目不支持,同时直接引入dist下index.html,将会导致你在本地运行时,页面无法直接引用index.html中的js文件。
所以我找了种可以避免使用线上react地址的方式,也就是每次打开应用则新开一个端口用作重定向,所有index.html以及相应的资源可以通过重定向的方式进行查找。
在你的main.js中先进行服务器的启动
// 启动HTTP服务器
console.log('Starting HTTP server...');
serverProcess = exec('node server.mjs', { cwd: __dirname }, (error, stdout, stderr) => {
if (error) {
console.error('Server start error:', error);
}
});
// 等待服务器启动,然后加载URL
setTimeout(() => {
// 加载HTTP服务器提供的文件,避免CORS错误
let serverPort = 3002;
const portFile = path.resolve(__dirname, 'server-port.txt');
// 读取服务器实际使用的端口
if (fs.existsSync(portFile)) {
serverPort = parseInt(fs.readFileSync(portFile, 'utf8'));
console.log('Server port from file:', serverPort);
}
const serverURL = `http://localhost:${serverPort}/`;
console.log('Loading URL:', serverURL);
win.loadURL(serverURL);
}, 2000);
server.mjs 是实际执行启动服务器的关键文件。其中内容是
import http from 'http';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// 获取当前文件的目录路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let port = 3002;
const outDir = path.join(__dirname, '../out');
// 创建服务器
const server = http.createServer((req, res) => {
// 解析请求路径
let filePath = path.join(outDir, req.url === '/' ? 'index.html' : req.url);
// 检查文件是否存在
fs.stat(filePath, (err, stats) => {
if (err) {
// 文件不存在,返回index.html(支持单页应用路由)
filePath = path.join(outDir, 'index.html');
} else if (stats.isDirectory()) {
// 如果是目录,返回index.html
filePath = path.join(filePath, 'index.html');
}
// 读取文件
fs.readFile(filePath, (err, content) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('File not found');
return;
}
// 设置Content-Type
const extname = path.extname(filePath);
let contentType = 'text/html';
switch (extname) {
case '.js':
contentType = 'text/javascript';
break;
case '.css':
contentType = 'text/css';
break;
case '.json':
contentType = 'application/json';
break;
case '.png':
contentType = 'image/png';
break;
case '.jpg':
case '.jpeg':
contentType = 'image/jpeg';
break;
case '.gif':
contentType = 'image/gif';
break;
case '.svg':
contentType = 'image/svg+xml';
break;
}
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
});
});
});
// 尝试启动服务器,直到找到可用端口
function startServer() {
server.listen(port, 'localhost', () => {
console.log(`Server running at http://localhost:${port}/`);
console.log('Press Ctrl+C to stop the server');
// 将端口信息保存到临时文件,供Electron应用读取
fs.writeFileSync(path.join(__dirname, 'server-port.txt'), port.toString());
});
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.log(`端口 ${port} 被占用,尝试使用端口 ${port + 1}`);
port++;
startServer();
} else {
console.error('服务器启动失败:', err);
}
});
}
// 启动服务器
startServer();
这段代码的主要逻辑是启动一个本地服务器,占用机器的端口,然后对应用内容的资源重定向,以防直接查看文件查找不到。同时,以防本地端口被占用,每次启动时都会查看端口是否被占用,如果占用的话使用新端口,server.port.text文件则用来存放端口信息,供loadUrl使用。
更多推荐


所有评论(0)