question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Provide a way to synchronously use modules that you know are loaded

See original GitHub issue

One of the few drawbacks of the esri-loader approach is that just getting a reference to JSAPI modules is always asynchronous, even if we know the module has already been loaded (i.e. was included in the Dojo build layer). A good example is esri/config - you may want to set corsEnabledServers on that before loading a map. Currently you’d have to call loadModules(['esri/config']).then(esriConfig => {}) to do that.

However, if you pass a single module id as a string (instead of an array of module ids) to Dojo’s require() it will return that module synchronously as long as it has already been loaded. See the “alternative require() syntax” in the Dojo loader docs. So, this library could expose a function that wraps a call to require(moduleId) using that syntax like:

import { getModule } from 'esri-loader';
const esriConfig = getModule('esri/config');

This would be a naive pass through, and would not attempt to verify that the script has loaded nor that the module exists nor fallback to loading it asynchronously, etc. It would just throw an error in those cases.

If you think this would be a useful feature, add a 👍

Conversely if you think this is not useful, add a 👎

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:10
  • Comments:13 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
tomwaysoncommented, Apr 14, 2018

Another way to have synchronous access to modules but w/o the the uncertainty of the above solution is to follow the pattern below.

Let’s say you need to create a map in one component, and then in another component create a legend. In this scenario, you need to create the map first, then create the legend only once you have a reference to the map. However, it is unlikely that you have both references to both DOM nodes at the time you want to start creating the map (for example if the legend component is a child of the map component and it’s render lifecycle hasn’t started yet).

One way to do this is in a service (or any singleton module in your app) add functions like:

  newMap (elem, options) {
    // load BOTH the map AND legend modules
    // even though we're not using the Legend at this time
    return loadModules(['esri/map', 'esri/dijit/Legend'])
    .then(([Map, Legend]) => {
	  if (!this._Legend) {
        // keep a reference to the Legend class so that legends can now be created synchronously
        this._Legend = Legend;
      }
      // create and return the map
      return new Map(elem, options);
    });
  },
  // synchronous function to create a new legend
  // will throw an error if newMap() has not already been called and returned
  newLegend (params, srcNodeRef) {
    if (this._Legend) {
      return this._Legend(params, srcNodeRef);
    } else {
      throw new Error('You must have loaded a map before creating a legend.');
    }
  }

Then once the map component’s DOM has loaded (like ngInit() or componentDidMount()) you can run something like:

mapService.newMap(elemRef, options).then(map => {
  // TODO: somehow signal to the legend component that the map has loaded
  // i.e. pass it down as a prop, etc
});

Then in the legend component, whenever you receive a new map instance (i.e. via prop, etc), you can run something like:

this.legend = mapService.newLegend({ map: this.map }, elemrRef);
this.legend.startup();

While that is a little complicated, what I like about it is that the developer is in complete control over which modules can be made available synchronously, so there’s no mystery about why attempts to load modules synchronously might fail (either b/c the JSAPI hasn’t been loaded, or the module is not one of the ones that can be loaded synchronously).

1reaction
odoecommented, Jan 5, 2018

@jpeterson to check what’s in the CDN build layers, look at the Layer Contents section of the build reports. https://js.arcgis.com/4.6/build-report.txt

Read more comments on GitHub >

github_iconTop Results From Across the Web

Synchronous module loading in ES6 - The Little Calculist
One of the great features of ES6 modules is the direct style module loading syntax: import map from "underscore.js"; ... map(a, f) ....
Read more >
Synchronously load a module whose name is determined at ...
With CommonJS, require calls are synchronous, one can easily load a module dynamically like this: require('./' + localModulePath);. ES6 ...
Read more >
CommonJS vs. ES modules in Node.js - LogRocket Blog
One of the limitations of using require() is that it loads modules synchronously. This means that modules are loaded and processed one by...
Read more >
The Dojo Loader Legacy Modes - Dojo Toolkit
I get tired just writing it down. Let's explore how each mode operates in detail. Legacy Synchronous Mode¶. In this mode, everything is...
Read more >
JavaScript - Parcel
Both the ES module import statement and CommonJS require function load dependencies synchronously: that is, the module can be referenced immediately without ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found