alex8088 / electron-vite

Next generation Electron build tooling based on Vite 新一代 Electron 开发构建工具,支持源代码保护
https://electron-vite.org
MIT License
3.57k stars 153 forks source link

bytecodePlugin doesn't work with electron 27.0.0 (MacOS universal) #315

Open theogravity opened 1 year ago

theogravity commented 1 year ago

Describe the bug

Electron 27 just came out, and I seem to be having problems launching my built app when using the bytecode plugin

image

With electron 26, there are no issues.

My configuration looks like this:

// electron.vite.common.ts
import { externalizeDepsPlugin } from 'electron-vite';
import react from '@vitejs/plugin-react';

export const mainPlugins = [
  externalizeDepsPlugin({
    exclude: [
      '@nut-tree/nutjs',
      'node-mac-permissions',
    ],
  }),
];

export const mainRollupOptions = {
  external: ['node-mac-permissions', '@nut-tree/nutjs'],
};

export const preloadPlugins = [
  externalizeDepsPlugin({
    exclude: ['@monarch/electron-common'],
  }),
];

export const rendererPlugins = [react()];
// electron.vite.config.prod.ts
import { resolve } from 'path';
import { bytecodePlugin, defineConfig } from 'electron-vite';
import { mainPlugins, mainRollupOptions, preloadPlugins, rendererPlugins } from './electron.vite.common';

export default defineConfig({
  main: {
    plugins: mainPlugins.concat([bytecodePlugin()]),
    build: {
      rollupOptions: mainRollupOptions,
    },
  },
  preload: {
    plugins: preloadPlugins,
    build: {
      minify: true,
    },
  },
  renderer: {
    resolve: {
      alias: {
        '@renderer': resolve('src/renderer/src'),
      },
    },
    plugins: rendererPlugins,
    build: {
      minify: true,
    },
  },
});

Fuse configuration:

