mac m1 electron生产环境使用prisma,sqlite

最近在用electron开发一个适合自己的小应用,技术选型中使用prisma和sqlite在进行数据存储,写这篇文章的目的就是用来记录下遇到的一些问题。

开发环境使用prisma

1、开发环境使用prisma非常的简单,只需要按照教程安装prisma,然后执行npx prisma init --datasource-provider sqlite 即可。脚本会生成schema文件

在schema文件中编写自己的模型。

开发环境中执行

bash 复制代码
npx prisma migrate dev --name xxxx

可以看到在我们的prisma目录下会有个迁移文件夹migrations,里面会生成我们的sql。这时候我们可以直接使用@prisma/client

typescript 复制代码
import { PrismaClient } from '@prisma/client'
const prismaInstance = new PrismaClient()

可以用prismaInstance实例来进行数据库操作咯,这时候如果你使用的是ts并且安装了prisma的vs code插件你就会发现它的语法提示非常人性化,如果你之前有orm的基础就可以直接上手。

在生产环境中使用

一般情况下开发环境有nodejs环境,全局安装了prisma我们只需要把migrations文件夹拷贝到开发环境并且执行下面命令就行。

bash 复制代码
npx prisma migrate deploy

在electron中你使用electron-builder打包要怎么做才能正常使用prisma呢?

1、首先你得把migrations文件夹拷贝到安装包中,在package.json中使用extraResources来将我们所需要的migrations文件移入到安装包中。

js 复制代码
"build": {
    "extraResources": [
      {
        "from": "prisma/migrations",
        "to": "resources/prisma/migrations"
      },
      {
        "from": "prisma/schema.prisma",
        "to": "resources/prisma/schema.prisma"
      }
    ]
}

这样打包后如果你打开 join(process.resourcesPath,'resources/prisma')这个路径就会发现migrations文件夹已经被移入,然后我们要执行npx prisma migrate delploy,但是在我们的electron生产环境中没有npx命令该怎么做,这时候我们就需要使用prisma提供的二进制来进行操作了。

根据不同的环境prisma会提供不同的二进制,比如我这边是mac m1,那么你就要在schema.prisma中加入以下内容,prisma运行过程中就会去下载drawin-arm64的二进制

js 复制代码
generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native", "darwin-arm64"]
}

下载完你就会发现node_modules/@prisma/engines下会多出两个二进制文件

libquery是sql引擎,没有它就不能进行数据库操作。

schema就是我们刚才说的执行npx prisma migrate deploy的,可以理解为全局安装的prisma就是执行的这个二进制。

这样我们就可以直接使用二进制来执行我们的命令咯,前提是我们把二进制拷贝到了安装包内,你也可以使用extraResources属性,但我这边并没有写,因为electron一般会对文件都打包进asar二进制中,但是如果有些三方库的二进制打入二进制会出现一些意想不到的问题,所以可以在package.json设置asarUnpack,意味着不用吧这些文件进行二进制打包。

js 复制代码
"build":{
 "asarUnpack": [
      "**/node_modules/prisma/**/*",
      "**/node_modules/@prisma/**/*"
    ]
}

我们怎么拿到那些不需要被打包的二进制呢?我们代码中怎么写呢,路径是什么呢?代码如下

typescript 复制代码
const appUnpackedPath = app.getAppPath().replace('app.asar', 'app.asar.unpacked')
const schemePath = electronIsDev ? resolve(__dirname, '../node_modules/@prisma/engines/schema-engine-darwin-arm64') : resolve(appUnpackedPath, './node_modules/@prisma/engines/schema-engine-darwin-arm64')

上面是对开发环境进行了判断,读者可以自行处理,appUnkpackedPath就是我们的二进制存放路径。

我们可以开发编写一套统一的处理代码,这套也是我从github某篇issue上直接拿下来的。

