Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

electron ES module import in renderer not following esm package resolution #387

Closed
devingfx opened this issue May 7, 2018 · 7 comments
Closed
Labels

Comments

@devingfx
Copy link

devingfx commented May 7, 2018

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.

@devingfx
Copy link
Author

devingfx commented May 7, 2018

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...

@jdalton
Copy link
Member

jdalton commented May 7, 2018

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.

@jdalton jdalton closed this as completed May 7, 2018
@Tundon
Copy link

Tundon commented Oct 19, 2018

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.

@devingfx
Copy link
Author

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...)

@devingfx
Copy link
Author

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>

@Invincibl-e
Copy link

Invincibl-e commented Nov 10, 2020

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>

Hi @devingfx
Have you found a better way to solve this problem? It looks like this code is no longer available.

@devingfx
Copy link
Author

Nope

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants