Как открыть HTML‑файл внутри app.asar в Electron
Узнайте, почему shell.openPath не открывает файлы внутри app.asar и как открыть HTML‑файл в браузере по умолчанию – во временную папку или используя протокол.
Как открыть HTML‑файл, упакованный в архив app.asar Electron‑приложения, через shell.openPath?
Я проверил существование файла с помощью
fs.existsSync('D:\Project\release\1.47.3\win-unpacked\resources\app.asar\dist\doc\index.html')
но вызов
shell.openPath('<path>')
не работает в Windows и выдаёт ошибку «cannot find the file», потому что ОС не может получить доступ к файловой системе asar.
Я хочу открыть файл в браузере по умолчанию, не копируя его в app.asar.unpacked. Как правильно открыть HTML‑файл, находящийся внутри app.asar?
Путь, который вы передаёте в shell.openPath, должен указывать на реальный файл, который ОС может прочитать.
app.asar – это просто один бинарный архив; ОС не рассматривает его как дерево каталогов, поэтому любой путь, указывающий внутрь архива, будет отклонён с ошибкой «не удаётся найти файл».
Из‑за этого ограничения «волшебного» способа вызвать shell.openPath с файлом внутри app.asar нет. На практике работают два привычных подхода:
| Цель | Что можно сделать |
|---|---|
| Открыть файл в браузере по умолчанию | Скопировать файл во временную папку (или в app.asar.unpacked) и открыть реальный путь через shell.openExternal('file://…'). |
| Серверить файл из приложения без извлечения | Зарегистрировать собственный протокол (например, app://), который читает файл из архива, и открыть URL через shell.openExternal. |
Ниже – конкретные примеры для обоих вариантов.
1. Скопировать в временный файл и открыть его
// main.js (main process)
const { app, shell } = require('electron');
const path = require('path');
const fs = require('fs');
const os = require('os');
const { v4: uuidv4 } = require('uuid'); // npm i uuid
/**
* Copy an HTML file that lives inside app.asar to a temp folder
* and open it in the default browser.
*/
function openDocInBrowser() {
// Where the file lives inside the asar
const asarPath = path.join(process.resourcesPath, 'app.asar', 'dist', 'doc', 'index.html');
// Create a temporary directory
const tmpDir = path.join(os.tmpdir(), 'my-electron-app-docs');
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
// Destination path inside the temp directory
const tmpFile = path.join(tmpDir, `index-${uuidv4()}.html`);
// Copy the file out of the archive
fs.copyFileSync(asarPath, tmpFile);
// Open the temporary file in the default browser
shell.openExternal(`file://${tmpFile}`);
}
// Call it at the appropriate time
app.whenReady().then(openDocInBrowser);
Почему это работает
fs.copyFileSyncдействительно работает, потому что API Nodefsв Electron патчится так, чтобы читать файлы из архива asar.- Операция копирования создаёт реальный файл на диске.
shell.openExternal('file://…')передаёт абсолютный путь Windows, которая открывает его в браузере по умолчанию.
2. Показать файл через собственный протокол
Если хочется избежать записи на диск, можно открыть файл через собственный протокол и открыть URL.
// main.js
const { app, protocol, BrowserWindow, shell } = require('electron');
const path = require('path');
const fs = require('fs');
function createWindow () {
const win = new BrowserWindow({ show: false });
// Register a custom protocol that reads files from the asar archive
protocol.registerFileProtocol('app', (request, callback) => {
const url = request.url.substr(6); // strip 'app://'
const filePath = path.join(process.resourcesPath, 'app.asar', url);
callback({ path: filePath });
});
// Open the file using the custom protocol
shell.openExternal('app://dist/doc/index.html');
}
app.whenReady().then(createWindow);
Пояснение
protocol.registerFileProtocolговорит Electron, что URL, начинающиеся сapp://, – это запросы к файлам внутри архива asar.- Callback преобразует URL в реальный путь внутри
app.asar, который Electron может прочитать. shell.openExternal('app://…')передаёт URL ОС; ОС откроет его в браузере, потому что схема URL распознаётся как ресурс, похожий на файл.
Итог
shell.openPathне может открыть файл внутриapp.asar– ОС не читает файловую систему архива.- Практичные решения:
- Скопировать файл во временную папку (или в
app.asar.unpacked) и открыть его черезshell.openExternal('file://…'). - Показать файл через собственный протокол (
app://…) и открыть URL черезshell.openExternal.
- Скопировать файл во временную папку (или в
Выбирайте подход, который лучше вписывается в вашу стратегию развертывания: для быстрого «открыть в браузере» проще использовать временный файл; если нужно полностью избежать записи на диск, используйте собственный протокол.