You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I agree to follow the code of conduct that this project uses.
I have searched the issue tracker for a bug that matches the one I want to file, without success.
Forge version
7.11.1
Electron version
36.5.0
Operating system
window 11
Last known working Forge version
7.11.1
Expected behavior
The @electron-forge/plugin-auto-unpack-natives plugin should automatically unpack native modules like serialport and ensure they work properly within the Electron app.
Actual behavior
Despite configuring the @electron-forge/plugin-auto-unpack-natives plugin, the serialport native module is not being unpacked, causing it to fail to work correctly.
Steps to reproduce
Create a new Electron app using the command npx create-electron-app@latest my-app --template=vite-typescript.
Install and configure the @electron-forge/plugin-auto-unpack-natives plugin.
Install the serialport module and reference it in the project.
Run the app and check whether the serialport module is properly unpacked and working.
Try running the make command with DEBUG enabled, as there is likely a hidden issue.
PowerShell:
$env:DEBUG="electron-forge:*"; npm run make
CMD:
set DEBUG=electron-forge:* && npm run make
When building your Electron app on Windows, native modules require additional dependencies such as Visual Studio and Python in order to compile (in my case, the native module is better-sqlite3).
If Electron Forge is able to build the project successfully, I won’t need to manually mark the module as unpacked.
I also tested on Linux (where the required build dependencies are usually already installed), and it worked correctly.
Ideally, the best approach would be to avoid native modules altogether and use WASM-based solutions instead.
Please see my final configuration below.
import { FuseV1Options, FuseVersion } from "@electron/fuses";
import { MakerZIP } from "@electron-forge/maker-zip";
import AutoUnpackNativesPlugin from "@electron-forge/plugin-auto-unpack-natives";
import { FusesPlugin } from "@electron-forge/plugin-fuses";
import { VitePlugin } from "@electron-forge/plugin-vite";
import type { ForgeConfig } from "@electron-forge/shared-types";
import fs from "node:fs";
import path from "node:path";
/**
* Native modules to unpack
*/
const nativeModules = ["xmllint-wasm"];
function copyDir(src: string, dest: string): void {
try {
fs.mkdirSync(dest, { recursive: true });
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
const s = path.join(src, entry.name);
const d = path.join(dest, entry.name);
if (entry.isDirectory()) {
copyDir(s, d);
} else {
fs.copyFileSync(s, d);
}
}
} catch (error) {
console.error("Error copying directory:", src, dest, error);
throw error;
}
}
const config: ForgeConfig = {
packagerConfig: {
asar: true,
},
rebuildConfig: {
force: true,
},
hooks: {
//Mettre les assets dans le build asar file
packageAfterCopy: async (_config, buildPath) => {
// buildPath = dossier “app” qui sera ensuite asarisé
const src = path.resolve("src/main/assets");
const dest = path.join(buildPath, ".vite", "build", "assets");
copyDir(src, dest);
//Copy manually the native modules to the build directory
const sourceNodeModulesPath = path.resolve(__dirname, "node_modules");
const destNodeModulesPath = path.resolve(buildPath, "node_modules");
for (const module of nativeModules) {
const sourceModulePath = path.resolve(sourceNodeModulesPath, module);
const destModulePath = path.resolve(destNodeModulesPath, module);
console.log(
"Copying native module",
module,
"from",
sourceModulePath,
"to",
destModulePath
);
copyDir(sourceModulePath, destModulePath);
}
},
},
makers: [new MakerZIP({}, ["win32", "linux", "darwin"])],
plugins: [
//Unpack the natives to the build directory
new AutoUnpackNativesPlugin({}),
//Vite plugin to build the application
new VitePlugin({
// `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/main.ts",
config: "vite.main.config.ts",
target: "main",
},
{
entry: "src/preload/preload.ts",
config: "vite.preload.config.ts",
target: "preload",
},
],
renderer: [
{
name: "main_window",
config: "vite.renderer.config.ts",
},
],
}),
// Fuses are used to enable/disable various Electron functionality
// at package time, before code signing the application
new FusesPlugin({
version: FuseVersion.V1,
//Run the application as a node process
[FuseV1Options.RunAsNode]: false,
//Enable cookie encryption
[FuseV1Options.EnableCookieEncryption]: true,
//Enable node options environment variable
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
//Enable node cli inspect arguments
[FuseV1Options.EnableNodeCliInspectArguments]: false,
//Enable embedded asar integrity validation
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
//Only load the app from the asar file
[FuseV1Options.OnlyLoadAppFromAsar]: true,
}),
],
};
export default config;
Activity
SebastienBrun commentedon Mar 17, 2026
Try running the make command with DEBUG enabled, as there is likely a hidden issue.
PowerShell:
$env:DEBUG="electron-forge:*"; npm run makeCMD:
set DEBUG=electron-forge:* && npm run makeWhen building your Electron app on Windows, native modules require additional dependencies such as Visual Studio and Python in order to compile (in my case, the native module is better-sqlite3).
If Electron Forge is able to build the project successfully, I won’t need to manually mark the module as unpacked.
I also tested on Linux (where the required build dependencies are usually already installed), and it worked correctly.
Ideally, the best approach would be to avoid native modules altogether and use WASM-based solutions instead.
Please see my final configuration below.