add: auto update launcher

This commit is contained in:
2025-07-08 02:30:35 +05:00
parent 5cd483209f
commit 31a26dc1ce
11 changed files with 132 additions and 20 deletions

1
.cursorignore Normal file
View File

@ -0,0 +1 @@
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)

View File

@ -36,9 +36,15 @@ const configuration: webpack.Configuration = {
}, },
optimization: { optimization: {
minimize: false,
minimizer: [ minimizer: [
new TerserPlugin({ new TerserPlugin({
parallel: true, parallel: true,
terserOptions: {
ecma: 2020,
keep_classnames: true,
keep_fnames: true,
},
}), }),
], ],
}, },

1
.gitignore vendored
View File

@ -27,3 +27,4 @@ npm-debug.log.*
*.css.d.ts *.css.d.ts
*.sass.d.ts *.sass.d.ts
*.scss.d.ts *.scss.d.ts
.env

View File

@ -18,7 +18,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/electron-react-boilerplate/electron-react-boilerplate.git" "url": "git+https://git.popa-popa.ru/DIKER/popa-launcher.git"
}, },
"license": "MIT", "license": "MIT",
"author": { "author": {
@ -42,14 +42,15 @@
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && npm run build:dll", "postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && npm run build:dll",
"lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx", "lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx --fix", "lint:fix": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx --fix",
"package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never && npm run build:dll", "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish always && npm run build:dll",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app", "rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
"prestart": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true NODE_OPTIONS=\"-r ts-node/register --no-warnings\" webpack --config ./.erb/configs/webpack.config.main.dev.ts", "prestart": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true NODE_OPTIONS=\"-r ts-node/register --no-warnings\" webpack --config ./.erb/configs/webpack.config.main.dev.ts",
"start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run prestart && npm run start:renderer", "start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run prestart && npm run start:renderer",
"start:main": "concurrently -k -P \"cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --watch --config ./.erb/configs/webpack.config.main.dev.ts\" \"electronmon . -- {@}\" --", "start:main": "concurrently -k -P \"cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --watch --config ./.erb/configs/webpack.config.main.dev.ts\" \"electronmon . -- {@}\" --",
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true NODE_OPTIONS=\"-r ts-node/register --no-warnings\" webpack --config ./.erb/configs/webpack.config.preload.dev.ts", "start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true NODE_OPTIONS=\"-r ts-node/register --no-warnings\" webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true NODE_OPTIONS=\"-r ts-node/register --no-warnings\" webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts", "start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true NODE_OPTIONS=\"-r ts-node/register --no-warnings\" webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
"test": "jest" "test": "jest",
"publish-debug": "electron-builder build --publish always"
}, },
"browserslist": [ "browserslist": [
"extends browserslist-config-erb" "extends browserslist-config-erb"
@ -190,7 +191,7 @@
"webpack-merge": "^6.0.1" "webpack-merge": "^6.0.1"
}, },
"build": { "build": {
"productName": "ElectronReact", "productName": "popa-launcher",
"appId": "org.erb.ElectronReact", "appId": "org.erb.ElectronReact",
"asar": true, "asar": true,
"afterSign": ".erb/scripts/notarize.js", "afterSign": ".erb/scripts/notarize.js",
@ -249,9 +250,12 @@
"./assets/**" "./assets/**"
], ],
"publish": { "publish": {
"provider": "github", "provider": "generic",
"owner": "electron-react-boilerplate", "url": "https://git.popa-popa.ru/DIKER/popa-launcher/releases/download/v${version}",
"repo": "electron-react-boilerplate" "channel": "latest",
"requestHeaders": {
"Authorization": "token ${env.GH_TOKEN}"
}
} }
}, },
"collective": { "collective": {

View File

@ -1,12 +1,12 @@
{ {
"name": "electron-react-boilerplate", "name": "popa-launcher",
"version": "4.6.0", "version": "1.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "electron-react-boilerplate", "name": "popa-launcher",
"version": "4.6.0", "version": "1.0.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT" "license": "MIT"
} }

View File

@ -1,12 +1,12 @@
{ {
"name": "electron-react-boilerplate", "name": "popa-launcher",
"version": "4.6.0", "version": "1.0.0",
"description": "A foundation for scalable desktop apps", "description": "Popa Launcher",
"license": "MIT", "license": "MIT",
"author": { "author": {
"name": "Electron React Boilerplate Maintainers", "name": "DIKER",
"email": "electronreactboilerplate@gmail.com", "email": "diker0k@gmail.com",
"url": "https://github.com/electron-react-boilerplate" "url": "https://github.com/DIKER0K"
}, },
"main": "./dist/main/main.js", "main": "./dist/main/main.js",
"scripts": { "scripts": {

View File

@ -25,7 +25,36 @@ class AppUpdater {
constructor() { constructor() {
log.transports.file.level = 'info'; log.transports.file.level = 'info';
autoUpdater.logger = log; autoUpdater.logger = log;
const server = 'https://git.popa-popa.ru/DIKER/popa-launcher';
// Для Gitea нужно указать конкретную структуру URL
// Обратите внимание на использование пути /download/
autoUpdater.setFeedURL({
provider: 'generic',
url: `${server}/releases/download/latest`, // Укажите конкретную версию
channel: 'latest',
});
// Проверка обновлений
autoUpdater.checkForUpdatesAndNotify(); autoUpdater.checkForUpdatesAndNotify();
// Периодическая проверка обновлений (каждый час)
setInterval(
() => {
autoUpdater.checkForUpdatesAndNotify();
},
60 * 60 * 1000,
);
// Обработчики событий обновления
autoUpdater.on('update-downloaded', () => {
log.info('Обновление загружено. Будет установлено при перезапуске.');
// Можно отправить событие в renderer для уведомления пользователя
if (mainWindow) {
mainWindow.webContents.send('update-available');
}
});
} }
} }
@ -160,3 +189,7 @@ app
}); });
}) })
.catch(console.log); .catch(console.log);
ipcMain.handle('install-update', () => {
autoUpdater.quitAndInstall();
});

View File

@ -9,7 +9,9 @@ export type Channels =
| 'close-app' | 'close-app'
| 'minimize-app' | 'minimize-app'
| 'save-pack-config' | 'save-pack-config'
| 'load-pack-config'; | 'load-pack-config'
| 'update-available'
| 'install-update';
const electronHandler = { const electronHandler = {
ipcRenderer: { ipcRenderer: {
@ -28,7 +30,7 @@ const electronHandler = {
once(channel: Channels, func: (...args: unknown[]) => void) { once(channel: Channels, func: (...args: unknown[]) => void) {
ipcRenderer.once(channel, (_event, ...args) => func(...args)); ipcRenderer.once(channel, (_event, ...args) => func(...args));
}, },
invoke(channel: string, ...args: unknown[]) { invoke(channel: Channels, ...args: unknown[]): Promise<any> {
return ipcRenderer.invoke(channel, ...args); return ipcRenderer.invoke(channel, ...args);
}, },
}, },

View File

@ -11,6 +11,7 @@ import './App.css';
import TopBar from './components/TopBar'; import TopBar from './components/TopBar';
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import MinecraftBackround from './components/MinecraftBackround'; import MinecraftBackround from './components/MinecraftBackround';
import { Notifier } from './components/Notifier';
// Переместите launchOptions сюда, вне компонентов // Переместите launchOptions сюда, вне компонентов
const launchOptions = { const launchOptions = {
@ -94,6 +95,7 @@ const App = () => {
> >
<MinecraftBackround /> <MinecraftBackround />
<TopBar onRegister={handleRegister} /> <TopBar onRegister={handleRegister} />
<Notifier />
<Routes> <Routes>
<Route path="/login" element={<Login />} /> <Route path="/login" element={<Login />} />
<Route <Route

View File

@ -0,0 +1,63 @@
import { Alert, Box, Snackbar, Button } from '@mui/material';
import { useEffect, useState } from 'react';
export const Notifier = () => {
const [open, setOpen] = useState(false);
const [message, setMessage] = useState('');
const [severity, setSeverity] = useState<
'error' | 'warning' | 'info' | 'success'
>('info');
const [hasUpdateAvailable, setHasUpdateAvailable] = useState(false);
useEffect(() => {
// Слушаем событие о наличии обновления
window.electron.ipcRenderer.on('update-available', () => {
setMessage('Доступно новое обновление');
setSeverity('info');
setHasUpdateAvailable(true);
setOpen(true);
});
return () => {
// Отписываемся от события при размонтировании
window.electron.ipcRenderer.removeAllListeners('update-available');
};
}, []);
const handleClose = () => {
setOpen(false);
};
const handleUpdate = () => {
window.electron.ipcRenderer.invoke('install-update');
setOpen(false);
};
return (
<Box>
<Snackbar
open={open}
autoHideDuration={hasUpdateAvailable ? null : 6000}
onClose={handleClose}
>
<Alert
severity={severity}
action={
hasUpdateAvailable && (
<>
<Button color="primary" size="small" onClick={handleUpdate}>
Обновить сейчас
</Button>
<Button color="secondary" size="small" onClick={handleClose}>
Позже
</Button>
</>
)
}
>
{message}
</Alert>
</Snackbar>
</Box>
);
};

View File

@ -6,7 +6,7 @@
http-equiv="Content-Security-Policy" http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline'" content="script-src 'self' 'unsafe-inline'"
/> />
<title>Hello Electron React!</title> <title>popa-launcher</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>