Hi!
I'm using esm with electron. The nodejs part of loading ES module works great but I can't figure out how to make the renderer process (aka BrowserWindow) to use esm also for module resolution.
I want to be able to unify the way scripts are loaded because it's a bit weird to be able to use import syntax in main process but still having to use require in the renderer process!
<script>
const { remote } = require( 'electron' )
</script>
so I want to be able to:
<script type="module">
import { remote } from 'electron'
</script>
but because the chromium process is able to use ES module imports, it use the browser path resolution and so I have this error:
Uncaught TypeError: Failed to resolve module specifier 'electron'
Is there a way to tell the BrowserWindow class to use esm instead? Or a way to teach the browser where to import 'global' module names?
I finally tried to import electron from the node_modules folder directly:
<script type="module">
import { remote } from './node_modules/electron/index.js'
</script>
but now I have this error:
Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
Maybe something like this in index.js (bootstrap file) to enable esm to modify the require function that stand in BrowserWindow instances:
const { BrowserWindow } = require('electron')
BrowserWindow.prototype.require = require("esm")( module/*, options*/ )
require = require("esm")( module/*, options*/ )
module.exports = require( `./${require('./package.json').module}` || "./main.js" )
This is just a way to illustrate the idea because the require method does not exist and the renderer module is to be initialized for each instance instead of here...
Hi @devingfx!
The esm loader is really intended for Node. I'm not sure how to modify the browser end of things without going through require(). If you figure it out though I wouldn't be against a PR or a proof of concept to work on.
Update:
For reference I've modified the electron-quick-start repo to use esm in the main and renderer processes. See https://github.com/standard-things/electron-quick-start.
So this could be solved with a simple preload script (when creating BrowserWindow, they have an option to pre-load a script), with a simple script as below:
var _require = require("esm")(module)
process.once('loaded', () => {
global.require = _require
})
And in your index.html file, require your main script in renderer
<script>
require('path/to/your/renderer/script.js')
</script>
Now that script.js can use whatever esm has brought us:
import '...'
export ...
@jdalton BrowserWindow actually integrates node environment into its javascript environment. Hopefully next time if anyone asks related again, this solution would help. And thanks for the great work, I love Electron + ESM. Cheers.
Thanks @Tundon it's good to know that require is extendable this way, but it is not what I wanted to do but instead:
<script type="module">
import { BrowserWindow } from 'electron'
</script>
... directly from root HTML scope and because this execution is handled by the BrowserWindow context aka chromium it's its implementation of import/export that gain precedence...
What is needed is to somehow extends chromium's way of importing (that is not the require from electron's main nor any function to override by the way...)
Hey! I just had an idea:
Is it posible to give the overrided require some string of ecmascript to execute?
Like so it can be implemented this way:
pre-load script:
var _require = require("esm")(module)
process.once('loaded', () => {
global.require = _require
[...document.scripts]
.filter( s=> s.type == "esm" )
.map( s=> _require.fromString(s.textContent) )
})
html pages:
<script type="esm">
import { BrowserWindow } from 'electron'
</script>
Hey! I just had an idea:
Is it posible to give the overrided
requiresome string of ecmascript to execute?Like so it can be implemented this way:
pre-load script:
var _require = require("esm")(module) process.once('loaded', () => { global.require = _require [...document.scripts] .filter( s=> s.type == "esm" ) .map( s=> _require.fromString(s.textContent) ) })html pages:
<script type="esm"> import { BrowserWindow } from 'electron' </script>Hi @devingfx
Have you found a better way to solve this problem? It looks like this code is no longer available.
Nope
Most helpful comment
Hi @devingfx!
The
esmloader is really intended for Node. I'm not sure how to modify the browser end of things without going throughrequire(). If you figure it out though I wouldn't be against a PR or a proof of concept to work on.Update:
For reference I've modified the
electron-quick-startrepo to useesmin the main and renderer processes. See https://github.com/standard-things/electron-quick-start.