UPDATE: This technique demonstrated in this repository will work, but you should probably just use esri-loader. Read this blog post to find out why.
TLDR: An example of a fast, flexible, modern way for you to build just your application code locally while using the CDN hosted builds of the ArcGIS API for JavaScript.
This is an example application using Rollup to bundle local ES2015 modules that use CDN hosted modules from the ArcGIS API for JavaScript.
You can view the site created by this repo live, and see the (unminified) bundled source code.
This example application also uses Gulp to minify the bundled code and manage static assets, but you can use Rollup with whatever build system you prefer. Earlier versions of the application simply used npm scripts as a build tool.
cd
into the repository root folder and run
npm install && npm start
Ever waited minutes for a Dojo build only to have it fail? If not, you're doing it wrong. Ever not been able to figure out why it failed? I have. Even when a Dojo build does work, have you ever looked at the size of the optimized output and realize that you saved exactly 0 bytes over the size of the compact build? There's 4 hours of your life you'll never get back. Ever used the Web Optimizer and wonder why part of your build process involves visiting a web site?
If you're like me, you're fed up with all that. It's time we respect ourselves and take back our valuable time. Esri's already done the Dojo builds for us and left them on a CDN. We should be able to pull in any of those and just build our own application code. Now with Rollup, it looks like we can. Even better, we can do so in a fast, flexible, and modern way!
These have not (yet) been tested:
Too good to be true? There a few known limitations that you should understand. However, there are workarounds that might work for you. They work for me!
dojo/text
plugin (but you can use Rollup's, or ES2015 template literals)dojo/i18n
!This approach relies on default behavior of Rollup to ignore modules that it can't resolve (i.e. anything in the esri
or dojo
packages) and only bundle our application code into a single AMD module.
$ rollup -c rollup-config.js
Treating 'dojo/_base/declare' as external dependency
Treating 'dijit/_WidgetBase' as external dependency
Treating 'dijit/_TemplatedMixin' as external dependency
Treating 'dojo/_base/declare' as external dependency
Treating 'esri/Map' as external dependency
Treating 'esri/views/MapView' as external dependency
Treating 'esri/layers/FeatureLayer' as external dependency
Treating 'esri/widgets/BasemapToggle' as external dependency
Treating 'esri/widgets/BasemapToggle/BasemapToggleViewModel' as external dependency
Treating 'dojo/_base/declare' as external dependency
Treating 'dijit/_WidgetBase' as external dependency
Treating 'dijit/_TemplatedMixin' as external dependency
Treating 'dojo/i18n!./nls/strings' as external dependency
Rollup's so smart. We didn't even need to tell it to ignore those modules.
We can then use the Dojo loader that is included in the ArcGIS API for JavaScript to load and run the bundled output like so:
// index.html
require(['app/bundle']);
As with the Dojo build you have a few options for how to handle third party libraries.
As stated above, any code to be included in the bundle must use ES2015 imports/exports. If you have a dependency that is written in ES2015, such as lodash-es, you can use import statements from your application modules and Rollup will try include only the code (down to the function level) required by your application, a process called tree shaking.
If a library exposes a global (such as $
, _
, d3
, etc), you can just use the global in your code (no one will get hurt, I promise). You can load the library on the page by including a script tag pointing to either a CDN or a local file. If using the latter, it is best to first concatenate all local scripts into a single minified file (vendor.js). I find that most of the libraries I use expose a global, and sometimes I'll use those even with a Dojo build (just to reduce the chances of build errors).
If a library only exposes AMD modules and no global (for example Dojo Bootstrap or dojox.charting), then unfortunately there's no good way to include that library in this build process. You can still use the library in your application by defining a dojoConfig package that points to either the CDN or local path to the library, but the modules will be loaded asynchronously at runtime.
Tree shaking sounds great on paper, but it is far from perfect. I have it working in this example app, but even just pulling in one function (along w/ all of the code Rollup thought might be needed by that function) the bundle starts to get a little cluttered. You can imagine how cluttered the bundle could get if you have a lot of dependencies. In a real app, I'd probably bring in a custom build of lodash as a global.
Obviously the Dojo build is much better than Rollup at handling AMD-only libraries. That said, I can't think of a single AMD-only library that is better than non-AMD equivalents. Need Bootstrap? Use jQuery. Need charts? Use C3. Branch out, see how the other half lives.
esri/dijit/...
), in which case you should use the full buildLook how happy you could be if you were using Rollup.