Loader of the Things: One Library to Load Them All

The esri-loader library hit the 2.0.0 milestone this week.  This release doesn’t add any features, but merely removes the old callback APIs that were deprecated when we introduced the promise-based ones in v1.5.0. If you’ve been using the new APIs, you can save yourself a few bytes by upgrading to 2.0.0. You can read more in the 2.0.0 release notes.

One does not simply load modules from the ArcGIS API

One does not simply load modules from the ArcGIS API

The work leading up to this milestone got me reflecting on the broader state of loading ArcGIS API for JavaScript modules and I came to this conclusion:

If your ArcGIS web application uses any other module loader besides the Dojo loader (i.e. webpack, Rollup.js, etc.), you should be using esri-loader.

That’s a bold statement, so let me back it up.

The two patterns

A little over a year ago, I published a blog post that described two general patterns for working around the limitation that the only reliable way to load ArcGIS API modules is to use the Dojo loader. I called these patterns “dedicated loader module” and “exclude and require” and presented them as equals, each with its own benefits and challenges. This was right after the initial release of esri-loader, and I referenced esri-loader as an implementation of the “dedicated loader module” pattern.

One library to load them all

It’s now clear that the benefits of the “dedicated loader module” pattern outweigh those of the “exclude and require” pattern. Here are a few things that you can only do if you’re using a library like esri-loader:

It’s also become clear that with nearly 100 stars on GitHub, and ~1,000 downloads a week, esri-loader has emerged as the de facto implementation of the “dedicated loader module” pattern. There are over a dozen open source reusable libraries and example applications that show how to use esri-loader in 7 different frameworks.

Not just for webpack

The above blog post presented these two patterns specifically as workarounds for webpack, but benefits of using esri-loader hold true regardless of which module loader you’re using. Below are a few special considerations for each module loader.

Webpack

I’ve already listed above the benefits of using esri-loader rather than the “exclude and require” pattern in applications bundled with webpack. For these reasons, I have deprecated my example repository showing how to use the “exclude and require” pattern with webpack.

There have been multiple efforts to get webpack to actually load and bundle Dojo modules, but I’m not sure that would be better than using esri-loader. The latest such effort is dojo-webpack-plugin and to my knowledge, no one has successfully used it with the ArcGIS API… yet. Unlike previous efforts, the OpenNTF team have put a lot of work into that plugin to try and achieve some level of parity with the Dojo loader, so it might actually work with the ArcGIS API. So why haven’t we heard about anyone getting this working? Maybe it’s not all that it’s cracked up to be. For one thing, it’s going to slow development build times. Also, I wonder if you’ll be able to produce a build that’s any smaller than a Dojo build, or if/how it works with newer webpack features like code splitting and dynamic import(). Even if someone ends up figuring all that out, this might not make sense for smaller applications, or those that have limited mapping needs. Until then, I’d say stick with esri-loader.

Rollup.js

The benefits listed above apply equally in applications bundled with rollup.js. I have also deprecated my example repository showing how to use the “exclude and require” pattern with rollup.js.

SystemJS

SystemJS is the one module loader that you could make a case for using another library, specifically systemjs-plugin-dojo, instead of esri-loader. That will work during development to load modules from individual files, but I’m unclear what will happen during production builds. I would guess that for production builds you’d need to fall back to using the “exclude and require” pattern, and how you would do that would depend on what bundler/build tool you use. Does JSPM support external modules?

If you don’t want to figure that out, I suggest just using esri-loader in your SystemJS applications.

Ember’s loader.js

Ember has to be special, so has it’s own module loader. So there’s a special Ember addon that wraps esri-loader called ember-esri-loader, and it will let you enjoy the above benefits in your Ember application. Well, all the benefits except one. Ember also has it’s own special flavor of universal application called FastBoot, and we’re still working on getting that to work with the ArcGIS API. You can track the progress here.

Parcel and whatever comes next

Parcel is a new bundler similar to webpack, but it promises zero configuration. While I haven’t yet tried to get esri-loader to work in a parcel app, I’m sure it will. More importantly, I’m pretty sure that the “exclude and require” pattern will not currently work in parcel. Follow this issue for details and updates.

Basically I’m confident that you could use esri-loader with any module loader. I haven’t tried it yet, but I’m pretty sure esri-loader would even work work in type=module scripts.

When would you not use esri-loader?

Obviously there’s no need to use esri-loader in a Dojo application that doesn’t use a module loader like any of the above. This approach makes the most sense for map-centric applications where a map (or a 3D scene) is the focus of the user experience and the source of most of the application state. Rene Rubalcava created a yeoman generator to scaffold this type of application.

This type of map-centric Dojo application can also use components from other frameworks, even without bringing in that framework’s module loader of choice. This is because other frameworks are usually distributed as UMD modules, which can be loaded by Dojo loader. The Using Frameworks guide page  discusses this approach further and includes links to a few samples including ones that use React and Vue.js components.

But we must have our precious import statements

It’s true that you can’t import ArcGIS modules when using esri-loader, but this is not necessarily a bad thing. I’ll admit that it is very convenient to be able to write something like import Map from 'esri/Map'. Maybe too convenient. If you use the “exclude and require” method, then there’s nothing stopping you from sprinkling statements like that throughout your app. Conversely, by forcing you to wrap all interaction with the ArcGIS API in asynchronous calls to loadModules(), esri-loader encourages you to think about how and when you use the ArcGIS API. You will find yourself naturally gravitating toward best practices like pushing your dependency on the ArcGIS API to the edge of your application and only using it for exactly what you need it for like maps and 3D scenes. This will make it easy to replace calls to loadModules() with import statements in your applications once esri-loader is no longer needed,

You shouldn’t sacrifice the benefits esri-loader can bring you today just because one day we won’t need all these workarounds to load ArcGIS modules. The ArcGIS API for JavaScript team is working on things like converting the code base to TypeScript and removing dependencies on plugins that can only be loaded by the Dojo loader (like dojo/i18n) so that you will eventually be able to actually import ArcGIS modules using other module loaders. Ideally the ArcGIS API would then be distributed as ES modules to enable other module loaders to tree-shake application builds. I don’t know what the timeline is for that work, but even once it’s done someone will need to start using those ES modules with loaders like webpack to  figure out if you can use techniques like code splitting and dynamic import() to achieve the same lazy loading benefit that you get with esri-loader today.

Until then, you can think of esri-loader as the best stop-gap. The active fellowship of contributors to esri-loader will ensure that it is going to continue to evolve to meet the challenge of using the ArcGIS API for JavaScript in the ever shifting JavaScript landscape.