Skip to content

Instantly share code, notes, and snippets.

@ppulwey
Last active January 17, 2022 13:13
Show Gist options
  • Save ppulwey/e9c5d9b1e61a1b01006b46775bf61af6 to your computer and use it in GitHub Desktop.
Save ppulwey/e9c5d9b1e61a1b01006b46775bf61af6 to your computer and use it in GitHub Desktop.
How to get an React Electron app with local DB (NEDB)

How to get an React Electron app with local DB (NEDB)

  • Create app with yarn create electron-app my-new-app --template=typescript-webpack
  • Install node packaged
    • ajv
    • nedb-promises
    • react
    • react-dom

src > Database > Schemas > SchemaName.ts

import { JSONSchemaType } from "ajv";

export interface Talk {
  number: string;
  title: string;
}

const TalkSchema: JSONSchemaType<Talk> = {
  type: "object",
  properties: {
    number: {
      type: "string",
    },
    title: {
      type: "string",
    },
  },
  required: ["number", "title"],
  additionalProperties: false,
};

export default TalkSchema;

src > Database > Stores > StoreName.ts

import Datastore from "nedb-promises";
import Ajv, { ValidateFunction } from "ajv";

import TalkSchema, { Talk } from "../Schemas/Talk";

const dbPath = `${process.cwd()}/talks.db`;
const db = Datastore.create({
  filename: dbPath,
  timestampData: true,
});
const ajv = new Ajv({
  allErrors: true,
  useDefaults: true,
});

const validator = ajv.compile(TalkSchema);

const talkStoreInstance = {
  validate: (data: Talk) => {
    return validator(data);
  },
  readAll: () => {
    return db.find({}).exec();
  },
  create: (data: Talk) => {
    const isValid = validator(data);
    if (isValid) {
      return db.insert(data);
    } else {
      console.error(`Schema not valid`, data);
    }
  },
  // ... more methods
};

export { talkStoreInstance };

src > index.ts

const mainWindow = new BrowserWindow({
    height: 600,
    width: 800,
    webPreferences: {
      nodeIntegration: true,
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
    },
  });

src > preload.js

import { contextBridge } from "electron";
import { talkStoreInstance } from "./Database/Stores/TalkStore";

contextBridge.exposeInMainWorld("db", {
  talks: talkStoreInstance,
});

src > renderer.js

// The whole file needs only this when using React
import "./index.tsx";

src > index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

package.json > config > forge > plugins > renderer > entryPoints

[
  {
    "html": "./src/index.html",
    "js": "./src/renderer.ts",
    "name": "main_window",
    "preload": {
      "js": "./src/preload.js"
    }
  }
]

src > types.d.ts

import { Talk } from "./Database/Schemas/Talk";

export type DB = {
  talks: {
    readAll:() => Promise<Talk[]>;
    create:(data:Talk) => Promise<Talk>;
  } ;
};

declare global {
  interface Window {
    db: DB;
  }
}

In Modules / Pages use as

const readTalks = async () => {
  const result = await window.db.talks.readAll();

  console.log(`All Talks`, result);
};

const addTalk = async () => {
  const talk: Talk = {
    number: "001",
    title: "Asdf",
  };

  await window.db.talks.create(talk);

  readTalks();
};

Use your normal React Setup

index.tsx

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";

import { BrowserRouter } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment