Чтение и запись файлов
Чтобы заметки не пропадали после перезапуска, их нужно записать на диск. Файлы читает и пишет главный процесс — с помощью модуля node:fs/promises из Node.js. Осталось решить, куда класть файл: для этого у Electron есть метод app.getPath.
Папка данных программы
app.getPath('userData') возвращает папку, которую система выделяет программе под её данные:
| Система | Путь |
|---|---|
| Windows | C:\Users\Anna\AppData\Roaming\notes |
| macOS | ~/Library/Application Support/notes |
| Linux | ~/.config/notes |
Последняя часть пути — поле name из package.json (или productName, если оно задано). Папка создаётся автоматически.
Путь к файлу
Добавьте в начало main.js:
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('node:path');
const fs = require('node:fs/promises');
function notesFile() {
return path.join(app.getPath('userData'), 'notes.json');
}getPath работает только после готовности программы, поэтому путь вычисляется функцией в момент вызова, а не при запуске файла.
Чтение
// main.js
async function loadNotes() {
try {
const json = await fs.readFile(notesFile(), 'utf8');
return JSON.parse(json);
} catch (error) {
if (error.code === 'ENOENT') {
return [];
}
throw error;
}
}При первом запуске файла ещё нет — readFile выбросит ошибку с кодом ENOENT, и функция вернёт пустой список. Остальные ошибки пробрасываются дальше.
Запись
// main.js
async function saveNotes(notes) {
await fs.writeFile(notesFile(), JSON.stringify(notes, null, 2), 'utf8');
}JSON.stringify с отступом 2 делает файл удобным для чтения человеком.
Обработчики IPC
Подключите функции к каналам из урока об IPC:
// main.js
app.whenReady().then(() => {
ipcMain.handle('notes:load', () => loadNotes());
ipcMain.handle('notes:save', (event, notes) => saveNotes(notes));
createWindow();
});// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('notes', {
load: () => ipcRenderer.invoke('notes:load'),
save: (notes) => ipcRenderer.invoke('notes:save', notes),
});Обработчик может вернуть промис — invoke на странице дождётся его.
На странице
// renderer.js
let notes = [];
form.addEventListener('submit', async (event) => {
event.preventDefault();
notes.push(text.value);
await window.notes.save(notes);
text.value = '';
render();
});
window.notes.load().then((saved) => {
notes = saved;
render();
});Функция render выводит массив notes в список, как showNotes в прошлом уроке. Добавьте пару заметок и перезапустите программу — они на месте. Файл notes.json можно открыть в папке данных программы.
Частая ошибка
Нельзя сохранять данные рядом с кодом через path.join(__dirname, 'notes.json'). Во время разработки это работает, но в собранной программе код лежит внутри архива app.asar или в папке Program Files, куда писать нельзя. Пользовательские данные всегда храните в app.getPath('userData').