// ...
  await flipFuses(electronBinaryPath, {
    version: FuseVersion.V1,
    [FuseV1Options.EnableCookieEncryption]: true,
    resetAdHocDarwinSignature: electronPlatformName === 'darwin' && arch === builder.Arch.universal,
    [FuseV1Options.RunAsNode]: false,
    [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
    [FuseV1Options.EnableNodeCliInspectArguments]: false,
    [FuseV1Options.OnlyLoadAppFromAsar]: true,
    // Mac app crashes when enabled
    [FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: false,
    // electron-builder doesn't support: https://github.com/electron/fuses/issues/7
    [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false,
  });
// ...

For notarization, we use notarytool.

package.json file

  "dependencies": {
    "@babel/plugin-transform-arrow-functions": "7.22.5",
    "@electron-toolkit/preload": "1.0.3",
    "@electron-toolkit/utils": "1.0.2",
    "@electron/fuses": "1.6.2",
    "electron-dl": "3.5.1",
    "electron-log": "5.0.0-rc.1",
    "electron-unhandled": "4.0.1",
    "electron-updater": "5.3.0"
  },
  "devDependencies": {
    "@electron-toolkit/tsconfig": "1.0.1",
    "@electron/notarize": "2.1.0",
    "@types/node": "18.17.14",
    "@types/react": "18.0.28",
    "@types/react-dom": "18.0.11",
    "@vitejs/plugin-react": "3.1.0",
    "autoprefixer": "10.4.16",
    "electron": "27.0.0",
    "electron-builder": "24.7.0",
    "electron-router-dom": "1.0.5",
    "electron-store": "8.1.0",
    "electron-vite": "1.0.28",
    "loglayer": "2.1.0",
    "macos-version": "6.0.0",
    "pkce-challenge": "3.1.0",
    "postcss": "8.4.30",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-router-dom": "6.8.2",
    "typescript": "5.2.2",
    "vite": "4.4.11"
  },
  "optionalDependencies": {
    "node-mac-permissions": "2.3.0"
  },
  "resolutions": {
    "postcss": "8.4.31",
    "semver": "7.5.4",
    "xml2js": "0.5.0"
  }

Electron-Vite Version

1.0.28

Electron Version

27.0.0

Vite Version

4.4.11

Validations

theogravity commented 1 year ago

I see that you have committed https://github.com/alex8088/electron-vite/commit/ac47dacc1b3d7c09d4a825615dba5172e78b379f

Will you be publishing a new npm package soon?

Also, is this something that should be customizable by the user? It seems to be a potential maintenance issue when a new major electron version comes out. If a new version comes out, it'd be nice if I can manually specify the node and chrome version being used.

alex8088 commented 1 year ago

https://electron-vite.org/guide/troubleshooting.html#a-javascript-error-occurred-in-the-main-process-error-invaild-or-incompatible-cached-data-cacheddatarejected

theogravity commented 1 year ago

I wonder why it works no problem in 26 but not in 27 with the same config?

We haven't changed our build processes at all between 26 and 27.

We're also not manually specifying the electron version anywhere as your doc says could be an issue.

alex8088 commented 1 year ago

I wonder why it works no problem in 26 but not in 27 with the same config?

We haven't changed our build processes at all between 26 and 27.

We're also not manually specifying the electron version anywhere as your doc says could be an issue.

Whether tested on the same operating system and the same architecture?

alex8088 commented 1 year ago

I think you package your app with electron-builder's universal mode, universal is not supported. https://electron-vite.org/guide/source-code-protection.html#multi-platform-build

theogravity commented 1 year ago

We've always been building Mac universal for the entire 25 and 26 electron without issues

Our CI build process hasn't changed at all

alex8088 commented 1 year ago

We've always been building Mac universal for the entire 25 and 26 electron without issues

Our CI build process hasn't changed at all

This depends on the operating system architecture. If it is built with x64, you will have this error when installing on arm64, but there will be no problem when installing on x64. If it is built with arm64, there will be this error when installed on x64, but there will be no problem when installed on arm64. Bytecode is related to architecture. You can use the old version to test. I think CI is usually based on x64 architecture. You can install the old installation package in the m1/m2 macOS and this problem will be reproduced.

theogravity commented 1 year ago

We've always been building Mac universal for the entire 25 and 26 electron without issues

Our CI build process hasn't changed at all

This depends on the operating system architecture. If it is built with x64, you will have this error when installing on arm64, but there will be no problem when installing on x64. If it is built with arm64, there will be this error when installed on x64, but there will be no problem when installed on arm64. Bytecode is related to architecture. You can use the old version to test. I think CI is usually based on x64 architecture. You can install the old installation package in the m1/m2 macOS and this problem will be reproduced.

My machine is an M2 and the 26 builds have no issues running. We've also tested with intel machines too.

theogravity commented 1 year ago

You can also find our 26 build for mac universal on our download page.

We only build for mac universal.

https://www.switchboard.app/product/desktop-app

alex8088 commented 1 year ago

Usually there will be problems with universal. You can try to package them into x64 and arm64 to see if the problem still exists.

alex8088 commented 1 year ago

I don’t know if the universal installation package still selects x64 when installing m1/2.

alex8088 commented 1 year ago

I learned from some developers that it is amazing that x64 bytecode can run in arm64, but it shouldn't be possible normally. This issue occurred after upgrading to version 27. this is a confusing issue.

theogravity commented 1 year ago

I learned from some developers that it is amazing that x64 bytecode can run in arm64, but it shouldn't be possible normally. This issue occurred after upgrading to version 27. this is a confusing issue.

Is there a way for the plugin to generate bytecode for both arch and then select the correct one to use in a universal package?

alex8088 commented 1 year ago

@theogravity Maybe it's possible. Check out: https://www.electron.build/configuration/mac.html

Note the mergeASARs and x64ArchFiles options, which may help us. Before using electron-builder packaging, we first specify different outDir to bundle code for the two architectures. Then use these two options to specify program code for different architectures. I haven't tried it, so I don't know if it's really possible.

alex8088 commented 1 year ago

@theogravity Have you found a way to handle universal packaging with bytecode? Can you share it?

theogravity commented 1 year ago

I haven't tried anything yet. I'll probably not try it out until we actually need to upgrade to 27.

lucasrabiec commented 1 year ago

I faced the same issue with x64 build for windows/linux on mac m1 (arm64 mac version works well on m1). I can't install the version on win x64 nor arm64. The issue occurs on Electron 27 and 28 (beta) but 26 works good.

Kyun-J commented 11 months ago

I had the same issue, but is resolved for now. First, my app is not universal and I build x64 and arm64 separately.

The key to solving the problem was to run electron-vite build with a different ELECTRON_EXEC_PATH per arch as mentioned in the guide. I applied the following code to the beforePack of electron-builder and got the desired result. (This only works on arm-based Mac, x64 Mac will get an error when building arm64)

const { downloadArtifact } = require('@electron/get');
const { log } = require('builder-util');
const { spawnSync } = require('child_process');
const { Arch } = require('electron-builder');
const unzip = require('extract-zip');
const fs = require('fs');
const path = require('path');

const electronAppDirPath = path.resolve(__dirname, '.electron');

const getMacElectronAppPath = async (arch, version) => {
  log.info({ arch }, 'generate darwin electron according to arch');
  const zipPath = await downloadArtifact({
    version,
    platform: 'darwin',
    artifactName: 'electron',
    arch,
  });
  await unzip(zipPath, { dir: electronAppDirPath });
  return path.resolve(
    electronAppDirPath,
    'Electron.app/Contents/MacOS/Electron',
  );
};

const build = (option) => {
  return new Promise((resolve) => {
    const isAlpha = process.env.npm_lifecycle_event.includes('alpha');
    const buildCommand = isAlpha ? 'build:alpha' : 'build';

    log.info(`electron-vite ${buildCommand}`);
    const std = spawnSync('npm', ['run', buildCommand], option);
    if (std.stderr && std.stderr.length > 0) {
      log.error(std.stderr.toString());
    }
    resolve();
  });
};

exports.default = function (context) {
  return new Promise((resolve) => {
    const version = context.packager.info._framework.version;
    const platform = context.electronPlatformName;
    const arch = Arch[context.arch];

    if (platform !== 'darwin') {
      resolve();
      return;
    }

    getMacElectronAppPath(arch, version)
      .then((appPath) => {
        return build({
          env: {
            ...process.env,
            ELECTRON_EXEC_PATH: appPath,
          },
        });
      })
      .finally(() => {
        fs.rmSync(electronAppDirPath, { recursive: true, force: true });
        resolve();
      });
  });
};

However, the process is quite complicated. Hopefully there will be some improvements when using the bytecode plugin.

rggagliardi-moveshelf commented 11 months ago

We're replicating the same issue when packing an application from Linux x64 to Windows x64. The installed application works with Electron 26.6.3, but not for Electron 27.x.x (or 28). We get a similar CacheDataRejected exception image

In particular we're using this Docker image electronuserland/builder:wine on our pipeline, building and packing the application for Windows. This is our electron.vite.config.js configuration:

import { defineConfig, bytecodePlugin } from 'electron-vite'
import { resolve } from 'path'

export default defineConfig({
  main: {
    plugins: [bytecodePlugin()],
    root: '.',
    build: {
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'electron/main.ts')
        }
      }
    }
  },
  preload: {
    plugins: [bytecodePlugin()],
    build: {
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'electron/preload.ts')
        }
      }
    }
  },
  renderer: {
    root: '.',
    build: {
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'dist/polyb/index.html')
        }
      }
    }
  }
})

And our version details:

Angular 16
"electron": "^27.1.3",
"electron-builder": "^24.9.4",
"electron-vite": "^1.0.29",
Node 18.18.2

If I comment these lines plugins: [bytecodePlugin()], for main and preload, the installed application works, so we currently concluded the issue is about the Bytecode plugin with newer Electron versions. Please let us know for any suggestion we could try

lucasrabiec commented 10 months ago

@alex8088 bytecode plugin issue still occurs with Electron 28 and electron-vite 2.0.0. Do you have any ideas on how to solve this problem?

jashok5 commented 10 months ago

在构建Mac universal app时,使用electron@28,我也遇到了同样的问题,我想知道这个问题是可以解决的吗

murrayee commented 8 months ago

Too.

alon42 commented 8 months ago

The deep problem lies within the need to compile the bytecode, under Linux, using the Windows electron.exe file. the bytecode plugin just calls the local electron, starts it with the flag "ELECTRON_RUN_AS_NODE=1" (which causes the electron to start as a simple node), and compiles the bytecode with it.

I tried a lot of workarounds, but Wine can't run electron.exe as a node properly under a Linux container, it is very hard to pass the input to the stdin of the wine-electron process. and wine ALWAYS throws its own warnings and errors to the stdin.

After a day of struggling with it, I managed to make Wine run electron.exe inside the container and pass the stdin of the compiled file to the process, I quit when I realized that Wine had two problems:

