Skip to content

Instantly share code, notes, and snippets.

@frank-dspeed
Last active April 16, 2022 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frank-dspeed/da0b05cfe646a352929b6d1225a44943 to your computer and use it in GitHub Desktop.
Save frank-dspeed/da0b05cfe646a352929b6d1225a44943 to your computer and use it in GitHub Desktop.

Electron ESM Support

Electron it self supports the usage of ESM you can load them via a cjs entry point and import(absolutePath)

in the import the createRequire will not work as expected there are dragons because some vars get copyed once only

but that is a none blocker normaly as long as you init your CJS code parts in CJS and keep your ESM Code ESM Only

for example at present there are no NodeJS and Or Electron ESM Modules the import fs from 'fs' is done on best effort base as so all the CJS import magic via dynamic import in ESM

ESM is at present only CJS Syntax Sugar in NodeJS Nativ at Last.

nodeNativeImport = (specifier) = rollupLoader(specifier);
// Translates all imports and code to CJS then requires the result

``ǹpm i esm``` also works great most of the time!.

General Rules for Transpiling ESM

ESM as it is syntax Sugar over CJS can simply be transpiled to CJS on runtime via rollupLoader no downSides as long as we only change the module system. The only edgecase as always is dynamic import with none static specifier and dynamic require with such a specifier then you maybe need some adjustments in the mappings but that is good anyway for deployment or packaging.

if you load with complex own specifiers and use them in your application all over then maybe consider npm esm if you load good static code you maybe produce a static bundle for deployment or you choose to run with the rollupLoader

same as webpack in generall or any other bundler

Collection of my Valueable Comments that introduce patterns

> @MarshallOfSound I Experiment at present with the NWJS C Cef implementation a Lot and the GraalJS one to connect the loops
> 
> my idea that is already partial implemented in NWJS is to spawn a NodeJS Only Start process as electron does but then we fork replace our own process with the right arrguments. So it should be solve able to expose some api's to switch the modes (entrypoints of the binary)
> 
> more easy explained abstract the fact that the bindings are sync via simply async init them and await nothing simply pass the original entrypoint into the new started shimed environment. So we call the same entrypointJs 2 times 1 time for main init of chrome and then 1 time again with chrome inited like specified in it self before.
> 
> for example
> 
> ```
> const myConfig = electron.someMethode('')
> ```
> 
> we control what the method returns. so when we run the secund time we run already know the results of someMethods as we did eval that in the run before and this way we can pass the correct references.
> 
> Pseudo Code
> 
> ```
> loadedCode
> Struct = returns v8::isolate(first pass with loadedCode) // can use ESM async await everything
> SecundRunningInstance = createSecundPass(Struct) // takes the result of the ESM Code to spawn MixedContext and this way run the same code again but with the sync parts already inited.
> this process stays alive while forking (processManager) 
> ```
> 
> the first run exposes methodsThat simply evaluate to the expect final result of the CJS Api's and then executes them sync before the secund run and passes the references back via the methods in the secund run.

Solutions

In general are the same as with NodeJS and Native Modules electron is a Nativ NodeJS Module so it can only get required

CJS Entrypoint

my-project/
  frontend/
    …
    index.html
  backend/
    index.cjs // very important to use `.cjs`
    app.js // regular ESM stuff
  package.json // type set to module so all .js files are like .mjs 

electron.cjs // main entrypoint

globalThis.electron = require(electron);
// Rest of your Electron main Configuration
// You can not use any ESM Stuff as you need
// to finish the bootstrap process 
await import('./app.js');

app.js

// electron.on(ready) would be registered to late!
electron.app.whenReady().then(...);

preflight scripts

They also need to be .cjs and fully sync they can register async operations but can not await the result of that operation in the main process only via messaging.

rule of thumb

  • only NodeJS Nativ Modules (every buildIn Module) do require to get loaded via require()
  • only .cjs entrypoints are valid as for html only <script> tags are valid you can later switch to script type=module but when you want to hook into the rendering CJS is required as the import module system is async.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment