Heck of a time with threeJS and electron

I’ve configured this stack in a number of different ways and I have a heck of a time running threeJS with Electron and Electron Forge.

It HATES my import statements for three and orbit controls.
I get a wide variety of errors and see a TON of variable solutions online.
I know that I have fixed this before, but don’t recall what I did.

Thanks a bunch for any direction.

Configuration Details:

Errors are associated with my import statements ( > npm run start)

(node:7852) Warning: To load an ES module, set “type”: “module” in the package.json or use the .mjs extension.
(Use electron --trace-warnings ... to show where the warning was created)
App threw an error during load
import * as THREE from ‘three’;

SyntaxError: Cannot use import statement outside a module
at internalCompileFunction (node:internal/vm:73:18)
at wrapSafe (node:internal/modules/cjs/loader:1160:20)
at Module._compile (node:internal/modules/cjs/loader:1212:27)
at Module._extensions…js (node:internal/modules/cjs/loader:1311:10)
at Module.load (node:internal/modules/cjs/loader:1098:32)
at Module._load (node:internal/modules/cjs/loader:945:12)
at c._load (node:electron/js2c/node_init:2:13672)
at cjsLoader (node:internal/modules/esm/translators:288:17)
at ModuleWrap. (node:internal/modules/esm/translators:234:7)
at ModuleJob.run (node:internal/modules/esm/module_job:217:25)

Look at electron as if it was just a browser - if a browser can run your website / app, so can electron (they work virtually the same, electron just extending the API served by the browser a bit.) That being said - it does not matter if / what libraries you use on your website, be that three.js or any other npm package - it should and will work with electron after bundling everything up.

Personally, I’d suggest scrapping the entire thing and quickly starting over - since setting it up fresh will likely just be easier and quicker:

  1. Create your app - it should have an index.html, and a single .js file. Use vite to bundle your javascript, HTML, and styles together into a static page.
  2. After your page is built into a static set of files, npm i express (express webserver.)
  3. Initialise your electron project in a neighbouring directory, for example (ofc feel free to adjust it to your preferences) :
- MyElectronApp/
  - web/
    - package.json: this package contains ONLY dependencies of your app, not electron
    - src/
      - index.html
      - some-js-file.js
    - dist/
      - index.html
      - bundle.js
  - electron/
    - package.json: this package.json contains electron and other non-web dependencies
    - index.js
    - preload.js
    - app/
      - (empty)
  1. In package.json of electron, add a build script that copies contents of MyElectronApp/web/dist/ into MyElectronApp/electron/app.
  2. In index.js of electron start express.js server and ask it to serve contents of MyElectronApp/electron/app as localhost:8181 (or another port, up to your preferences.)
  3. In index.js of electron, await browserWindow.loadURL("http://localhost:8181"); (docs.)
  4. Celebrate great success.
1 Like

Oh my gosh, mjurczyk, I’ve restarted this stack over and over again for weeks. I always get stuck at the import statements. It runs if I remove the import statements. Maybe I just shouldn’t have those. Without imports:

With imports:

The entire library relies on importmaps now afaik. So even if you import one of the source files like OrbitControls with a direct path… it won’t work because OrbitControls attempts to:

import * as THREE from “three” which wont work. So you either have to pull the library in via NPM, or use importmaps in your HTML…

Stick the following script tag in your html before you load any other scripts:

<script type="importmap">
    "imports": {
        "three": "https://threejs.org/build/three.module.js",
        "three/addons/": "https://threejs.org/examples/jsm/"

This tells the browser that anything imported from “three” should actually load from threejs.org

And anything imported from “three/addons/” should be loaded from threejs.org/examples/jsm/

Then in your top level script, you import threejs etc like this:

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { RGBELoader } from "three/addons/loaders/RGBELoader.js";
import { GUI } from "three/addons/libs/lil-gui.module.min.js";

If that works, then you might be set, and you can switch the paths in the import map to direct to the CDN of your choice, or your own local copy of the threejs version you need.

Import maps are confusing at first, but then you realize that they are fantastic because they let you globally re-route where your entire app imports things from.

1 Like

I feel like all I have to do is add a path to these node_modules so the browser can find the three libraries.

I’ve install three via npm.

I’ve never gotten three to import inside electron. Its so close, if I could just access the three folder. Maybe my path names are wrong. I tried using absolute paths. Maybe I should run three inside main.js?

There are NO videos on how to set this up this way. Someone should make one.
Most resources online are pretty insistent that you set up electron first, so I haven’t tried. I wonder why they say that. But, I have built up three with express and vite.

Can I have the electron forge dev dependencies in package.json?
I think that electron and electron forge are two different things. I’ve built it using electron and then converted the application over into electron forge. Three failed in that case.

I’ve got the broken project on the left and a functioning threeJS on the right.

Maybe I can do what you advise.

I feel like the two different architectures have different entry points.
I’m worried about what I enter into the “start” script.

I found it super easy to package everything, you could even make a web game to publish on Steam.
I followed these steps: https://www.electronforge.io/
here as result : game.exe - Google Drive

And thanks for the tip, I was thinking about putting chromium embebed: CEF Forum • Index page

you should merely build your project with vite as you always do: npm run build. this will create a /dist folder. in electron you link the index file of the dist directory and that’s it.

const win = new BrowserWindow(...)

you don’t need import maps nor should you use them because they are complex especially for sub and sub-sub-n dependencies, and they shut you out of the javascript eco system. you consume packages through tooling, like vite, which is pure esm but it removes all the major barriers.

1 Like

I can’t use the internet in the final result, hence the use of electron forge.
Maybe I could use builder instead of electron forge. That might gain me some flexibility.
Maybe I have just been installing things in the wrong order. Every resource I’ve found says I HAVE to start by installing electron forge.

Some people say that I shouldn’t try to do this without React Three JS.

I am married to using, at least, three JS because it is so fun and I already created files in blender. I really, really want to use it. Its soooo fun.

But, some people say that I shouldn’t even try to do this without React Three JS. I’m no front end dev, but I’ll die on this cross if it allows me to use threeJS functionality.

Maybe at a minimum, I only require either (electron and threeJS) or (electron and react three fiber).

I still need to try mjurczyk’s suggestion. I am just frightened and all frozen up in a state of fear.

You don’t need react. You don’t even need electron. You can use NW.js. :slight_smile:

edit: I just converted one of my single page apps into an NWjs desktop app in <7 minutes.



Here’s a zip:


Unzip it somewhere, and run nw.exe

To modify it for your own app,
open the “app” folder… and put your index.html, scripts, assets, etc. in there.

1 Like

Say WHAT?!?!?!?!
Oh man! I should have written to you all weeks ago.

you not need React to uses THREE.
Three its a wraper/tool to uses WebGL. and React its a Tool for javascript/shadow dom.
Everything you do with these 2 you can do natively

So basically, if we build a threeJS app, then build an electron app, we want to move that threeJS dist folder into the electron app because the dist folder contains all our our custom GTLF files and everything threeJS built into a web application. Then, electron has everything it needs to make a desktop application?

I guess that makes sense. Slowly, but surely, this might start to make sense.
I’m need to step thru it piece by piece. Ecosystem (again) - #2 by morty1