Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Чтение и запись файлов

Чтобы заметки не пропадали после перезапуска, их нужно записать на диск. Файлы читает и пишет главный процесс — с помощью модуля node:fs/promises из Node.js. Осталось решить, куда класть файл: для этого у Electron есть метод app.getPath.

Папка данных программы

app.getPath('userData') возвращает папку, которую система выделяет программе под её данные:

СистемаПуть
WindowsC:\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').

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.