`
20 | },
21 | outFields: ['Station_Na', 'Street_Add', 'City', 'State', 'ZIP', 'Fuel_Type', 'Station_Ph', 'Groups_Wit', 'Access_Day']
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/src/app/SidePanel.js:
--------------------------------------------------------------------------------
1 | // NOTE: using jQuery global intead of importing
2 | // because it is included it in vendor.js
3 | // and we don't want it bundled with our application code
4 | /* global $:false */
5 | import declare from 'dojo/_base/declare';
6 | import _WidgetBase from 'dijit/_WidgetBase';
7 | import _TemplatedMixin from 'dijit/_TemplatedMixin';
8 | // NOTE: we're using Rollup's string plugin to load
9 | // the template which will be inlined into the build output
10 | import template from './templates/SidePanel.html';
11 | import strings from 'dojo/i18n!./nls/strings';
12 |
13 | export default declare([_WidgetBase, _TemplatedMixin], {
14 |
15 | baseClass: 'side-panel',
16 | nls: strings,
17 | templateString: template,
18 |
19 | // set panel header title
20 | _setTitleAttr: { node: 'titleNode', type: 'innerHTML' },
21 |
22 | // wire up events
23 | postCreate () {
24 | this.inherited(arguments);
25 | let domNodeId = '#' + this.domNode.id;
26 | // update chevron icon when panel collapses/expands
27 | $(domNodeId + ' .collapse').on('hide.bs.collapse show.bs.collapse', () => {
28 | $(domNodeId + ' .panel-title .glyphicon').toggleClass('glyphicon-chevron-up glyphicon-chevron-down');
29 | });
30 | }
31 | });
32 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Esri Rollup Example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
25 |
26 |
27 |
28 |
29 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/app/mapService.js:
--------------------------------------------------------------------------------
1 | import declare from 'dojo/_base/declare';
2 | import Map from 'esri/Map';
3 | import MapView from 'esri/views/MapView';
4 | import FeatureLayer from 'esri/layers/FeatureLayer';
5 | import BasemapToggle from 'esri/widgets/BasemapToggle';
6 | import BasemapToggleVM from 'esri/widgets/BasemapToggle/BasemapToggleViewModel';
7 |
8 | // define a stateful service to manage the map
9 | const MapService = declare([], {
10 | // create a map and map view
11 | init: function (options) {
12 | this.map = new Map({
13 | basemap: options.basemap
14 | });
15 | delete options.basemap;
16 | options.map = this.map;
17 | this.view = new MapView(options);
18 | },
19 |
20 | createBasemapToggle (node, secondaryBasemap) {
21 | if (!node || !secondaryBasemap || !this.view) {
22 | return;
23 | }
24 |
25 | return new BasemapToggle({
26 | // Setting widget properties via viewModel is subject to
27 | // change for the 4.0 final release
28 | viewModel: new BasemapToggleVM({
29 | view: this.view,
30 | secondaryBasemap: secondaryBasemap
31 | })
32 | }, node);
33 | },
34 |
35 | // add a feature layer to the map
36 | addFeatureLayer: function (props) {
37 | if (!this.map) {
38 | return;
39 | }
40 |
41 | const featureLayer = new FeatureLayer(props);
42 | this.map.add(featureLayer);
43 | return featureLayer;
44 | }
45 | });
46 |
47 | // return a singleton instance of this service
48 | if (!_instance) {
49 | var _instance = new MapService();
50 | }
51 | export default _instance;
52 |
--------------------------------------------------------------------------------
/src/app/App.js:
--------------------------------------------------------------------------------
1 | import declare from 'dojo/_base/declare';
2 | import _WidgetBase from 'dijit/_WidgetBase';
3 | import _TemplatedMixin from 'dijit/_TemplatedMixin';
4 | import config from './config';
5 | import mapService from './mapService';
6 | import SidePanel from './SidePanel';
7 | import { formatTitle } from './utils';
8 |
9 | export default declare([_WidgetBase, _TemplatedMixin], {
10 |
11 | baseClass: 'app',
12 | // using an inline template
13 | templateString: `
14 |
15 |
16 |
17 |
18 |
19 |
20 | `,
21 |
22 | // kick off app once this component has been created
23 | postCreate () {
24 | this.inherited(arguments);
25 |
26 | // initialize map
27 | config.mapProps.container = this.mapNode;
28 | mapService.init(config.mapProps);
29 |
30 | // initialize side panel
31 | this.sidePanel = new SidePanel({}, this.sidePanelNode);
32 |
33 | // initialize the basemap toggle
34 | this.basemapToggle = mapService.createBasemapToggle(this.basemapToggleNode, config.secondaryBasemap);
35 |
36 | // add feature layer and once loaded
37 | // set side title of side panel
38 | mapService.addFeatureLayer(config.fuelingStationLayerProps).then(layer => {
39 | this.sidePanel.set('title', formatTitle(layer.title || layer.name));
40 | });
41 | },
42 |
43 | // you gotta start me up
44 | startup () {
45 | this.sidePanel.startup();
46 | this.basemapToggle.startup();
47 | }
48 | });
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "esri-rollup-example",
3 | "version": "0.1.10",
4 | "description": "Example application using Rollup to bundle local ES2015 modules that use CDN hosted modules from the ArcGIS API for JavaScript",
5 | "main": "src/main.js",
6 | "dependencies": {
7 | "lodash-es": "^4.11.1"
8 | },
9 | "devDependencies": {
10 | "babel-plugin-external-helpers": "^6.8.0",
11 | "babel-preset-es2015": "^6.16.0",
12 | "browser-sync": "^2.12.3",
13 | "calcite-bootstrap": "^0.3.2",
14 | "del": "^2.2.0",
15 | "gulp": "^3.9.1",
16 | "gulp-concat": "^2.6.0",
17 | "gulp-debug": "^2.1.2",
18 | "gulp-gh-pages": "^0.5.4",
19 | "gulp-if": "^2.0.0",
20 | "gulp-load-plugins": "^1.2.1",
21 | "gulp-rename": "^1.2.2",
22 | "gulp-sass": "^2.2.0",
23 | "gulp-semistandard": "^1.0.0",
24 | "gulp-size": "^2.1.0",
25 | "gulp-sourcemaps": "^2.1.1",
26 | "gulp-uglify": "^2.0.0",
27 | "jquery": "^2.2.3",
28 | "rollup": "^0.36.3",
29 | "rollup-plugin-babel": "^2.6.1",
30 | "rollup-plugin-string": "^2.0.2",
31 | "rollup-plugin-uglify": "^1.0.1",
32 | "semistandard": "^9.1.0"
33 | },
34 | "scripts": {
35 | "test": "gulp test",
36 | "build": "gulp",
37 | "start": "gulp serve"
38 | },
39 | "keywords": [
40 | "ArcGIS",
41 | "JavaScript",
42 | "Rollup"
43 | ],
44 | "author": "Tom Wayson ",
45 | "license": "MIT",
46 | "repository": {
47 | "type": "git",
48 | "url": "git+https://github.com/tomwayson/esri-rollup-example.git"
49 | },
50 | "bugs": {
51 | "url": "https://github.com/tomwayson/esri-rollup-example/issues"
52 | },
53 | "homepage": "https://github.com/tomwayson/esri-rollup-example#readme"
54 | }
55 |
--------------------------------------------------------------------------------
/src/styles/_appstrap.scss:
--------------------------------------------------------------------------------
1 | // NOTE: copied from:
2 | // ./node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss
3 | // and commented out unused modules
4 |
5 | // TODO: uncomment as needed when adding modules
6 |
7 | // Core variables and mixins
8 | @import "bootstrap/variables";
9 | @import "bootstrap/mixins";
10 |
11 | // Reset and dependencies
12 | @import "bootstrap/normalize";
13 | @import "bootstrap/print";
14 | @import "bootstrap/glyphicons";
15 |
16 | // Core CSS
17 | @import "bootstrap/scaffolding";
18 | @import "bootstrap/type";
19 | @import "bootstrap/code";
20 | @import "bootstrap/grid";
21 | @import "bootstrap/tables";
22 | @import "bootstrap/forms";
23 | @import "bootstrap/buttons";
24 |
25 | // Components
26 | @import "bootstrap/component-animations";
27 | @import "bootstrap/dropdowns";
28 | // @import "bootstrap/button-groups";
29 | // @import "bootstrap/input-groups";
30 | // @import "bootstrap/navs";
31 | // @import "bootstrap/navbar";
32 | // @import "bootstrap/breadcrumbs";
33 | // @import "bootstrap/pagination";
34 | // @import "bootstrap/pager";
35 | // @import "bootstrap/labels";
36 | // @import "bootstrap/badges";
37 | // @import "bootstrap/jumbotron";
38 | // @import "bootstrap/thumbnails";
39 | // @import "bootstrap/alerts";
40 | // @import "bootstrap/progress-bars";
41 | // @import "bootstrap/media";
42 | // @import "bootstrap/list-group";
43 | @import "bootstrap/panels";
44 | // @import "bootstrap/responsive-embed";
45 | // @import "bootstrap/wells";
46 | // @import "bootstrap/close";
47 |
48 | // Components w/ JavaScript
49 | // @import "bootstrap/modals";
50 | // @import "bootstrap/tooltip";
51 | // @import "bootstrap/popovers";
52 | // @import "bootstrap/carousel";
53 |
54 | // Utility classes
55 | // @import "bootstrap/utilities";
56 | // @import "bootstrap/responsive-utilities";
57 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Esri Rollup Example Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## Unreleased
6 | ## v0.1.9
7 | ### Support
8 | - bump dependencies, add repo to package.json
9 |
10 | ## v0.1.9
11 | ### Changed
12 | - using Rollup to uglify source and generate sourcemaps
13 | - update to JSAPI 4.0
14 | - update to latest rollup and rollup-plugin-uglify to fix build errors
15 |
16 | ### Support
17 | - only bundle app, startup app in index, drop main
18 |
19 | ## v0.1.8
20 |
21 | ### Changed
22 | - only bundle app, startup app in index, drop main
23 |
24 | ## v0.1.7
25 |
26 | ### Added
27 | - added missing `this.inherited(arguments)` to side panel widget
28 |
29 | ### Support
30 | - Use Rollup's `useStrict: false` option instead of gulp-replace on the bundled output.
31 |
32 | ## v0.1.6
33 |
34 | ### Added
35 | - importing capitalize() from ES2015 build of lodash
36 |
37 | ### Support
38 | - better sourcemaps (not inlined)
39 |
40 | ## v0.1.5
41 |
42 | ### Changed
43 | - only include the bootstrap components used by the app
44 |
45 | ## v0.1.4
46 |
47 | ### Added
48 | - added chevron icon to collapsing panel and dynamically update (up/down) using jQuery global
49 |
50 | ### Support
51 | - lint bfore script tasks in live reload
52 |
53 | ## v0.1.3
54 |
55 | ### Added
56 | - added bootstrap JS and jquery for collapsing panel
57 |
58 | ## v0.1.2
59 |
60 | ### Changed
61 | - copy vendor fonts to dist before serving
62 |
63 | ## v0.1.1
64 |
65 | ### Added
66 | added Sass and loading Calcite Bootstrap via Sass
67 |
68 | ### Changed
69 | - minor tweaks to and comments for gulp tasks
70 | - minor tweaks to README
71 |
72 | ## v0.1.0
73 |
74 | ### Added
75 | - added gh-pages deploy
76 | - added gulp build
77 |
78 | ## v0.0.8
79 |
80 | ### Changed
81 | - fleshed out README
82 |
83 | ### Added
84 | - added basemap toggle
85 | - added CHANGELOG
86 |
87 | ## v0.0.7
88 |
89 | ### Added
90 | - re-build whenever src changes
91 |
92 | ## v0.0.6
93 |
94 | ### Changed
95 | - using JSAPI v4 Beta 3 instead of v3.16
96 | - map service can add layer and manages map state
97 |
98 | ## v0.0.5
99 |
100 | ### Added
101 | - added calcite bootstrap and side panel widget
102 |
103 | ## v0.0.4
104 |
105 | ### Added
106 | - added linting w/ semistandard
107 |
108 | ### Added
109 | - added a custom dijit to show current time
110 |
111 | ## v0.0.3
112 |
113 | ### Added
114 | - minify bundled output
115 |
116 | ## v0.0.2
117 |
118 | ### Changed
119 | - babel actually transpiles
120 |
121 | ### Added
122 | - added a custom dijit to show current time
123 |
124 | ## v0.0.1
125 |
126 | ### Added
127 | - first working rollup build!
128 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gulpLoadPlugins = require('gulp-load-plugins');
3 | var del = require('del');
4 | var rollup = require('rollup').rollup;
5 | var rollupBabel = require('rollup-plugin-babel');
6 | var rollupString = require('rollup-plugin-string');
7 | var rollupUglify = require('rollup-plugin-uglify');
8 | var browserSync = require('browser-sync');
9 | var ghPages = require('gulp-gh-pages');
10 |
11 | var $ = gulpLoadPlugins();
12 | var reload = browserSync.reload;
13 |
14 | // NOTE: to debug any task add .pipe($.debug()) after the .src()
15 |
16 | // clean output and temp directories
17 | gulp.task('clean', del.bind(null, ['dist']));
18 |
19 | // lint source files
20 | gulp.task('lint', function () {
21 | return gulp.src(['./src/app/**/*.js'])
22 | .pipe($.semistandard())
23 | .pipe($.semistandard.reporter('default', {
24 | breakOnError: !browserSync.active
25 | }));
26 | });
27 |
28 | // bunlde, minify, and generate sourcemaps
29 | // for app scripts using rollup
30 | gulp.task('scripts:app', function () {
31 | return rollup({
32 | entry: 'src/app/App.js',
33 | plugins: [
34 | // compile future ES 2015 to runnable ES 5
35 | rollupBabel({
36 | runtimeHelpers: true,
37 | // don't compile templates
38 | exclude: 'src/app/templates/**'
39 | }),
40 | // load templates from files
41 | rollupString({
42 | include: ['**/*.html']
43 | }),
44 | // minify output
45 | rollupUglify()
46 | ]
47 | }).then(function (bundle) {
48 | return bundle.write({
49 | // include sourcemaps to ES2015 files
50 | sourceMap: true,
51 | // Dojo friendly output options
52 | format: 'amd',
53 | useStrict: false,
54 | dest: 'dist/app/App.min.js'
55 | });
56 | });
57 | });
58 |
59 | // copy nls files to dist
60 | gulp.task('scripts:nls', function () {
61 | return gulp.src('./src/app/nls/**/*.js')
62 | .pipe(gulp.dest('./dist/app/nls'));
63 | });
64 |
65 | // concatenate vendor scripts and minify (as needed)
66 | gulp.task('scripts:vendor', function () {
67 | return gulp.src([
68 | './node_modules/jquery/dist/jquery.js',
69 | // NOTE: include other bootstrap components here as needed
70 | './node_modules/bootstrap-sass/assets/javascripts/bootstrap/transition.js',
71 | './node_modules/bootstrap-sass/assets/javascripts/bootstrap/collapse.js'
72 | ])
73 | .pipe($.sourcemaps.init())
74 | .pipe($.concat('vendor.js'))
75 | .pipe(gulp.dest('dist/vendor'))
76 | // also include minified output
77 | .pipe($.uglify())
78 | .pipe($.rename({ suffix: '.min' }))
79 | .pipe($.sourcemaps.write('.'))
80 | .pipe(gulp.dest('dist/vendor'));
81 | });
82 |
83 | // copy fonts from vendor dependencies
84 | gulp.task('fonts', function () {
85 | return gulp.src('./node_modules/bootstrap-sass/assets/fonts/bootstrap/**/*.{eot,svg,ttf,woff,woff2}')
86 | .pipe(gulp.dest('dist/styles/fonts'));
87 | });
88 |
89 | // styles: compile Sass styles to CSS
90 | // TODO: may want to add autoprefixer
91 | // or need to add plumber to handle errors
92 | gulp.task('styles', function () {
93 | return gulp.src('./src/styles/main.scss')
94 | // .pipe($.plumber())
95 | .pipe($.sourcemaps.init())
96 | .pipe($.sass.sync({
97 | outputStyle: 'expanded',
98 | precision: 10,
99 | includePaths: [
100 | '.',
101 | './node_modules/bootstrap-sass/assets/stylesheets',
102 | './node_modules/calcite-bootstrap/dist/sass'
103 | ]
104 | })) // .on('error', $.sass.logError))
105 | // .pipe($.autoprefixer({browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']}))
106 | .pipe($.sourcemaps.write('.'))
107 | .pipe(gulp.dest('./dist/styles'));
108 | });
109 |
110 | // html: for now just copying
111 | // later may want to transform/minify
112 | gulp.task('html', function () {
113 | return gulp.src('./src/*.html')
114 | .pipe(gulp.dest('./dist'));
115 | });
116 |
117 | // build, copy to dist, and size'r up
118 | gulp.task('build', ['lint', 'fonts', 'scripts:vendor', 'scripts:nls', 'scripts:app', 'styles', 'html'], function () {
119 | return gulp.src('dist/**/*').pipe($.size({
120 | title: 'build',
121 | gzip: true,
122 | showFiles: true
123 | }));
124 | });
125 |
126 | // serve up the built application
127 | // and live-reload whenever files change
128 | gulp.task('serve:dist', ['build'], function () {
129 | // serve build output files
130 | browserSync({
131 | notify: false,
132 | port: 9000,
133 | server: {
134 | baseDir: ['dist']
135 | }
136 | });
137 |
138 | // reload whenever output files updated
139 | gulp.watch([
140 | 'dist/**/*'
141 | ]).on('change', reload);
142 |
143 | // update output files when source files change
144 | gulp.watch('./src/styles/*.scss', ['styles']);
145 | gulp.watch('./src/app/nls/**/*.*', ['lint', 'scripts:nls']);
146 | gulp.watch(['./src/app/**/*.*', '!./src/app/nls/**/*.*'], ['lint', 'scripts:app']);
147 | gulp.watch('./src/*.html', ['html']);
148 | });
149 |
150 | // remove old files then serve the built application
151 | gulp.task('serve', ['clean'], function () {
152 | gulp.start('serve:dist');
153 | });
154 |
155 | // test: for now just lint
156 | // TODO: add tests
157 | gulp.task('test', ['lint']);
158 |
159 | // deploy to github pages
160 | gulp.task('deploy', ['build'], function () {
161 | return gulp.src('./dist/**/*')
162 | .pipe(ghPages());
163 | });
164 |
165 | // clean dist and run build
166 | gulp.task('default', ['clean'], function () {
167 | gulp.start('build');
168 | });
169 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Esri Rollup Example
2 |
3 | **UPDATE**: This technique demonstrated in this repository will work, but you should probably just use [esri-loader](https://github.com/Esri/esri-loader/). Read this [blog post](http://tomwayson.com/2018/01/05/loader-of-the-things-one-library-to-load-them-all/) to find out why.
4 |
5 | ## Life's Too $hort to Use Dojo Build TM
6 |
7 | **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].**
8 |
9 | This is an example application using [Rollup] to bundle local ES2015 modules that use CDN hosted modules from the [ArcGIS API for JavaScript].
10 |
11 | You can view the site created by this repo [live](http://tomwayson.github.io/esri-rollup-example/), and see the (unminified) [bundled source code](http://tomwayson.github.io/esri-rollup-example/app/bundle.js).
12 |
13 | 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](https://github.com/rollup/rollup/wiki/Build-tools). Earlier versions of the application simply [used npm scripts as a build tool](https://github.com/tomwayson/esri-rollup-example/blob/v0.0.8/package.json#L17-L21).
14 |
15 | ## Getting started
16 |
17 | 1. Clone/download this repository
18 | 2. `cd` into the repository root folder and run
19 | `npm install && npm start`
20 | 3. Make some changes to the source code and the browser will live reload the newly built code
21 |
22 | ## Why?
23 |
24 | 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](https://github.com/odoe/generator-arcgis-js-app/issues/11). 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](https://jso.arcgis.com/) and wonder why part of your build process involves visiting a web site?
25 |
26 | 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!
27 |
28 | ### Known benefits
29 | * ~10 million times faster than a Dojo build - something that can be used with live reload!
30 | * No need to bower install half the Internet (i.e. all of Dojo and the [ArcGIS API for JavaScript])
31 | * No _need_ for bower at all, use either npm or bower, or both, or neither! I'd rather not know about how you handle other people's packages.
32 | * No longer dependent on [grunt-dojo](https://www.npmjs.com/package/grunt-dojo), so use whatever build system you prefer: [Gulp], [npm scripts](http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/), or [Grunt](https://github.com/chrisprice/grunt-rollup) - I ain't mad atcha!
33 | * Develop and test off your _built_ code
34 | * Your users' browsers may already have the CDN build of the [ArcGIS API for JavaScript] cached
35 |
36 | ### Potential benefits
37 | These have not (yet) been tested:
38 | * Use other component frameworks ([React](https://github.com/odoe/esrijs4-vm-react), [Web Components](https://github.com/patrickarlt/custom-elements-dev-summit-2016)) and/or UI library ([Bootstrap]) instead of Dijit, again, I'm not mad at you
39 |
40 | ## What's the catch?
41 |
42 | 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!
43 |
44 | ### Known limitations
45 | * Any code to be included in the bundle must use ES2015 imports/exports
46 | * Your app code should be written in ES2015 or [TypeScript](https://github.com/rollup/rollup-plugin-typescript)
47 | * You probably won't be be able to use this with a pre-existing AMD app without something like [amd-to-as6](https://github.com/jonbretman/amd-to-as6)
48 | * See below for options on [handling third party dependencies](#handling-third-party-dependencies)
49 | * Can't use `dojo/text` plugin (but you can [use Rollup's](https://github.com/tomwayson/esri-rollup-example/blob/4bd1b8819b36a009b70f02ba1e0eb82025f072c7/src/SidePanel.js#L4-L6), or [ES2015 template literals](https://github.com/tomwayson/esri-rollup-example/blob/e7f239c5e042ba2fc68d40093a10aa01a6176585/src/app/App.js#L13-L20))
50 | * Can't inline i18n bundles, but you _can_ [use `dojo/i18n`](https://github.com/tomwayson/esri-rollup-example/blob/4bd1b8819b36a009b70f02ba1e0eb82025f072c7/src/SidePanel.js#L7)!
51 | * Build output is a single AMD module, not a Dojo build layer, so sub modules are not exposed. This should be fine when building apps, but is probably not suitable for building libraries.
52 |
53 | ### Caveats
54 | * Hasn't been used in a production application yet (help me fix that!), so not sure how it scales.
55 | * This is not an [official build solution from Esri](https://developers.arcgis.com/javascript/jshelp/inside_bower_custom_builds.html), so support means [people helping people](https://github.com/tomwayson/esri-rollup-example/issues).
56 |
57 | ## How does it work?
58 |
59 | 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.
60 |
61 | ```bash
62 | $ rollup -c rollup-config.js
63 | Treating 'dojo/_base/declare' as external dependency
64 | Treating 'dijit/_WidgetBase' as external dependency
65 | Treating 'dijit/_TemplatedMixin' as external dependency
66 | Treating 'dojo/_base/declare' as external dependency
67 | Treating 'esri/Map' as external dependency
68 | Treating 'esri/views/MapView' as external dependency
69 | Treating 'esri/layers/FeatureLayer' as external dependency
70 | Treating 'esri/widgets/BasemapToggle' as external dependency
71 | Treating 'esri/widgets/BasemapToggle/BasemapToggleViewModel' as external dependency
72 | Treating 'dojo/_base/declare' as external dependency
73 | Treating 'dijit/_WidgetBase' as external dependency
74 | Treating 'dijit/_TemplatedMixin' as external dependency
75 | Treating 'dojo/i18n!./nls/strings' as external dependency
76 | ```
77 |
78 | Rollup's so smart. We didn't even need to tell it to ignore those modules.
79 |
80 | 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:
81 |
82 | ```js
83 | // index.html
84 | require(['app/bundle']);
85 | ```
86 |
87 | ## Handling Third Party Dependencies
88 |
89 | As with the Dojo build you have a few options for how to handle third party libraries.
90 |
91 | ### ES2015 imports/exports
92 |
93 | 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](https://www.npmjs.com/package/lodash-es), you can [use import statements from your application modules](https://github.com/rollup/rollup-plugin-typescript) and Rollup will try include only the code (down to the function level) required by your application, a process called [tree shaking](https://medium.com/@Rich_Harris/tree-shaking-versus-dead-code-elimination-d3765df85c80).
94 |
95 | ### Globals
96 |
97 | 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](https://github.com/tomwayson/esri-rollup-example/blob/84b0c433ab37ceca860df2c72b3c412501e7bb97/src/index.html#L26). If using the latter, it is best to first [concatenate all local scripts into a single minified file (vendor.js)](https://github.com/tomwayson/esri-rollup-example/blob/84b0c433ab37ceca860df2c72b3c412501e7bb97/gulpfile.js#L73-L88). 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).
98 |
99 | ### AMD
100 |
101 | If a library only exposes AMD modules and no global (for example [Dojo Bootstrap](http://xsokev.github.io/Dojo-Bootstrap/) or [dojox.charting](https://dojotoolkit.org/reference-guide/1.10/dojox/charting.html)), 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.
102 |
103 | ### Considering your choices
104 |
105 | Tree shaking sounds great on paper, but it is [far from perfect](https://github.com/rollup/rollup/issues/45#issuecomment-168127982). 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](http://tomwayson.github.io/esri-rollup-example/app/bundle.js). 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.
106 |
107 | 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](http://c3js.org/). Branch out, see how the other half lives.
108 |
109 | ## FAQ
110 | * When should I use this?
111 | * Best suited for developing **new** web **apps** with the [ArcGIS API for JavaScript] with modern tools without the hassles of the Dojo build
112 | * When should I not use this?
113 | * Not suitable for apps that are written in ES5 or use a lot of Dijit and Dojox.
114 | * What versions of the [ArcGIS API for JavaScript] can I use with this?
115 | * This has been tested with v3.16 and v4.0 Beta 3
116 | * Should I use the compact build?
117 | * Depends. You should use the [compact build](https://developers.arcgis.com/javascript/jshelp/intro_accessapi.html#compact-build) unless you are going to use modules that aren't included in it (i.e. `esri/dijit/...`), in which case you should use the full build
118 | * Shouldn't I be able to do the same thing with [webpack](https://webpack.github.io/)?
119 | * Go for it. You can [start here](https://github.com/tomwayson/esri-webpack/tree/es2015). Let me know how that works out for ya.
120 | * I used to (twitter/facebook/read War and Peace/prep for the Bar exam/crochet) while I was waiting for the Dojo build to finish, when can I do that now?
121 | * Now you can spend time on your hobbies after you've shipped!
122 |
123 | Look how happy you could be if you were using Rollup.
124 |
125 | [](https://www.youtube.com/watch?v=UhQz-0QVmQ0)
126 |
127 | [Rollup]:http://rollupjs.org
128 | [ArcGIS API for JavaScript]:https://developers.arcgis.com/javascript/
129 | [Gulp]:http://gulpjs.com/
130 | [Bootstrap]:http://getbootstrap.com/
131 |
--------------------------------------------------------------------------------