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

Error while running inside of Electron #21

Closed
TheKeithStewart opened this issue Apr 20, 2017 · 11 comments
Closed

Error while running inside of Electron #21

TheKeithStewart opened this issue Apr 20, 2017 · 11 comments

Comments

@TheKeithStewart
Copy link
Contributor

TheKeithStewart commented Apr 20, 2017

I am writing a mapping application that is going to be running inside of Electron. I am trying to use this to load the ArcGIS API for JavaScript modules but I am getting the following error:

ERROR Error: Uncaught (in promise): AssertionError: path must be a string
AssertionError: path must be a string
    at Module.require (module.js:497)
    at require (internal/module.js:20)
    at Object.dojoRequire (index.js:44)
    at esri-loader.service.js:41
    at new ZoneAwarePromise (zone.js:776)
    at EsriLoaderService.loadModules (esri-loader.service.js:39)
    at esri4-map.service.js:15
    at ZoneDelegate.invoke (zone.js:365)
    at Object.onInvoke (core.es5.js:4145)

The line of code that this is failing on is:

window['require'](modules, callback);

Because of the fact that this is running inside of Electron and therefor is loading in a NodeJS process the require() function accepts a string as an argument rather than an array of strings.

I have created a repo to demonstrate this issue. Instructions for running this application inside of Electron can be found in its README.

One possible solution to this issue is to use RequireJS for loading modules. This is generally not meant to be used in a NodeJS environment but should provide the API that you are looking for with the window['require'](modules, callback) call.

@tomwayson
Copy link
Member

tomwayson commented Apr 24, 2017

@kgs916

First, let me start by saying that I've never created an electron app that uses the ArcGIS API.

I believe @odoe has.

Based on that error, it looks to me like window.require is Node's require. What I suspect is happening is that when you call load() (thank you for providing source btw) that it calls isLoaded() which sees that require() is defined and says, yeah, it's already loaded.

I did a little searching, and I came upon @odoe's suggestion to rename node's require before loading the JSAPI: https://geonet.esri.com/thread/160978#comment-623946 I would try just renaming require() to nodereq() and then using that where you'd ordinarily use require() for node modules, maybe just here?

Can you try that?

@andygup
Copy link
Member

andygup commented Apr 25, 2017

@kgs916 I've seen that error before when trying to run a require statement in the main process.

I haven't tried esri-loader in Electron, but in a few prototypes that I built I didn't seem to need it.

Here's a simple example you can try out really fast using electron-quick-start.

Run the following commands in console:

git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
npm install && npm start

The quickstart app should launch. If it does then control-c in the console to exit the app.

Change the index.html file to this:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

    <link rel="stylesheet" href="https://js.arcgis.com/4.3/esri/css/main.css">
    <script src="https://js.arcgis.com/4.3/"></script>
  </head>
  <body>
    <h1>Hello World Part 2!</h1>
    <!-- All of the Node.js APIs are available in this renderer process. -->
    We are using Node.js <script>document.write(process.versions.node)</script>,
    Chromium <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.

    <div id="viewDiv"></div>

  </body>

  <script src="index.js"></script>
  <script>
    // You can also require other files to run in this process
    require('./renderer.js')
  </script>
</html>

And create index.js and copy the following content in:

require([
     "esri/Map",
     "esri/views/MapView",
     "dojo/domReady!"
 ], function(Map, MapView) {

     console.log("Require() loaded.");

     var map = new Map({
         basemap: "streets"
     });

     var view = new MapView({
         container: "viewDiv",
         map: map,
         zoom: 4,
         center: [15, 65]
     });

 });

The last step is to run npm start again and you should see a map.

image

@tomwayson
Copy link
Member

tomwayson commented Apr 25, 2017

Yeah, I've been wondering about the value of esri-loader in an electron app. I'm guessing the reaons to use it is b/c you have source that uses imports/exports that is getting transpiled into code that runs in electron.

In that case, I wonder if using the Exclude and Require pattern would be a better solution. You could trade the run time complexity introduced by esri-loader for the the build time complexity of configuring webpack (or whatever bundler you're using) to exclude the esri modules and output an AMD bundle that would be something you could use i @andygup's above example. Presumably you are building a desktop application and therefore the initial load time should not be as great a concern, so the benefits of using esri-loader (like lazy loading) should not be as important, right?

@andygup
Copy link
Member

andygup commented Apr 25, 2017

RE: using imports/exports so true and a good point so thanks for calling that out. It does depend on how you are building the app. My overly simple, single page web app above is definitely not a one-size-fits-all solution.

RE: dedicated loader versus Exclude and Require...hmmm good question, and I think either pattern could actually work. The cool thing about Electron is you can use it with your favorite JavaScript framework such as Angular, Vue, React, Ember etc. It's all V8 JavaScript Engine under the hood. So, the pattern you use pretty much depends on your needs, likes, requirements, skillz and tolerances.

RE: load times. The nice thing about Electron is the shell that loads the app is pretty lightweight and fast, so as you mentioned it seems reasonable that you may have a little more wiggle room for module loading that might not exist in a full-blown browser-based app. As for which pattern is best, it may actually take some A/B testing to compare dedicated loader versus exclude and require, or any other pattern that developer comes up with.

From an Electron standpoint and with respect to the error above, the real key to app happiness is to carefully separate the Renderer processes from the Main process. The Renderer handles all the .html, .css and .js goodness. Bundling modules, transpiling etc for the Renderer works just like it does in non-Electron apps. For example, Electron even comes with it's own compiler.

@TheKeithStewart
Copy link
Contributor Author

@tomwayson and @andygup, thanks for all the great info!

I would like to avoid the "Exclude and Require pattern" if I can because I am using the Angular CLI and there is very limited access to the webpack build process to make the necessary changes.

I managed to get this working with the Angular CLI making a very small change to the esri-loader. I created a pull request with the change: #22. I tried this out both inside and outside of Electron and it worked well. I can create an example demonstrating this as well if needed I just ran out of time this morning to get that pulled together.

@TheKeithStewart
Copy link
Contributor Author

I have updated my example at https://github.com/kgs916/electronMap to include the change to the esri-loader. It is now working correctly both in and outside of Electron.

@tomwayson
Copy link
Member

Resolved in #22

@tomwayson
Copy link
Member

@kgs916 if you update your electronMap example to use the v1.0.0 let me know and I'll include it in the examples.

@TheKeithStewart
Copy link
Contributor Author

@tomwayson I'm thinking about renaming electronMap to something a bit more descriptive. What do you think of ng-cli-electron-esri-loader? To long?

I was also thinking to add an npm script to esri-angular-cli-example that would allow for it to be run in Electron. This would make for a much more compelling example of JSAPI running in Electron. What do you think?

@tomwayson
Copy link
Member

What do you think of ng-cli-electron-esri-loader?

Maybe just ng-cli-electron-esri?

thinking to add an npm script to esri-angular-cli-example that would allow for it to be run in Electron

Go for it!

@TheKeithStewart
Copy link
Contributor Author

@tomwayson

I like the name. I have renamed the repo to ng-cli-electron-esri and updated it to use the latest esri-loader. Thanks for getting release out there!

One more change that I want to make to this example before I consider it good-to-go is to use the angular2-esri-loader so that it matches the example gist. I've submitted a PR to update the angular2-esri-loader to the latest esri-loader as well tomwayson/angular-esri-loader#13.

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

No branches or pull requests

3 participants