添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Electron is a great framework to build cross-platform applications. With Electron, we can easily build the desktop application by using web techniques.

Using Electron can let us easily create cross-platform applications on top of web technologies. Since Electron app is still kind of web app, when talking about storing data, we are used to storing the data in remote servers via sending HTTP requests.

What if I want to store the data locally?

In this article, I will share my experience in building an Electron application with persistent local data storage.

  • Browser localStorage: Electron is built on Chromium, that is browser localStorage is well supported.
  • electron-store : For simple scenarios, just go for electron-store. The API is easy to use

    Considering storing your data in the SQL or NoSQL like database would be a better idea when use cases are a bit complicated.

    After doing some researches and leveraging between SQL and NoSQL with Electron, I end up going to NoSQL solution.

    I am going to introduce the way to integrate nedb with your Electron app.

    As NeDB doc said, NeDB is

    Embedded persistent or in memory database for Node.js, nw.js, Electron and browsers, 100% JavaScript, no binary dependency. API is a subset of MongoDB's and it's plenty fast.

    I am significantly pleasure using NeDB to build my production-ready product.

    To help you understand the idea quickly, let's use electron-quick-start template and have the quick experience

    Follow the installation instruction:

    # Clone this repository
    $ git clone https://github.com/electron/electron-quick-start
    # Go into the repository
    $ cd electron-quick-start
    # Install dependencies
    $ npm install
    # Run the app
    $ npm start
        Enter fullscreen mode
        Exit fullscreen mode
    

    Create a db folder. Then, create schemas and stores folder under db.

    The repo should look like:
    ├── LICENSE.md ├── README.md ├── db │   ├── schemas │   └── stores ├── index.html ├── main.js ├── package-lock.json ├── package.json ├── preload.js └── renderer.js Enter fullscreen mode Exit fullscreen mode

    nedb-promises is a wrapper around nedb. With promise can save you tons of time to handle the callback.

    $ yarn add nedb-promises
        Enter fullscreen mode
        Exit fullscreen mode
    

    ajv is a JSON schema validator library. Schema validator is optional to build the NoSQL database, but I'd recommend using it since well-defined schema and validator can bring better maintainability.

    NIT: You can also replace ajv to your preference schema validator

    $ yarn add ajv
        Enter fullscreen mode
        Exit fullscreen mode
    

    Let's destruct the component of a todo list app.

    A todo list app should have a list of todo item. A simple todo item would include todo content, is it finished?

    The schema will be:

    db/schemas/todoItem.js

    const todoItemSchema = {
      type: 'object',
      properties: {
        content: {
          type: 'string',
        isDone: {
          type: 'boolean',
          default: false
    module.exports = todoItemSchema;
        Enter fullscreen mode
        Exit fullscreen mode
    

    The store will contain the interface to Create / Update / Delete the NeDB.

    Main thread will import this store and Renderer thread will call these methods.

    First, init the NeDB, validator in the constructor

    db/stores/todoItem.js

    const Datastore = require('nedb-promises');
    const Ajv = require('ajv');
    const todoItemSchema = require('../schemas/todoItem');
    class TodoItemStore {
        constructor() {
            const ajv = new Ajv({
                allErrors: true,
                useDefaults: true
            this.schemaValidator = ajv.compile(todoItemSchema);
            const dbPath = `${process.cwd()}/todolist.db`;
            this.db = Datastore.create({
                filename: dbPath,
                timestampData: true,
        Enter fullscreen mode
        Exit fullscreen mode
    
    const Datastore = require('nedb-promises');
    const Ajv = require('ajv');
    const todoItemSchema = require('../schemas/todoItem');
    class TodoItemStore {
        constructor() {
            const ajv = new Ajv({
                allErrors: true,
                useDefaults: true
            this.schemaValidator = ajv.compile(todoItemSchema);
            const dbPath = `${process.cwd()}/todolist.db`;
            this.db = Datastore.create({
                filename: dbPath,
                timestampData: true,
        validate(data) {
            return this.schemaValidator(data);
        create(data) {
            const isValid = this.validate(data);
            if (isValid) {
                return this.db.insert(data);
        read(_id) {
            return this.db.findOne({_id}).exec()
        readAll() {
            return this.db.find()
        readActive() {
            return this.db.find({isDone: false}).exec();
        archive({_id}) {
            return this.db.update({_id}, {$set: {isDone: true}})
    module.exports = new TodoItemStore();
        Enter fullscreen mode
        Exit fullscreen mode
    

    Since the goal of the article is sharing the way to integrate NeDB with Electron, I won't elaborate the API of NeDB too much. You can get the idea first and spend some time to go through the NeDB afterwards.

    Worth noticing, we init the class when exporting the module. This tactic help you to keep one Store instance across the application.

    Since this is a simple example, there is only one store. In real-world cases, you can use the same structure to extend the application.

    Integrate everything

    So far, we've finished all works for controlling the database. The repo should look like:
    ├── LICENSE.md ├── README.md ├── db │   ├── schemas │   │   └── todoItem.js │   └── stores │   └── todoItem.js ├── index.html ├── main.js ├── package.json ├── preload.js ├── renderer.js └── yarn.lock Enter fullscreen mode Exit fullscreen mode

    // Modules to control application life and create native browser window
    const {app, BrowserWindow} = require('electron')
    const path = require('path')
    const db = require('./db/stores/todoItem');
    global.db = db;
    function createWindow () {
      // Create the browser window.
      const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
      mainWindow.loadFile('index.html')
    ...the same...
        Enter fullscreen mode
        Exit fullscreen mode
    

    So we can start to add the view logic. I will skip the explanation of the View layer, since there are many ways to do that.

    The final implementation

    Electron doesn't have the strict limitation of data flow. You can store the data in localStorage, or store the data in main thread and expose it to global. Or, you can also use electron-store for simple key-value storage.

    When the application grows bigger and bigger, the data flow will become harder to maintain. You may have a copy in localStorage, and if you are using client state management framework, like redux, client side will also have another copy.

    The data flow will become a mess without proper data flow.

    The demo is a simple case. In the real world case, you can add cache to improve the performance, or add more validation to secure the db access.

    Plus, NeDB always stores the data in a text file, so it's straightforward to realize data import/export.

    There is a new package to store data in electron as JSON files. The beautiful thing about this package is that it allows you to encrypt your data and you can store different kinds of data each one with its file and also there no API to get and set the data. You can manipulate your data with vanilla Javascript, also your data is watched which means the data will be written to a JSON file in every change

    Read more:

    npmjs.com/package/electron-data-ho...

    Built on Forem — the open source software that powers DEV and other inclusive communities.

    Made with love and Ruby on Rails. DEV Community © 2016 - 2024.