[Feature Request] Allow ES Module import of Node Builtin Modules in Browser Context and/or Make "main" optional when setting "node-main"
See original GitHub issueAs @frank-dspeed explains in #7557, ES Module support is pretty important: as they are not going to implement ESM this is the moment where NW.js can shine when it is able to run Electron apps.
Builtin node modules (e.g. fs
) can be mixed with browser APIs easily using require
syntax:
(click to show)
<script src="script-that-requires-builtins-and-uses-browser-apis.js"></script>
<script>const test = require("script-that-requires-builtins-and-uses-browser-apis.js");</script>
<script>
const fs = require("fs");
const data = fs.readFileSync("data");
document.querySelector("#data").textContent = data;
</script>
However, there doesn’t seem to be a way to do this easily with ES Modules.
Each of the following fail with: Uncaught TypeError: Failed to resolve module specifier "path". Relative references must start with either "/", "./", or "../"
:
(click to show)
<script type="module" src="script-imports-builtins-and-uses-browser-apis.mjs"></script>
<script type="module">import test from "script-imports-builtins-and-uses-browser-apis.js";</script>
<script type="module">
import fs from "fs";
const data = fs.readFileSync("data");
document.querySelector("#data").textContent = data;
</script>
and excluding the type="module"
each of these fail silently:
(click to show)
<script src="script-imports-builtins-and-uses-browser-apis.mjs"></script>
<script>import test from "script-imports-builtins-and-uses-browser-apis.js";</script>
<script>
import fs from "fs";
const data = fs.readFileSync("data");
document.querySelector("#data").textContent = data;
</script>
The only way importing node builtins seems to work is with a node-main in
the package.json
e.g. {"node-main":"script-imports-builtins.js"}
however the browser APIs are not directly available as node-main code is not in a browser context even if "chromium-args": "--mixed-context"
is used. A workaround is to use nw.Window.get()
or nw.Window.getAll()
to get an NW window and then use e.g. nwWindow.window
to get access to its web APIs. This is hacky at best as node-main
code gets loaded before the window pointed to by main
so a setTimeout is needed to get a window loaded via main
.
Currently the best workaround is to create all windows from within the script referenced by node-main
(which is actually similar to how electron works) however main
is currently still required even if node-main
is set. The workaround is to point main to an empty .js file and just use node-main
I propose, that only one of main
or node-main
should be required and that import
is patched to work with node builtins when used from within a browser context.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:18
Top GitHub Comments
@sysrage I am sorry, but my experience has been similarly poor as yours!
Here is my tedious workaround to ESM using ESModuleShim library – use below as your entry (main) script and your app proper is invoked in it at the end. It might give you a few ideas:
I would suggest not using NW.js for new projects, except in case of niche requirements like code obfuscation etc. since you are unlikely to get a genuine ear to even legitimate issues in this community.
FYI - if anyone is interested in the current workaround. Here is what I came up with:
package.json
node-main.mjs:
loader.mjs:
empty.js: