andywer / threads.js

🧵 Make web workers & worker threads as simple as a function call.
https://threads.js.org/
MIT License
3.06k stars 164 forks source link

Threads.js and Electron - Problem after Build step with electron-builder #406

Open Comkiled opened 2 years ago

Comkiled commented 2 years ago

Hello everyone,

i got a weird problem, after building my application with electron-builder.

I do output my application as a portable for Windows, asar packaging is activated, but I unpack all my workers with "asarUnpack".

As far as I understand the build process, first output of the build process is a so called "win-unpacked" folder with an .exe file, resources folder and some other folders. When I start the .exe file in the "win-unpacked" folder, yet everything works as expected.

The 2nd part of the build process will then give me a small portable .exe file without any folder accompanying. When I start this .exe file, the same folder as the one in the first build step ("win-unpacked") will be created temporarily somewhere in AppData/Local/Temp/xxxx folder. But in this case, my application does not work anymore, but throws JS errors, stating that the "threads" module, which should be imported into the worker, could not be found. The threads module is located somewhere inside the asar-package as a dependency.

After the first build step this reference stays available, the worker locates the "threads" module inside the asar package and imports it successfully, thus everything works as expected. After outputting and then starting the portable .exe file, it seems as if this reference is broken, although the temporarily created folder inside "AppData/Local/Temp/xXxxXX" is exactly the same folder in size and amount of data as the one from the first build step.

Maybe anyone of you has a suggestion, what my problem might be.

Edit 1: I am not using any bundler for my backend code. So the problem is not associated with bundling. Edit 2:

Edit 3: In order to reproduce this error:

  1. package.json:
    {
    "name": "workertest",
    "version": "1.0.0",
    "description": "",
    "main": "build/main.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "npm run buildElectron && electron .",
    "buildElectron": "tsc",
    "buildAndOutputPortable": "set NODE_ENV=production && npm run buildElectron && electron-builder"
    },
    "author": "",
    "license": "ISC",
    "build": {
    "appId": "de.worker.test",
    "directories": {
      "output": "workerTest"
    },
    "files": [
      "build/**/*",
      "package.json"
    ],
    "win": {
      "target": "portable",
      "artifactName": "workerTest.exe"
    },
    "asarUnpack": [
      "build/workers/testWorker.js"
    ]
    },
    "devDependencies": {
    "electron": "^16.0.5",
    "electron-builder": "^22.14.5"
    },
    "dependencies": {
    "threads": "^1.7.0",
    "tslib": "^2.3.1"
    }
    }
  2. tsconfig.json:
    {
    "compilerOptions": {
      "target": "es6",
      "module": "commonjs",
      "moduleResolution": "node",
      "noEmitOnError": true,
      "lib": ["es2017", "dom"],
      "strict": true,
      "esModuleInterop": false,
      "allowSyntheticDefaultImports": true,
      "experimentalDecorators": true,
      "importHelpers": true,
      "outDir": "build/",
      "sourceMap": true,
      "inlineSources": true,
      "rootDir": "./"
    }
    }
  3. main.ts:
    
    import { app, BrowserWindow } from 'electron';
    import { spawn, Worker } from 'threads';

let testWorker : any = undefined

function createWindow () { const win = new BrowserWindow({ width: 800, height: 600 })

win.loadFile('index.html')

} async function start() { if(!testWorker) { testWorker = await spawn(new Worker('workers/testWorker')) } app.whenReady().then(() => { createWindow() }) } start()


4. index.html:

<!doctype html>

pxt-ui-app Hello world
5. folder structure:

project-name/ |- workers |- testWorker.ts |- package.json |- index.html |- main.ts |- tsconfig.json

andywer commented 2 years ago

Hey @Comkiled. Very detailed description 👍

Bad news first: I don't use Windows, don't have an electron app using threads.js in the app thread at hand and thus I don't have an answer to your issue.

However, some feedback nevertheless: Pretty sure that the parent node_modules/ cannot be located from within the win-unpacked directory. Can you check the path of the worker module and the path of the node_modules/ after unpacking?

I would say it's a 50:50 chance if it's a general issue with your app's electron setup or if it's a bug in threads.js. After all we do some acrobatics around worker module paths.

Comkiled commented 2 years ago

Hi @andywer, the node_modules folder is located inside the .asar package. The worker module is located inside node_modules, thus also inside the .asar package. The workers themselves will be unpacked from the .asar archive. The strange thing is, that without building a portable, but just a normal folder build, everything works as expected. As soon as I build the portable, the import references which looked into the .asar package before, now are broken. The good thing is, i found a workaround to solve my problem, but the workaround is pretty ugly. Meanwhile I think it is a problem with electron-builder and not a problem with threads.js. I posted the same issue in the GitHub project of electron-builder. Maybe they will find a solution.

biw commented 1 year ago

Hey @Comkiled, what was your workaround?