Boa*_*rdy 5 installation node.js reactjs electron
我正在使用 Electron 和 ReactJS 开发一个新项目。该项目在开发模式下运行良好,但我正在尝试为 Windows 创建一个安装程序,但无论我尝试什么以及在 Google 上找到什么,都没有任何效果。我只是得到一个空白的白色屏幕。
下面是我的 pacakge.json
{
"name": "MyApp",
"description": "My App Description",
"version": "0.1.2",
"private": true,
"homepage": "./",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^26.0.14",
"@types/node": "^14.11.2",
"@types/react": "^16.9.50",
"@types/react-dom": "^16.9.8",
"bootstrap": "^4.5.2",
"electron-is-dev": "^1.2.0",
"electron-settings": "^4.0.2",
"electron-squirrel-startup": "^1.0.0",
"react": "^16.13.1",
"react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1",
"react-icons": "^3.11.0",
"react-json-pretty": "^2.2.0",
"react-scripts": "3.4.3",
"react-tooltip": "^4.2.10",
"typescript": "^4.0.3"
},
"main": "src/electron-starter.js",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron-start": "set ELECTRON_START_URL=http://localhost:3000 && electron .",
"package-win": "electron-packager . --asar --out=release-builds --platform=win32 --arch=x64 --no-prune --ignore=/e2e --overwrite",
"create-installer-win": "node installers/windows/createInstaller.js"
},
"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": {
"electron": "^10.1.3",
"electron-packager": "^12.0.1",
"electron-winstaller": "^4.0.1",
"react-router-dom": "^5.2.0",
"react-toastify": "^6.0.8"
}
}
Run Code Online (Sandbox Code Playgroud)
我的electron-start.js 脚本如下
const {electron, Menu, app, BrowserWindow} = require('electron');
// Module to control application life.
//const app = electron.app;
// Module to create native browser window.
//const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
if (require('electron-squirrel-startup')) app.quit()
// if first time install on windows, do not run application, rather
// let squirrel installer do its work
const setupEvents = require('../installers/setupEvents')
if (setupEvents.handleSquirrelEvent()) {
console.log("Squirrel event returned true");
process.exit()
//return;
}
console.log("Starting main program");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
/*const env = process.env.NODE_ENV;
let windowUrlBase = "";
if (env === "production")
{
windowUrlBase = "/";
}
else
{
windowUrlBase = 'http://localhost:3000';
}*/
let windowUrlBase = 'http://localhost:3000';
function returnMainWindow()
{
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
//preload: __dirname + '/preload.tsx'
}
});
//const env = process.env.NODE_ENV;
//console.log("Environment: " + env);
const isDev = require('electron-is-dev');
windowUrlBase = "";
console.log("Not electron dev");
console.log("dir name: " + __dirname);
const startUrl = process.env.ELECTRON_START_URL || url.format({
//pathname: path.join(__dirname, '/../build/index.html'),
pathname: path.join(__dirname, '../index.html'),
protocol: 'file:',
slashes: true,
webSecurity: false
});
mainWindow.loadURL(startUrl);
return mainWindow;
}
function createWindow() {
// Create the browser window.
mainWindow = returnMainWindow();
mainWindow.maximize();
// and load the index.html of the app.
// Open the DevTools.
//mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
setMainMenu();
}
function setMainMenu()
{
const template = [
{
label: 'File',
submenu: [
{
label: 'Exit',
accelerator: "ctrl+f4",
click() {
app.quit();
}
}
]
},
{
label: 'Edit',
submenu: [
{
label: 'Settings',
click() {
mainWindow.loadURL(windowUrlBase + "/settings");
}
}
]
},
{
label: 'Help',
submenu: [
{
label: 'Show Dev Console',
accelerator: "f11",
click() {
mainWindow.webContents.openDevTools();
}
}
]
}
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
});
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
});
Run Code Online (Sandbox Code Playgroud)
我的创建安装程序脚本如下
const createWindowsInstaller = require('electron-winstaller').createWindowsInstaller
const path = require('path')
getInstallerConfig()
.then(createWindowsInstaller)
.catch((error) => {
console.error(error.message || error)
process.exit(1)
})
function getInstallerConfig () {
console.log('creating windows installer')
const rootPath = path.join('./')
const outPath = path.join(rootPath, 'release-builds')
return Promise.resolve({
appDirectory: path.join(outPath, 'crash-catch-control-panel-win32-x64'),
authors: 'Boardies IT Solutions',
noMsi: true,
outputDirectory: path.join(outPath, 'windows-installer'),
exe: 'crash-catch-control-panel.exe',
setupExe: 'crash-catch-control-panel-installer.exe'
//setupIcon: path.join(rootPath, 'assets', 'images', 'logo.ico')
})
}
Run Code Online (Sandbox Code Playgroud)
我的 setupEvents.js 在下面
const electron = require('electron')
const app = electron.app
module.exports = {
handleSquirrelEvent: function() {
if (process.argv.length === 1) {
return false;
}
const ChildProcess = require('child_process');
const path = require('path');
const appFolder = path.resolve(process.execPath, '..');
const rootAtomFolder = path.resolve(appFolder, '..');
const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
const exeName = path.basename(process.execPath);
const spawn = function(command, args) {
let spawnedProcess, error;
try {
spawnedProcess = ChildProcess.spawn(command, args, {detached: true});
} catch (error) {}
return spawnedProcess;
};
const spawnUpdate = function(args) {
return spawn(updateDotExe, args);
};
const squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case '--squirrel-install':
case '--squirrel-updated':
// Optionally do things such as:
// - Add your .exe to the PATH
// - Write to the registry for things like file associations and
// explorer context menus
// Install desktop and start menu shortcuts
spawnUpdate(['--createShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-uninstall':
// Undo anything you did in the --squirrel-install and
// --squirrel-updated handlers
// Remove desktop and start menu shortcuts
spawnUpdate(['--removeShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-obsolete':
// This is called on the outgoing version of your app before
// we update to the new version - it's the opposite of
// --squirrel-updated
app.quit();
return true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的 App.js 在下面
import * as React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom'
import './Stylesheet.css'
import Dashboard from "./Components/Dashboard";
import Settings from "./Components/Settings";
import './ComponentStyles/BreadcrumbNav.css'
import 'react-toastify/dist/ReactToastify.min.css';
import { ToastContainer, toast } from 'react-toastify';
import CustomerDetails from "./Components/CustomerDetails";
toast.configure({
position: 'top-center',
hideProgressBar: true
});
function App() {
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/" render={() => <Dashboard /> } exact />
<Route path="/customer-information/:customer_id" render={(props) => <CustomerDetails {...props} /> } exact />
<Route path="/settings" render={() => <Settings /> } exact />
</Switch>
</div>
</BrowserRouter>
);
}
export default App;
Run Code Online (Sandbox Code Playgroud)
当我在应用程序加载时查看 chrome 控制台时,我看到以下错误:
不允许加载本地资源:file:///C:/Users/Chris/AppData/Local/MyApp/app-0.1.2/resources/app.asar/index.html
如上所述,只有当我安装了电子应用程序时才会启动该问题。如果我将它作为 Node 开发服务器的一部分启动,那么它工作得很好。
更新
以下目录结构按要求
components 目录包含实际的 ReactJS 组件,目录 ComponentStyles 是所有单独的组件样式表。组件是打字稿,因此采用 tsx 格式。
经过大量的尝试和错误,我终于让它工作了。
第一件事是更改我的 App.js,这样我现在不再使用 BrowserRouter,而是使用 HashRouter,如下所示,并使用react-router-dom 中的历史记录
import {HashRouter, useHistory} from "react-router-dom";
const history = createBrowserHistory();
<HashRouter basename="/" history={history} >
<Switch>
<Route path="/" exact component={Dashboard} />
<Route path="/customer-information/:customer_id" component={CustomerDetails} />
<Route path="/settings" component={Settings} />
<Route path="*" component={NotFound} />
</Switch>
</HashRouter>
Run Code Online (Sandbox Code Playgroud)
然后在每个组件中,当我想更改位置时,我会执行以下操作:
const history = useHistory();
history.push('/newlocation');
Run Code Online (Sandbox Code Playgroud)
当我加载浏览器窗口时,我现在有以下内容:
mainWindow.loadURL(isDev ? windowUrlBase : `file://${__dirname}/../build/index.html`);
Run Code Online (Sandbox Code Playgroud)
并删除了以下块
const startUrl = process.env.ELECTRON_START_URL || url.format({
//pathname: path.join(__dirname, '/../build/index.html'),
pathname: path.join(__dirname, '../index.html'),
protocol: 'file:',
slashes: true,
webSecurity: false
});
Run Code Online (Sandbox Code Playgroud)
isDev 使用以下内容设置:
const isDev = require('electron-is-dev');
Run Code Online (Sandbox Code Playgroud)
对于设置菜单更改使用 IPC 的位置,使用以下命令:
在 Electron-start.js 中
const { ipcMain } = require("electron");
submenu: [
{
label: 'Settings',
click() {
//mainWindow.loadURL(windowUrlBase + "/settings");
//history.push('/settings')
//location.pathname = "/settings";
//ipcMain.send("change-location", "/settings");
mainWindow.webContents.send('change-location', '/settings')
//mainWindow.location.pathname = "/settings";
}
}
]
Run Code Online (Sandbox Code Playgroud)
然后在整个项目共享的组件中,我有以下内容来接收 IPC 事件
const {ipcRenderer} = window.require('electron')
const history = useHistory();
useEffect(() => {
ipcRenderer.on('change-location', (event, arg) => {
history.push(arg);
});
})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
433 次 |
| 最近记录: |