dennis_10-33
dennis_10-33

Reputation: 49

Electron-app can't find prisma after building an exe

I'm facing the next issue after completing my program and trying to make an executable.

I've started the project directly with electron:

npx create-electron-app@latest my-app --template=webpack

And added into this project the other dependencies: Vue, TailwindCSS and Prisma.

On dev everthing work as it should but after I issued the npm run make Prisma isn't working anymore. I got the message

Cannot find module './prisma/client

There are some solutions for this on the internet, adding this part somewhere:

  '**/*', 
  'node_modules/@prisma/client/**/*',  
  'node_modules/.prisma/**/*', 

But I'm not sure where to add these lines. I tried to add them into my packag.json under a "build"-part, also tried to add them into the froge.config.js. But nothing worked - now the app don't even start anymore...

Hope someone here can help me.

Here is my package.json:

{
  "name": "invoice-manager",
  "productName": "Invoice Manager",
  "version": "1.0.0",
  "description": "",
  "main": ".vite/build/main.js",
  "scripts": {
    "start": "electron-forge start",
    "package": "electron-forge package",
    "make": "electron-forge make",
    "publish": "electron-forge publish",
    "lint": "echo \"No linting configured\""
  },
  "devDependencies": {
    "@electron-forge/cli": "^7.6.1",
    "@electron-forge/maker-deb": "^7.6.1",
    "@electron-forge/maker-rpm": "^7.6.1",
    "@electron-forge/maker-squirrel": "^7.6.1",
    "@electron-forge/maker-zip": "^7.6.1",
    "@electron-forge/plugin-auto-unpack-natives": "^7.6.1",
    "@electron-forge/plugin-fuses": "^7.6.1",
    "@electron-forge/plugin-vite": "^7.6.1",
    "@electron/fuses": "^1.8.0",
    "@vitejs/plugin-vue": "^5.2.1",
    "autoprefixer": "^10.4.20",
    "electron": "34.1.1",
    "postcss": "^8.5.2",
    "prisma": "^6.3.1",
    "tailwindcss": "^3.4.17",
    "vite": "^5.4.14"
  },
  "keywords": [],
  "author": {
    "name": "Dennis"
  },
  "license": "MIT",
  "dependencies": {
    "@aws-sdk/client-s3": "^3.744.0",
    "@aws-sdk/lib-storage": "^3.744.0",
    "@prisma/client": "^6.3.1",
    "prisma": "^6.3.1",
    "angular-expressions": "^1.4.3",
    "docxtemplater": "^3.60.0",
    "dotenv": "^16.4.7",
    "electron-squirrel-startup": "^1.0.1",
    "electron-store": "^10.0.1",
    "flowbite": "^3.1.2",
    "flowbite-vue": "^0.1.7",
    "pinia": "^2.3.1",
    "pizzip": "^3.1.8",
    "vue": "^3.5.13",
    "vue-router": "^4.5.0"
  }
}

And here the forge.config.json:

const { FusesPlugin } = require('@electron-forge/plugin-fuses');
const { FuseV1Options, FuseVersion } = require('@electron/fuses');

module.exports = {
  packagerConfig: {
    asar: false,
  },
  rebuildConfig: {},
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {},
    },
    {
      name: '@electron-forge/maker-zip',
      platforms: ['darwin'],
    },
    {
      name: '@electron-forge/maker-deb',
      config: {},
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {},
    },
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-vite',
      config: {
        // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
        // If you are familiar with Vite configuration, it will look really familiar.
        build: [
          {
            // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
            entry: 'src/main.js',
            config: 'vite.main.config.mjs',
            target: 'main',
          },
          {
            entry: 'src/preload.js',
            config: 'vite.preload.config.mjs',
            target: 'preload',
          },
        ],
        renderer: [
          {
            name: 'main_window',
            config: 'vite.renderer.config.mjs',
          },
        ],
      },
    },
    // Fuses are used to enable/disable various Electron functionality
    // at package time, before code signing the application
    new FusesPlugin({
      version: FuseVersion.V1,
      [FuseV1Options.RunAsNode]: false,
      [FuseV1Options.EnableCookieEncryption]: true,
      [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
      [FuseV1Options.EnableNodeCliInspectArguments]: false,
      [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
      [FuseV1Options.OnlyLoadAppFromAsar]: true,
    }),
  ],
};

Everything except the asar: false is like it came from the inital npx-command.

And here my prisma.scheme:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

Whats the issue, can you have any idea ? Thanks a lot in advance!

Upvotes: 1

Views: 39

Answers (1)

Zenovak
Zenovak

Reputation: 45

Hello I had my fair share of headaches with this before as there are no official guides to do this specifically with electron-forge. I have the same versions of dependencies as yours. So here's what I did to get it working in prod and dev:

  1. In forge.config.js you need to declare your prisma files, and the generated prisma clients from the .node modules. This ensures that the production build will specifically copy all your prisma files to the out/myproject/resources folder.
 packagerConfig: {
    asar: true,
    // prisma extra resources must be declared here
    extraResource: [
      "./prisma/app.db",
      "./node_modules/.prisma",
      "./node_modules/@prisma"
    ]
  }

In my approach I decided to include the dev database, so I dont have to do another headache of configuring how to run npm exec prisma migrate dev during installs on the client

  1. In webpack.rules.js add your prisma to the exclude rule. This will prevent webpack from packaging your prisma files and creating a new db inside .webpack/ when you are in dev mode during npm run start
{
    test: /[/\\]node_modules[/\\].+\.(m?js|node)$/,
    parser: { amd: false },
    // https://github.com/prisma/prisma/issues/12627
    // fix for prisma with electron
    exclude: /\.prisma/,
    use: {
      loader: '@vercel/webpack-asset-relocator-loader',
      options: {
        outputAssetBase: 'native_modules',
      },
    },
  },
  1. when creating your prisma client, be sure to check and use the db file located in userData during production, here's what I did for my helper
import { PrismaClient } from '@prisma/client';

const { app } = require('electron')
const { join } = require('path');
const fs = require('fs')
const path = require('path')
export const isDev = process.env.NODE_ENV === "development";


const dbPath = isDev ? "./app.db" : path.join(app.getPath("userData"), "app.db");


if (!isDev) {
    try {
        // database file does not exist, need to create
        fs.copyFileSync(join(process.resourcesPath, 'app.db'), dbPath, fs.constants.COPYFILE_EXCL);
        console.log("New database file created")
    } catch (err) {
        if (err.code != "EEXIST") {
            console.error(`Failed creating sqlite file.`, err);
        } else {
            console.log("Database file detected");
        }
    }
}


export const prisma = new PrismaClient({
    log: ['info', 'warn', 'error',
        //     {
        //     emit: "event",
        //     level: "query",
        // },
    ],
    datasources: {
        db: {
            url: `file:${dbPath}`,
        },
    },
});


console.log(`Is Production?: ${!isDev}`)

My references:

How to add extra resources files in production in electron using electron-forge

https://github.com/TasinIshmam/prisma-electron-test/blob/master/package.json

https://github.com/prisma/prisma/issues/12627

Upvotes: 0

Related Questions