-
Notifications
You must be signed in to change notification settings - Fork 79
Provide a way to synchronously use modules that you know are loaded #71
Comments
This would be an excellent feature as long as folks know what they're doing (read: document/warn about it well). |
I suspect anyone creating their own build is comfortable enough to know what it contains. But is there any documentation that would help developers know which modules are included in the build layer of the CDN hosted version of the JSAPI? |
Does this mean that if someone tries to use that function whilst the API is still loading it will fail? The config example is something I would associate with someone doing if they are preloading the API, so that means they'd still need to check it was loaded before doing the Only other thing I'd add is that if you want to work in a more synchronous manner and are using something like the webpack then you can use the ignore externals technique and you get a similar end result. |
Thanks @davetimmins
Yes.
Yes, and since 1.6 I suppose you can actually use // preload the JSAPI
loadModules('esri/config')
.then([esriConfig] => {
// use esriConfig to configure CORS etc
}); Then in a sumbodule somewhere you can just call: loadModules(['esri/views/MapView', 'esri/WebMap'])
.then(([MapView, WebMap]) => {
// this block should not execute until after the config was set... I think... I'd have to double check...
}); So config might not be the best example - In my own code, I've noticed needing references to classes like
Yes, I completely agree that is likely going to be the case, which is why I'd want to see a lot of 👍 on this before taking it on.
True, but part of my secret agenda w/ this issue is to address the one "advantage" that technique has over esri-loader. At this point, I think there are so many pros on the esri-loader side, that I'm going to start actively discouraging people to use the "ignore externals" approach.
Also feel free to 👎 if you don't think it's worthwhile. I have half a mind to do that myself. 😜 |
Ok cool, downvoted :) Yea I never use the ignore externals technique, I find it too cumbersome with the setup and messing around with the script injection etc. |
@jpeterson to check what's in the CDN build layers, look at the Layer Contents section of the build reports. |
I would agree that the example of For what its worth, my annoyances with async-ing everything include:
|
I'm going to give this a 👍 since I see some benefits and don't really see any harm in having the option ( as long as it's documented well 😃 ). Some of the strongest use cases for optional synchronous module load capability come from apps that aren't map-centric. For some apps I've worked on this capability comes into play after the app has loaded and you don't have to worry so much about taking a synchronous request performance hit in the UI.
OMG, Totally agree! |
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 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 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). |
A variation of the above pattern can be seen in this ember app, where there is a map service w/ a |
#122 suggests something similar to this - and is working in prod. |
To clarify, #122 still uses |
Closing as I think it's better to document the pattern (#150) rather than provide an API for this. |
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 setcorsEnabledServers
on that before loading a map. Currently you'd have to callloadModules(['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 "alternativerequire()
syntax" in the Dojo loader docs. So, this library could expose a function that wraps a call torequire(moduleId)
using that syntax like: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 👎
The text was updated successfully, but these errors were encountered: