11 KiB
Пошаговый гайд: как “поднять” существующий Angular-проект из ui/
внутри нового Electron-проекта desktop-angular/
(без копирования собранного кода)
Ниже — практичный сценарий: вы создаёте папку desktop-angular/
с каркасом Electron, подключаете туда исходники Angular (те, что уже лежат в ui/
), настраиваете общий запуск в dev-режиме и сборку prod-пакета. Никаких переносов уже собранных файлов, всё работает от исходников Angular.
Что получится в итоге
- Dev-режим: одновременно запускается
ng serve
изui/
и Electron, который открываетhttp://localhost:4200
. - Prod-режим: сначала билдится Angular в
ui/dist/...
, затем Electron упаковывает приложение и грузитindex.html
из собранного Angular.
1) Создаём новый проект desktop-angular/
для Electron
- В корне репозитория создайте папку
desktop-angular/
:
mkdir /home/su/projects/articles/embed-gui-article/desktop-angular
cd /home/su/projects/articles/embed-gui-article/desktop-angular
npm init -y
- Устанавливаем зависимости Electron и утилиты для дев-сценария:
npm i -D electron electron-builder concurrently wait-on cross-env
Рекомендуемая структура (минимум):
desktop-angular/package.json
— скрипты для dev/prod.desktop-angular/src/main/main.js
— основной процесс Electron.desktop-angular/src/preload/preload.js
— безопасный мост.- (Без
renderer/
— рендерером будет ваш Angular изui/
.)
Создайте папки и файлы:
mkdir -p src/main src/preload
touch src/main/main.js src/preload/preload.js
2) Подключаемся к уже существующему Angular-проекту в ui/
Предполагаем, что Angular уже установлен и запускается из /home/su/projects/articles/embed-gui-article/ui/
стандартными командами:
- Dev:
npm start
(илиng serve
) - Build:
npm run build
Если нет npm start
, добавьте его в ui/package.json
:
{
"scripts": {
"start": "ng serve --port 4200 --disable-host-check",
"build": "ng build"
}
}
3) Код main.js
для Electron (dev: URL, prod: файл из dist)
Создайте простой BrowserWindow
, который:
- в dev грузит
http://localhost:4200
- в prod грузит файл
../ui/dist/project-front/browser/index.html
Обратите внимание на относительные пути: мы опираемся на реальную структуру вашего репо и текущие выходные пути Angular (ui/dist/project-front/browser
у вас уже есть).
// desktop-angular/src/main/main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
const isDev = process.env.NODE_ENV !== 'production';
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
show: false,
webPreferences: {
preload: path.join(__dirname, '../preload/preload.js'),
contextIsolation: true,
nodeIntegration: false,
sandbox: true
}
});
win.on('ready-to-show', () => win.show());
if (isDev) {
win.loadURL('http://localhost:4200');
// win.webContents.openDevTools(); // включите по желанию
} else {
// В PROD грузим из собранного Angular
const indexPath = path.resolve(
__dirname,
'../../../ui/dist/project-front/browser/index.html'
);
win.loadFile(indexPath);
}
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
4) Код preload.js
(минимальная безопасная заготовка)
// desktop-angular/src/preload/preload.js
const { contextBridge } = require('electron');
contextBridge.exposeInMainWorld('env', {
isElectron: true
});
В Angular вы сможете проверять наличие window.env?.isElectron
.
5) Скрипты в desktop-angular/package.json
Добавим удобные команды:
dev
: параллельно запускает Angular dev-сервер вui/
и Electron (ждём порт 4200).build:ui
: сборка Angular.start
: старт Electron в prod-режиме (если нужно локально проверить загрузку собранного Angular без упаковки).dist
: упаковка Electron (electron-builder).
{
"name": "desktop-angular",
"version": "1.0.0",
"private": true,
"main": "src/main/main.js",
"scripts": {
"dev": "concurrently -k -n UI,ELECTRON -c green,cyan \"cd ../ui && npm start\" \"wait-on http://localhost:4200 && cross-env NODE_ENV=development electron .\"",
"build:ui": "cd ../ui && npm run build",
"start": "cross-env NODE_ENV=production electron .",
"dist": "npm run build:ui && cross-env NODE_ENV=production electron-builder"
},
"devDependencies": {
"concurrently": "^9.0.0",
"cross-env": "^7.0.3",
"electron": "^31.0.0",
"electron-builder": "^24.13.3",
"wait-on": "^7.2.0"
}
}
6) Конфигурация упаковки Electron (electron-builder)
Добавьте секцию build
в desktop-angular/package.json
. Мы не копируем Angular внутрь desktop-angular
— Electron будет брать собранный Angular прямо из ui/dist/...
при упаковке (через extraResources
). Это удобно и прозрачно.
{
"build": {
"appId": "com.yourcompany.knocker",
"productName": "Knocker Desktop Angular",
"files": [
"src/main/**/*",
"src/preload/**/*",
"package.json"
],
"extraResources": [
{
"from": "../ui/dist/project-front/browser",
"to": "ui-dist",
"filter": ["**/*"]
}
],
"linux": {
"target": ["AppImage"],
"category": "Utility",
"artifactName": "Knocker-Desktop-Angular-${version}.${ext}"
}
}
}
И соответствующее изменение в main.js
на prod, если хотите грузить из resources/ui-dist
у упакованного приложения:
- В упакованном
.AppImage
ваши ресурсы оказываются вprocess.resourcesPath
. - Тогда путь до
index.html
будет:path.join(process.resourcesPath, 'ui-dist', 'index.html')
.
Адаптированный prod-фрагмент:
// ... в main.js, в ветке !isDev:
const indexPath = app.isPackaged
? path.join(process.resourcesPath, 'ui-dist', 'index.html')
: path.resolve(__dirname, '../../../ui/dist/project-front/browser/index.html');
win.loadFile(indexPath);
Так вы покроете оба случая: локальный prod-запуск и реальный упакованный билд.
7) CORS, безопасность и доступ к файлам
- В dev Angular грузится по
http://localhost:4200
— обычно проблем нет. - В prod Angular грузится с
file://
— убедитесь, что никакие запросы не завязаны на абсолютные HTTP-URL без необходимости. - По умолчанию оставляем
contextIsolation: true
,nodeIntegration: false
,sandbox: true
. Для доступа к нативному коду используйте IPC иpreload.js
.
8) Локальный запуск dev
cd /home/su/projects/articles/embed-gui-article/desktop-angular
npm run dev
- Скрипт поднимет
ng serve
изui/
и откроет Electron, который загрузитhttp://localhost:4200
.
9) Локальная проверка prod без упаковки
# Собираем Angular
cd /home/su/projects/articles/embed-gui-article/ui
npm run build
# Запускаем Electron в prod-режиме
cd /home/su/projects/articles/embed-gui-article/desktop-angular
npm run start
10) Упаковка приложения
cd /home/su/projects/articles/embed-gui-article/desktop-angular
npm run dist
- Angular соберётся.
- Electron-упаковщик положит содержимое
ui/dist/project-front/browser
вresources/ui-dist
. - Приложение загрузит
index.html
изresources/ui-dist
.
11) Советы по интеграции Angular и Electron
- Детект среды в Angular:
// пример: app.component.ts
isElectron = typeof (window as any).env?.isElectron === 'boolean';
- Статические пути: В Angular используйте относительные пути к ассетам, чтобы они работали и в
http://localhost:4200
, и вfile://
в prod. - IPC: если потребуется обмен с main-процессом, расширяйте
preload.js
и опишите чёткий API черезcontextBridge
.
12) Итоговая структура (ключевые узлы)
ui/
— как есть, исходники Angular.desktop-angular/
package.json
— скриптыdev
,build:ui
,start
,dist
, секцияbuild
(electron-builder).src/main/main.js
— создаёт окно, грузит URL в dev и файл в prod.src/preload/preload.js
— мост в рендерер.
- Ничего из
ui/
внутрьdesktop-angular/
мы не копируем; работаем поверх исходников.
Что делать, если вы хотите переиспользовать текущую папку desktop/
?
Можно; у вас уже есть desktop/
с Electron. Тогда:
- Либо перенести логику оттуда в
desktop-angular/
(описано выше). - Либо в существующем
desktop/
заменить рендерер на Angular изui/
по тем же принципам: dev —loadURL('http://localhost:4200')
, prod —loadFile(...)
наui/dist/...
.