Using Local Files for Persistent Data Storage
Generally, user personalized data is not stored in the application installation directory because the installation directory is unreliable. Application upgrades or reinstallations may cause the installation directory to be emptied, resulting in the loss of user data. Fortunately, the operating system provides a dedicated directory for applications to store personalized data: C:\Users\username\AppData\Roaming.
In Electron, you can use app.getPath to obtain different paths by passing in different parameters. The corresponding parameter descriptions are as follows:
home: The user's home folder (home directory).appData: Each user's application data directory. By default, it points to:%APPDATA%(in Windows).$XDG_CONFIG_HOME or ~/.config(in Linux).~/Library/Application Support(in macOS).
userData: The folder for storing your application configuration files. By default, it is theappDatafolder with the application name appended. According to the habit, user storage data files should be written in this directory. At the same time, it is not recommended to write large files here because some environments will back up this directory to cloud storage.sessionData: This directory stores data generated by the Session, such aslocalStorage,cookies, disk caching, downloaded dictionaries, network status, and developer tool files. By default, it is theuserDatadirectory. Chromium may write very large disk caching here. Therefore, if your application does not rely on browser storage (such aslocalStorageorcookie) to save user data, it is recommended to set this directory to other locations to avoid polluting theuserDatadirectory.temp: Temporary folder.exe: The current executable file.module: The libchromiumcontent library.desktop: The current user's desktop folder.documents: The path of the user's document directory.downloads: The path of the user's download directory.music: The path of the user's music directory.pictures: The path of the user's picture directory.videos: The path of the user's video directory.recent: The directory of the user's recent files (only in Windows).logs: The application's log folder.crashDumps: The directory where crash dump files are stored.
Lowdb
lowdb is a lightweight local JSON database.
- Installing dependencies:
 
pnpm i lowdb
          - Basic usage:
 
<script setup lang="ts">import { JSONFilePreset } from "lowdb/node";import { resolve } from "path";function resolvePath(fileName: string) {  return resolve(app.getPath("userData"), fileName);}type User = {  id: number;  username: string;  age: number;  userType: string;  email: string;  sort: number;};type Data = {  users: User[];};// Basic usageasync function main() {  // Initialize default data  const defaultData: Data = { users: [] };  // Create or read data  const db = await JSONFilePreset(resolvePath("db.json"), defaultData);  // Create user object  const user = { id: 1, username: "kunkun", age: 18, userType: "user", email: "kunkun@qq.com", sort: 10 };  // Write data  db.data.users.push(user);  await db.write();  // Equivalent to  await db.update(({ users }) => {    users.push(user);  });}main();</script>
          After executing the above command, a db.json file will be generated in the app.getPath('userData') directory with the following content:
{  "users": [    {      "id": 1,      "username": "kunkun",      "age": 18,      "userType": "user",      "email": "kunkun@qq.com",      "sort": 10    }  ]}
          - Extending Lowdb
 
Using lodash to extend lowdb
pnpm i lodash
          <script setup lang="ts">import { Low } from "lowdb";import lodash from "lodash";// lodash.chain: Create a lodash object that can be chained.class LowWithLodash<T> extends Low<T> {  chain: lodash.ExpChain<this["data"]> = lodash.chain(this).get("data");}</script>
          - Basic usage (after extension):
 
<script setup lang="ts">import { LowSync } from "lowdb";import { JSONFileSync, JSONFileSyncPreset } from "lowdb/node";import { resolve } from "path";import lodash from "lodash";function resolvePath(fileName: string) {  return resolve(app.getPath("userData"), fileName);}type User = {  id: number;  username: string;  age: number;  userType: string;  email: string;  sort: number;};type Data = {  users: User[];};// Using lodash to extend lowdbclass LowWithLodash<T> extends LowSync<T> {  // lodash.chain: Create a lodash object that can be chained.  chain: lodash.ExpChain<this["data"]> = lodash.chain(this).get("data");}// Initialize default dataconst defaultData: Data = { users: [] };// Create an adapterconst adapter = new JSONFileSync<Data>(resolvePath("db.json"));// Instantiateconst db = new LowWithLodash(adapter, defaultData);// Read the filedb.read();// Add datafunction addUser(user: Omit<User, "id">) {  let id = db.data.users.length + 1;  db.chain    .get("users")    .push({ id, ...user })    .value();  db.write();}addUser({ username: "kunkun", age: 18, userType: "user", email: "kunkun@qq.com", sort: 10 });addUser({ username: "唔西迪西", age: 20, userType: "admin", email: "wuxidxi@qq.com", sort: 12 });// Delete datafunction delUser(id: number) {  db.chain.get("users").remove({ id: id }).value();  db.write();}// Clear datafunction clearUser() {  db.chain.set("users", []).value();  db.write();}// Modify datafunction updateUser(id: number, user: Partial<Omit<User, "id">>) {  db.chain.get("users").find({ id: id }).assign(user).value();  db.write();}updateUser(1, { username: "坤坤", userType: "admin" });// Query data// Query data by idconst user = db.chain.get("users").find({ id: 1 }).value();// Query the last dataconst lastUser = db.chain.get("users").last().value();// Query the total number of usersconst total = db.chain.get("users").size().value();// Get the top 10 dataconst topTenList = db.chain.get("users").sortBy("sort").take(10).value();function getUser(id: number) {  return db.chain.get("users").find({ id }).value();}// Query all datafunction getUserList() {  return db.chain.get("users").value();}</script>
          Data Encryption
<script setup lang="ts">import { LowSync } from "lowdb";import { DataFileSync, JSONFileSync, JSONFileSyncPreset } from "lowdb/node";import { resolve } from "path";import lodash from "lodash";import crypto from "crypto";function resolvePath(fileName: string) {  return resolve(app.getPath("userData"), fileName);}type User = {  id: number;  username: string;  age: number;  userType: string;  email: string;  sort: number;};type Data = {  users: User[];};// Algorithmconst algorithm = "aes-256-cbc";// Secret keyconst key = crypto.scryptSync("secret", "salt", 32);// Initialization vectorconst iv = Buffer.alloc(16, 6);// Encrypt datafunction encrypt(data: string) {  // Create encryption object  const cipher = crypto.createCipheriv(algorithm, key, iv);  // Encrypt data  let encrypted = cipher.update(data, "utf8");  // End encryption  encrypted = Buffer.concat([encrypted, cipher.final()]);  // Generate hexadecimal ciphertext  let result = encrypted.toString("hex");  return result;}// Decryptfunction decrypt(text: string) {  // Create decryption object  const decipher = crypto.createDecipheriv(algorithm, key, iv);  // Decrypt  let decrypted = decipher.update(text, "hex");  // End decryption  decrypted = Buffer.concat([decrypted, decipher.final()]);  let result = decrypted.toString();  return result;}// Default dataconst defaultData: Data = { users: [] };// Create adapterconst adapter = new DataFileSync<Data>(resolvePath("db.json"), {  parse: (data) => {    return JSON.parse(decrypt(data));  },  stringify: (data) => {    return encrypt(JSON.stringify(data));  },});const db = new LowSync(adapter, defaultData);db.read();// Add data and encrypt automaticallyfunction addUser(user: Omit<User, "id">) {  let id = db.data.users.length + 1;  db.data.users.push({ id, ...user });  db.write();}addUser({ username: "kunkun", age: 18, userType: "user", email: "kunkun@qq.com", sort: 10 });// Get data and decrypt automaticallyfunction getUserById(id: number) {  return db.data.users.find((item) => item.id === id);}let user = getUser(1);console.log(user);</script>
          Electron Store
Electron Store is simple data persistence for your Electron app or module - Save and load user preferences, app state, cache, etc
- Installing dependencies:
 
pnpm i electron-store
          - Configuring the environment (background.ts):
 
import Store from "electron-store";// InitializeStore.initRenderer();
          - Configuring the environment (vite.config.ts):
 
import { defineConfig } from "vite";import vue from "@vitejs/plugin-vue";import electron from "vite-plugin-electron";import renderer from "vite-plugin-electron-renderer";// https://vitejs.dev/config/export default defineConfig({  plugins: [    vue(),    electron({      entry: "src/background.ts",      onstart: (options) => {        options.startup();      },    }),    // Use electron api in the rendering process    renderer({      resolve: {        "electron-store": { type: "esm" },      },    }),  ],});
          - Basic usage:
 
<script setup lang="ts">import Store from "electron-store";const store = new Store();store.set("name", "kunkun");console.log(store.get("name"));</script>
          After the above test, a config.json file will be generated in the app.getPath('userData') path with the following content:
{  "name": "kunkun"}
          - Other operations:
 
<script setup lang="ts">import Store from "electron-store";type User = {  id: number;  username: string;  age: number;  userType: string;  email: string;  sort: number;};type Data = {  users: User[];};// The generated path is: app.getPath('userData')/db/db.jsonconst store = new Store<Data>({  // Folder name  cwd: "db",  // File name  name: "db",  // Default value  defaults: { users: [] },});// Get valuelet users = store.get("users");let username = store.get("users[0].username");let data = store.store;// Set valuestore.set("users", [  ...users,  { id: users.length + 1, username: "kunkun", age: 18, userType: "user", email: "kunkun@qq.com", sort: 10 },]);// Open the storage file in the editorstore.openInEditor();// The path of the storage filelet path = store.path;// Delete the users fieldstore.delete("users");// Delete all values and reset to default valuesstore.clear();</script>
          - Data encryption
 
When instantiating store, add the encryptionKey property and specify the secret key. Electron-store will use the aes-256-cbc encryption algorithm to encrypt the storage area.
const store = new Store<Data>({  // Folder name  cwd: "db",  // File name  name: "db",  // Default value  defaults: { users: [] },  // Data encryption  encryptionKey: "secret",});
          Sqlite
SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine.
- Installing dependencies:
 
pnpm i sqlite3pnpm i fs-extra
          - Configuring the environment (vite.config.ts):
 
import { defineConfig } from "vite";import vue from "@vitejs/plugin-vue";import electron from "vite-plugin-electron";import renderer from "vite-plugin-electron-renderer";// https://vitejs.dev/config/export default defineConfig({  plugins: [    vue(),    electron({      entry: "src/background.ts",      onstart: (options) => {        options.startup();      },    }),    // Use electron api in the rendering process    renderer({      resolve: {        "electron-store": { type: "esm" },        sqlite3: { type: "cjs" },        "fs-extra": { type: "esm" },      },    }),  ],});
          - Basic usage:
 
<script setup lang="ts">  import * as sqlite3 from 'sqlite3'  import { resolve } from 'path'  import { app } from '@electron/remote'  import fs from 'fs-extra'  function resolvePath(dir: string, fileName: string) {    return resolve(app.getPath('userData'), dir, fileName)  }  // Connect to the database  // Execute the verbose function to facilitate debugging code. If there is an error in the code, it will be located to the specific code.  const sqlite = sqlite3.verbose()  // Specify the file path  let dbPath = resolvePath('db','db.db')  // Specify that if the file does not exist, create it. If it exists, do not perform any operations.  fs.ensureFileSync(dbPath)  // Initialize the database and specify the database storage path and the database operation mode as the sketch mode.  const db = new sqlite.Database(dbPath, sqlite.OPEN_READWRITE, (err) => {    if (err) return console.log(err)    console.log('Database connection successful')  })  // db.run(sql,params?,callback?)  // Execute SQL statements other than queries, such as creating tables, inserting, updating and deleting.  // Create user table  db.run(    `CREATE TABLE IF NOT EXISTS user (      id 				INTEGER 			NOT NULL		PRIMARY KEY AUTOINCREMENT,      username 	CHAR ( 45 ) 	NOT NULL,      age       INT						NOT NULL,      userType 	CHAR ( 45 ) 	NOT NULL 		DEFAULT 'user',      email     CHAR ( 45 )		NOT NULL  	UNIQUE,      sort 		 	INT 					NOT NULL 		DEFAULT  10      )`,    (err) => {      if (err) return console.log(err)      console.log('Create user table success')    }  )