first you need to make wine to manage to run node_modules/electron/dist/electron.exe without any errors. so you'll have to extend electronuserland/builder:wine and install dependencies.

by adding:

FROM electronuserland/builder:wine

RUN apt update 
RUN apt upgrade -y

RUN apt install -y xorg xvfb xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic winbind
RUN wine reg add "HKCU\\Software\\Wine\\DllOverrides" /v winemenubuilder /d "" /f
RUN echo '#!/bin/bash\n\
export DISPLAY=:0.0\n\
Xvfb :0 -screen 0 1024x768x24 &\n\
exec "$@"' > /entrypoint.sh

# Make the entry point script executable
RUN chmod +x /entrypoint.sh

# Set the entry point to your script
ENTRYPOINT ["/entrypoint.sh"]

I managed to make wine node_modules/electron/dist/electron.exe to run inside a new docker image.

But:

  1. I didn't manage to make Wine run quietly, it always throws some errors to the stdout and it ends up inside the bytecode.
  2. Vite runs in parallel and starts multiple wine electron.exe, but wine is terrible in it, so even after managing to make a wine run electron.exe and passing the stdin to it, when you try to use it with electron-vite, it breaks due to the problem of running multiple wine programs in the same time.
wiryonolau commented 6 months ago

electron-vite build also not working for windows when using bytecodeplugin It always got this error if

out/main/index.js                59.17 kB
node:events:495
      throw er; // Unhandled 'error' event
      ^

Error: write EPIPE
    at afterWriteDispatched (node:internal/stream_base_commons:160:15)
    at writeGeneric (node:internal/stream_base_commons:151:3)
    at Socket._writeGeneric (node:net:962:11)
    at Socket._write (node:net:974:8)
    at writeOrBuffer (node:internal/streams/writable:392:12)
    at _write (node:internal/streams/writable:333:10)
    at Writable.write (node:internal/streams/writable:337:10)
    at file:///home/user/project/node_modules/electron-vite/dist/index.mjs:35:24
    at new Promise (<anonymous>)
    at compileToBytecode (file:///home/user/project/node_modules/electron-vite/dist/index.mjs:26:12)
    at file:///home/user/project/node_modules/electron-vite/dist/index.mjs:276:54
    at Array.map (<anonymous>)
    at Object.writeBundle (file:///home/user/project/node_modules/electron-vite/dist/index.mjs:258:39)
    at file:///home/user/project/node_modules/rollup/dist/es/shared/node-entry.js:19774:40
    at async Promise.all (index 0)
    at async PluginDriver.hookParallel (file:///home/user/project/node_modules/rollup/dist/es/shared/node-entry.js:19702:9)
    at async file:///home/user/project/node_modules/rollup/dist/es/shared/node-entry.js:20699:13
    at async catchUnfinishedHookActions (file:///home/user/project/node_modules/rollup/dist/es/shared/node-entry.js:20119:16)
    at async build (file:///home/user/project/node_modules/vite/dist/node/chunks/dep-cNe07EU9.js:67481:22)
    at async build (file:///home/user/project/node_modules/electron-vite/dist/chunks/lib-GB2q6SUI.mjs:26:13)
    at async CAC.<anonymous> (file:///home/user/project/node_modules/electron-vite/dist/cli.mjs:83:9)
Emitted 'error' event on Socket instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -32,
  code: 'EPIPE',
  syscall: 'write'
}
qyh214 commented 4 months ago

@alon42 I have also encountered similar difficulties, mainly because it is a great idea to directly compile and push Gitlab CI, but it seems that Wine cannot accurately complete this task. In fact, I also encountered an error that asked me to delete package lock.json and interrupt compilation. The current solution may be to directly create a Gitlab runner in Windows


Update: Now Windows 11 x64 install gitlab-runner,and link to gitlab.use this runner to ci build

Venipa commented 1 week ago

any update on this? on electron v31.0.2