Electron 下使用 Prisma 的 SQL

Posted

技术标签:

【中文标题】Electron 下使用 Prisma 的 SQL【英文标题】:SQL with Prisma under Electron 【发布时间】:2021-11-03 09:35:13 【问题描述】:

我的主要目标是创建一个电子应用程序 (Windows),将数据本地存储在 SQLite 数据库中。由于类型安全,我选择使用Prisma framework 而不是其他 SQLite 框架。 我接受了this Electron Sample Project,现在尝试加入 Prisma。根据我尝试的不同,确实会出现不同的问题。

1。 PrismaClient 无法在浏览器中运行

我执行了npx prisma generate,然后尝试通过一个按钮执行这个函数:

  import  PrismaClient  from '@prisma/client';

  onSqlTestAction(): void 
    const prisma = new PrismaClient();
    const newTestObject = prisma.testTable.create(
      
        data: 
          value: "TestValue"
        
      
    );

  

在 Electron 中执行此操作时,我得到以下信息:

core.js:6456 ERROR Error: PrismaClient is unable to be run in the browser.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
    at new PrismaClient (index-browser.js:93)
    at HomeComponent.onSqlTestAction (home.component.ts:19)
    at HomeComponent_Template_button_click_7_listener (template.html:7)
    at executeListenerWithErrorHandling (core.js:15281)
    at wrapListenerIn_markDirtyAndPreventDefault (core.js:15319)
    at HTMLButtonElement.<anonymous> (platform-browser.js:568)
    at ZoneDelegate.invokeTask (zone.js:406)
    at Object.onInvokeTask (core.js:28666)
    at ZoneDelegate.invokeTask (zone.js:405)
    at Zone.runTask (zone.js:178)

Prisma 不能在浏览器中运行似乎是合乎逻辑的。但我实际上构建了一个原生应用程序 - 使用嵌入浏览器的 Electron。这似乎是一个漏洞。

2。重大变化:webpack

所以我发现了这个问题:How to use Prisma with Electron 似乎正是我所寻找的。但错误信息不同(未找到 Debian 二进制文件)。 提供的解决方案是将 prisma 工件生成到 src 文件夹而不是 node_modules - 这会导致 19 个 polyfill 错误。一个例子:

./src/database/generated/index.js:20:11-26 - Error: Module not found: Error: Can't resolve 'path' in '[PATH_TO_MY_PROJECT]\src\database\generated'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback:  "path": require.resolve("path-browserify") '
        - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback:  "path": false 

这与其他 18 个模块重复。由于开始的错误消息不同,我也怀疑这是要走的路。

【问题讨论】:

【参考方案1】:

我终于想通了。我需要了解的是,所有 Electron 应用程序都由两部分组成:前端 Web 应用程序(在嵌入式 Chromium 中运行)和 Node 后端服务器。这两个部分分别称为IPC Main 和IPC Renderer,它们可以相互通信。而且由于 Prisma 只能在作为后端的主进程上运行,我必须将我的 SQL 操作发送到 Electron 后端并在那里执行它们。

我的最小例子

在前端(我使用 Angular)

// This refers to the node_modules folder of the Electron Backend, the folder where the main.ts file is located.
// I just use this import so that I can use the prisma generated classes for type safety.

import  TestTable  from '../../../app/node_modules/.prisma/client';

  // Button action
  onSqlTestAction(): void 
    this.electronService.ipcRenderer.invoke("prisma-channel", 'Test input').then((value) => 
      const testObject: TestTable = JSON.parse(value);
      console.log(testObject);
    );

我使用的示例项目已经有这个服务来提供 IPC Renderer:

@Injectable(
  providedIn: 'root'
)
export class ElectronService 
  ipcRenderer: typeof ipcRenderer;
  webFrame: typeof webFrame;
  remote: typeof remote;
  childProcess: typeof childProcess;
  fs: typeof fs;

  get isElectron(): boolean 
    return !!(window && window.process && window.process.type);
  

  constructor() 
    // Conditional imports
    if (this.isElectron) 
      this.ipcRenderer = window.require('electron').ipcRenderer;
      this.webFrame = window.require('electron').webFrame;

      this.childProcess = window.require('child_process');
      this.fs = window.require('fs');

      // If you want to use a NodeJS 3rd party deps in Renderer process (like @electron/remote),
      // it must be declared in dependencies of both package.json (in root and app folders)
      // If you want to use remote object in renderer process, please set enableRemoteModule to true in main.ts
      this.remote = window.require('@electron/remote');
    
  

然后在 Electron 后端,我首先将 "@prisma/client": "^3.0.1" 添加到 package.json(用于 Electron 后端而不是前端)。然后我在main.ts中添加了这个函数来处理来自渲染器的请求:

// main.ts
ipcMain.handle("prisma-channel", async (event, args) => 

  const prisma = new PrismaClient();
  await prisma.testTable.create(
    
      data: 
        value: args
      
    
  );

  const readValue = await prisma.testTable.findMany();
  return JSON.stringify(readValue);
)

这种在main.ts 文件中简单地添加IPC Main 处理程序的方式当然是一个很大的代码味道,但作为最小示例很有用。我想我会继续使用this article 中提出的架构概念。

【讨论】:

以上是关于Electron 下使用 Prisma 的 SQL的主要内容,如果未能解决你的问题,请参考以下文章

使用 GraphQL、Nexus 和 Prisma 优化 SQL 查询

Prisma Client 在电子打包所有内容后找不到查询引擎

带条件的 Prisma 查询

如何使用 Prisma 编写等效的 SQL MERGE 语句?

如何使用 Prisma 为 Postgres 进行 SQL 插入,条件是行数?

在使用 Prisma 的选择查询中使用 _count