node-interop
node-interop copied to clipboard
How to use with webdev
This is more of a question than an issue: How do I use this with webdev?
Until now I had build_web_compilers in my pubspec.yaml, a web/index.html file, web/main.dart, and an index.js file to run Electron and have it show localhost:8080.
That worked great, until I tried to use node_interop. My code compiles but I get a runtime error about the module not being loaded. I presumed that is because I need to use build_node_compilers instead of build_web_compilers.
I swapped that in pubspec.yaml, and renamed the web directory to node, but when I run webdev serve node:8080 it gives error:
webdev could not run for this project.
You must have a dependency on `build_web_compilers` in `pubspec.yaml`.
If I add them both then I get this error:
Ok well I was getting an error like Could not find web/index.html or index.html, but now I get this, even after removing .dart_tool:
[SEVERE] The platform `ddc`, has already been registered.
[SEVERE] Failed to instantiate builder for collection with configuration:
{}
Unhandled exception:
Bad state: Unable to start build daemon.
#0 _handleDaemonStartup (package:build_daemon/client.dart:82:5)
<asynchronous suspension>
#1 BuildDaemonClient.connect (package:build_daemon/client.dart:183:11)
<asynchronous suspension>
#2 connectClient (package:webdev/src/daemon_client.dart:17:23)
#3 _startBuildDaemon (package:webdev/src/serve/dev_workflow.dart:25:18)
<asynchronous suspension>
#4 DevWorkflow.start (package:webdev/src/serve/dev_workflow.dart:173:24)
<asynchronous suspension>
#5 ServeCommand.run (package:webdev/src/command/serve_command.dart:138:27)
<asynchronous suspension>
#6 CommandRunner.runCommand (package:args/command_runner.dart:197:27)
<asynchronous suspension>
#7 _CommandRunner.runCommand (package:webdev/src/webdev_command_runner.dart:38:24)
<asynchronous suspension>
#8 CommandRunner.run.<anonymous closure> (package:args/command_runner.dart:112:25)
#9 new Future.sync (dart:async/future.dart:222:31)
#10 CommandRunner.run (package:args/command_runner.dart:112:14)
#11 run (package:webdev/src/webdev_command_runner.dart:19:56)
#12 main (file:///Users/timh/.pub-cache/hosted/pub.dartlang.org/webdev-2.5.1/bin/webdev.dart:17:22)
<asynchronous suspension>
#13 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:303:32)
#14 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
How is this supposed to work?
Aha I figured it out! For any people trying to get Electron to work... the problem is as follows.
First, I enabled nodeIntegration in my Electron entry point:
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Allow using node APIs from the web context.
nodeIntegration: true,
},
This means that Electron adds the Node APIs to the web page when the page is loaded in an Electron window. This means you can do stuff like loading files, running processes etc. from your web page (running in Electron) that you couldn't do.
However if you simply webdev serve and then do
win.loadURL("http://localhost:8080");
in your index.js, you will find a problem. Electron adds window.require() which is Node's special require() function. The problem is that webdev, or maybe some part of AngularDart, also uses a require() function, but a different one! So you'll get some error about require().
This is mentioned in the Electron docs and I copied their solution:
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
And everything worked... until I tried to use node_interop. The problem is that node_interop calls require() and it expects it to be Node's require(). Since it is actually calling AngularDart's require() you get a very confusing and incorrect error message.
I have now "solved" this by changing this code in node.dart:
external dynamic require(String id);
To this:
external dynamic nodeRequire(String id);
dynamic require(String id) {
return nodeRequire(id);
}
It would be great if there were an option to do this somehow.
Also, my attempt to use build_node_compilers was a red herring - my code isn't actually running in the main Node process, so it doesn't need to be compiled as Node modules. ES6 modules (or whatever webdev uses) work fine.