Sqlite 如何从电子前端进行数据库调用?

Sqlite 如何从电子前端进行数据库调用?,sqlite,electron,svelte,Sqlite,Electron,Svelte,(这里是全新的学习电子,所以我确信这是一个基本问题,我遗漏了一些基本的东西…) 如何从电子应用程序前端与本地数据库(我正在使用Sqlite)交互?我有一个非常基本的数据库管理器类,在我的电子应用程序的index.js文件中使用它没有问题。但是从前端(我使用的是Svelte,但我可能可以翻译来自其他前端框架的解决方案),如何与数据库交互?这似乎很基本,但我正在努力寻找一个基本的例子 因为所有东西都是本地的,所以似乎不需要设置一个完整的API来来回封送数据,但也许是这样?但是如果是这样的话,如何告诉

(这里是全新的学习电子,所以我确信这是一个基本问题,我遗漏了一些基本的东西…)

如何从电子应用程序前端与本地数据库(我正在使用Sqlite)交互?我有一个非常基本的数据库管理器类,在我的电子应用程序的
index.js
文件中使用它没有问题。但是从前端(我使用的是Svelte,但我可能可以翻译来自其他前端框架的解决方案),如何与数据库交互?这似乎很基本,但我正在努力寻找一个基本的例子

因为所有东西都是本地的,所以似乎不需要设置一个完整的API来来回封送数据,但也许是这样?但是如果是这样的话,如何告诉电子“后端”(如果这是正确的术语)做一些事情并将结果返回到前端?我看到了一些关于IPC的东西,但现在这没有多大意义,似乎有点过头了

下面是我的简单数据库管理器类:

const sqlite3 = require("sqlite3").verbose();

class DbManager {
  #db;
  open() {
    this.#db = new sqlite3.Database("testing.db", sqlite3.OPEN_READWRITE);
  }
  close() {
    this.#db.close();
  }
  run(sql, param) {
    this.#db.run(sql, param);
    return this;
  }
}

const manager = new DbManager();
module.exports = manager;
我可以调用它,从Electron入口点
index.js
执行任何没有问题的操作:

const { app, BrowserWindow, screen } = require("electron");
require("electron-reload")(__dirname);
const db = require("./src/repository/db");

const createWindow = () => {
   ...
};

let window = null;

app.whenReady().then(() => {
  db.open();
  createWindow();
});

app.on("window-all-closed", () => {
  db.close();
  app.quit();
});
但是我的组件应该怎么做呢

<script>
  // this won't work, and I wouldn't expect it to, but not sure what the alternative is
  const db = require("./repository/db");  
  let accountName;
  function addAccount() {
    db.run("INSERT INTO accounts (name) VALUES ($name);", { $name: accountName });
  }
</script>

<main>
  <form>
    <label for="account_name">Account name</label>
    <input id="account_name" bind:value={accountName} />
    <button on:click={addAccount}>Add account</button>
  </form>
</main>

//这是行不通的,我也不希望这样,但不确定还有什么替代方案
const db=require(“./repository/db”);
让帐户名;
函数addAccount(){
run(“插入帐户(名称)值($name);”,{$name:accountName});
}
帐户名
添加帐户

如果有人知道样板实现可以做类似的事情,那将非常有用。显然,这就像这里的应用程序101;我只是不知道如何在Electron中实现这一点,希望有人能给我指出正确的方向。

如果你绝对100%确定你的应用程序不会访问任何远程资源,那么你可以通过预加载脚本公开
require
以及任何你可能需要的内容,只需编写
const nodeRequire=require;window.require=noderrequire


这是一个相当广泛的话题,需要一些阅读。我将尝试为您提供入门知识并链接一些资源

Electron运行在两个(如果打开多个窗口,则运行更多)进程上—主进程和渲染器进程。主进程处理诸如打开新窗口、启动和关闭整个应用程序、托盘图标、窗口可见性等,而渲染器进程基本上类似于浏览器中的JS代码

默认情况下,渲染器进程无权访问节点运行时,但可以允许它访问。你可以用两种方法来做,但要注意很多

一种方法是在创建
浏览器窗口时设置
webPreferences.nodeIntegration=true
(注意:
nodeIntegration
。这允许您使用前端代码中的所有节点API,代码段也可以工作。但您可能不应该这样做,因为
BrowserWindow
能够加载外部URL,这些页面中包含的任何代码都可以在您或您用户的计算机上执行任意代码

另一种方法是使用预加载脚本。预加载脚本在渲染器进程中运行,但可以访问节点运行时以及浏览器的
窗口
对象(除非
节点集成
为true,否则在实际前端代码运行之前,节点全局将从作用域中删除)。您可以简单地设置
window.require=require
,基本上使用前端文件中的节点代码。但您可能也不应该这样做,即使您对公开的内容非常小心,因为仍然很容易留下漏洞,允许潜在攻击者利用某些公开的API进行完全访问

那么如何安全地做到这一点呢?将
webPreferences.contextIsolation
设置为
true
。这将明确地将预加载脚本上下文与渲染器上下文分离,而不是
nodeIntegration:false
导致的不可靠的节点API剥离,因此您几乎可以确保没有恶意代码具有完全访问权限到节点

然后,您可以通过
contextBridge.exposeInMainWorld
从预加载向前端公开特定函数。例如:

contextBridge.exposeInMainWorld('Accounts'){
addAccount:async(accountData)=>{
//验证和清理。。。
const success=await db.run(“…”);
回归成功;
}
}
这将使用前端的
窗口中的指定方法安全地公开
帐户
对象。因此,您可以在组件中编写:

const accountAdded=await Accounts.addAccount({id:123,用户名:'foo'});
请注意,您仍然可以公开一个方法
runDbCommand(command){db.run(command)}
,甚至
evalInNode(code){eval(code)}
,这就是为什么我写了几乎所有的代码


你实际上不需要使用IPC来处理文件或数据库,因为这些API在预加载中可用。只有当你想从渲染器进程操作窗口或触发主进程上的任何其他内容时,才需要IPC。

如果你绝对100%确定你的应用程序不会访问任何远程资源然后您可以通过预加载脚本公开
require
以及您可能需要的任何内容,只需编写
const nodeRequire=require;window.require=nodeRequire;


这是一个相当广泛的主题,需要一些阅读。我将尝试为您提供入门知识并链接一些资源

Electron运行在两个(如果打开多个窗口,则运行更多)进程上—主进程和渲染器进程。主进程处理打开新窗口、启动和关闭整个应用程序、托盘图标、窗口可见性等,而渲染器进程基本上与中的JS代码类似