79445715

Date: 2025-02-17 14:33:17
Score: 0.5
Natty:
Report link

Finally found how to do it ! As Maneet pointed in their answer, better-sqlite3 wasn't packaged, and thus the required call would fail.

I found here and there mentions to packagerConfig.extraRessource property in forge.config.ts file, which will copy asked files outside the asar archive. However, I needed better-sqlite3 files to be inside the asar archive.

After an astronomic amount of research, I found the answer on this page. I had to adapt it a little, but it works fine. The idea is to use an Electron-forge hook to copy what we want in a temp file, before it gets archived int app.asar. This solution only requires changes on forge.config.ts file :

import type { ForgeConfig } from "@electron-forge/shared-types";
import { MakerSquirrel } from "@electron-forge/maker-squirrel";
import { VitePlugin } from "@electron-forge/plugin-vite";
import { FusesPlugin } from "@electron-forge/plugin-fuses";
import { FuseV1Options, FuseVersion } from "@electron/fuses";
import { resolve, join, dirname } from "path";
import { copy, mkdirs } from "fs-extra";

const config: ForgeConfig = {
    packagerConfig: {
        asar: true
    },
    rebuildConfig: {},
    hooks: {
        // The call to this hook is mandatory for better-sqlite3 to work once the app built
        async packageAfterCopy(_forgeConfig, buildPath) {
            const requiredNativePackages = ["better-sqlite3", "bindings", "file-uri-to-path"];

            // __dirname isn't accessible from here
            const dirnamePath: string = ".";
            const sourceNodeModulesPath = resolve(dirnamePath, "node_modules");
            const destNodeModulesPath = resolve(buildPath, "node_modules");

            // Copy all asked packages in /node_modules directory inside the asar archive
            await Promise.all(
                requiredNativePackages.map(async (packageName) => {
                    const sourcePath = join(sourceNodeModulesPath, packageName);
                    const destPath = join(destNodeModulesPath, packageName);

                    await mkdirs(dirname(destPath));
                    await copy(sourcePath, destPath, {
                        recursive: true,
                        preserveTimestamps: true
                    });
                })
            );
        }
    },
    makers: [new MakerSquirrel({})],
    plugins: [
        new VitePlugin({
            build: [
                {
                    entry: "src/main.ts",
                    config: "vite.config.ts",
                    target: "main"
                },
                {
                    entry: "src/preload.ts",
                    config: "vite.config.ts",
                    target: "preload"
                }
            ],
            renderer: [
                {
                    name: "main_window",
                    config: "vite.config.ts"
                }
            ]
        }),
        new FusesPlugin({
            version: FuseVersion.V1,
            [FuseV1Options.RunAsNode]: false,
            [FuseV1Options.EnableCookieEncryption]: true,
            [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
            [FuseV1Options.EnableNodeCliInspectArguments]: false,
            [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
            [FuseV1Options.OnlyLoadAppFromAsar]: true
        })
    ]
};

export default config;

For each string in requiredNativePackages list, the hook will look for a directory with the same name in node_modules, and copy this in a directory named node_modules inside the temp directory which will be turned into an archive right after. We need bindings and file-uri-to-path packages in top of better-sqlite3 because they're direct dependencies.

Reasons:
  • Blacklisted phrase (0.5): I need
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (1):
Posted by: HellNoki