typescript 复制代码
export async function runPrisma(command: string[]) {
  try {
    const exitCode = await new Promise((r, _) => {
      const prismaPath = resolve(electronIsDev ? resolve(__dirname, '../node_modules') : resolve(appUnpackedPath, './node_modules'), 'prisma', 'build', 'index.js')
      logger.info(process.cwd(), 'cwd')
      const child = fork(prismaPath, command, {
        cwd: electronIsDev ? process.cwd() : join(appUserPath, 'resources'),
        env: {
          ...process.env,
          DATABASE_URL: process.env.DATABASE_URL,
          PRISMA_QUERY_ENGINE_LIBRARY: queryPath,
          PRISMA_SCHEMA_ENGINE_BINARY: schemePath,
        },
        stdio: 'pipe',
      })

      child.on('message', (msg) => {
        logger.info(msg)
      })

      child.on('error', (err) => {
        logger.error('Child process got error:', err)
      })

      child.on('close', (code) => {
        logger.info(code)
        r(code)
      })

      child.stdout?.on('data', function (data) {
        // console.log(data)

        logger.info('prisma: ', data.toString())
      })

      child.stderr?.on('data', function (data) {
        logger.error('prisma: ', data.toString())
      })
    })

    if (exitCode !== 0) {
      throw Error(`command ${command} failed with exit code ${exitCode}`)
    }

    return exitCode
  } catch (e) {
    logger.error(e)
    throw e
  }
}

我们执行只需要传入参数进行即可

要注意我们的命令执行路径,也就是cwd参数要传入正确,要确保路径下面的文件内容格式符合prisma要求,prisma/migrations/xx类似这样即可

ts 复制代码
runPrisma(['migrate', 'deploy'])

上面代码中还有个queryPath,这个path是用来获取执行sql的引擎的,如果没有他我们就不能进行数据库操作,开发环境不需要我们指定引擎的二进制,但是在electron中需要我们来指定一下,有两种方法一种是使用环境变量process.env.PRISMA_QUERY_ENGINE_BINARY = queryPath,但是这种方法我这一直没成功,所以在github上找到了一种隐藏api方式来直接指定

ts 复制代码
const prismaInstance = new PrismaClient({
  __internal: {
    engine: {
      binaryPath: queryPath,
    },
  },
} as any)

这个__internal是一个非标准api,但是使用了发现能正常执行了。如果不指定就会一直报错
Can not spawn Query Engine when using Electron

结语

最后寻找感兴趣开发小工具的小伙伴一起来开发,目前我给这个产品取名Ew Box,Everything You Want,技术栈使用如下:

  • vite
  • electron
  • react,react-router
  • prisma
  • sqlite
  • tailwindcss
  • shadcn/ui
  • koa

对以上技术感兴趣,还有一些不错的idea的小伙伴都可以加入哟,后续可以使用你感兴趣的任何技术栈都可以集成其中

产品没有盈利目的,都是些简单的小功能点,做一款适合自己的小工具,就单纯想扩展或者提升技术面的小伙伴可以尝试加入哟

目前产品功能有压缩图片/密码箱/todo日历等功能,有想法的朋友可以一起加入哟。

相关推荐
Lei_zhen961 小时前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron
辣条小哥哥1 小时前
electron主进程和渲染进程之间的通信
javascript·electron·ecmascript
咖喱鱼蛋1 小时前
Electron一些概念理解
前端·javascript·electron
小江村儿的文杰10 小时前
XCode Build时遇到 .entitlements could not be opened 的问题
ide·macos·ue4·xcode
smilejingwei12 小时前
面向 Java 程序员的 SQLite 替代品
开发语言·sqlite·spl·esproc spl
天涯倦客的美丽人生12 小时前
2024年11月最新 Alfred 5 Powerpack (MACOS)下载
macos
SoraLuna12 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
总爱写点小BUG13 小时前
VM虚拟机装MAC后无法联网,如何解决?
macos
mariokkm19 小时前
Django一分钟:django中收集关联对象关联数据的方法
android·django·sqlite
Cod_Next19 小时前
Mac系统下配置 Tomcat 运行环境
java·macos·tomcat