Using Bower (A package manager for the front-end web development) is another option for developers of the JavaScript API to generate custom builds of the ArcGIS API for JavaScript. You would use the Bower download of the ArcGIS API for JavaScript if you wanted to create local builds of your application. This is similar to what you can do with the JavaScript Optimizer but locally.
Note: See the prerequisites section on configuring your system before proceeding. If you system is already configured with Git, Node.js, Grunt.js, and Bower, you may proceed to the Getting Started section.
To check if these are installed:
$ node --version
$ git --version
$ grunt --version
$ bower --version
$ java -version
Tip: if you have issues with ssh on your machine, which is common on Windows or due to firewall settings, you
can tell git to use https
over ssh
.
git config --global url."https://github.com".insteadOf git://github.com
Now that your system is configured, it is time to make a decision on whether you are going to use the Dojo Toolkit or RequireJS.
Note: There are some limitations in choosing the RequireJS AMD loader over the Dojo AMD loader. The RequireJS loader is missing some methods that might be required at runtime, one of which is a cross-domain loader. You can view the provided Gruntfile for information on some build limitations. These mainly have to do with limitations in how the r.js optimizer performs builds.
Clone the jsapi-resources repository (code below) to your local machine or download the repository to your local machine.
git clone https://github.com/Esri/jsapi-resources.git
Bower requires Node.js so they naturally work
well together. In the Generate a custom build (dojo) and
Generate a custom build (requirejs) sections, you will be asked to issue a command
npm install
. You can read more about npm-scripts,
but essentially this tells node to download any dependencies
and/or devDependencies
listed
in the package.json
file. See
the package.json
file in the dojo or
require samples for more information.
The npm-scripts field in the package.json
file
is special in the fact that some of the named scripts such as install
have the option to run special
pre
and post
hooks. This is important because it allows you to perform operations before
or after a given command.
In our instance, we want to run the bower install
command on our preinstall
hook.
When using Bower, you can predefine what Bower packages you want to install via a file called bower.json
.
Take a look at the example below:
{
"name": "arcgis-js-api-sample-app",
"version": "1.0.0",
"dependencies": {
"esri": "arcgis-js-api#3.26.0"
},
"resolutions": {
"dojo": "v1.11.2/esri-3.18.0"
}
}
What this file is saying is that when you do bower install it will download version 3.26 of the ArcGIS API for JavaScript.
The default folder all Bower dependencies are downloaded to is called bower_components. Notice how we have a dependency called esri that is pointing the arcgis-js-api Bower package. This means it will name the folder esri that the Bower package is downloaded, so it will look like bower_components/esri.
The ArcGIS JS API package has some of its own predefined dependencies that will also be downloaded. This is why there is a resolution for the dojo dependency to use our version. You can see a list of the dependencies in the README for the Bower package. When everything is downloaded, you should have a folder structure that looks like this.
bower_components
├── dgrid
├── dijit
├── dojo
├── dojox
├── dstore
├── esri
├── moment
├── put-selector
├── util
└── xstyle
When you develop your application, you can set up your dojoConfig to point to these folders.
var dojoConfig = {
baseUrl: '.',
packages: [
{
name: 'dgrid',
location: 'bower_components/dgrid',
},
{
name: 'dijit',
location: 'bower_components/dijit',
},
{
name: 'dojo',
location: 'bower_components/dojo',
},
{
name: 'dojox',
location: 'bower_components/dojox',
},
{
name: 'dstore',
location: 'bower_components/dstore',
},
{
name: 'esri',
location: 'bower_components/esri',
},
{
name: 'put-selector',
location: 'bower_components/put-selector',
},
{
name: 'xstyle',
location: 'bower_components/xstyle',
}
]
};
Now you have full access to the ArcGIS API for JavaScript and its dependencies.
You could take this one step further and have the Bower packages installed into a different folder. Let's assume you are writing your application in a src/app folder. You can have the Bower packages downloaded into the src folder by default by creating a .bowerrc file in the root of your application that looks like this.
{
"directory":"src/"
}
When you do bower install it will download all the same packages into the src directory. This allows you to simplify your dojoConfig inside your src folder.
var dojoConfig = {
baseUrl: '.',
packages: [
'app',
'dijit',
'dojo',
'dojox',
'dstore',
'dgrid',
'xstyle',
'put-selector',
'esri'
]
};
This will make it easier to do local custom builds of your application.
Since Bower is run under the preinstall
hook of the npm-scripts
it precedes the install
script. So when you issue the command npm install
,
preinstall
runs first which is actually the command bower install
. Then npm install
runs
looking for dependencies listed in the package.json
file.
Npm will then download and install any dependencies listed in the
dependencies
and/or devDependencies
section in the package.json
file.
Finally, the npm install
sequence is where
Grunt
and the supporting plugins
grunt-contrib-clean
and
grunt-contrib-copy
are installed.
See the package.json file in the dojo or require samples for more information.
For both options (clone or download), you need to copy the source files from
PATH-TO-REPO/jsapi-resources/bower/dojo
to a new directory. In the following steps, we'll name the new directory esrijs-bower-dojo
.
The contents of your directory should appear as follows:
esrijs-bower-dojo
├── .bowerrc
├── Gruntfile.js
├── README.md
├── bower.json
├── build.profile.js
├── package.json
└── src
├── app
│ ├── main.js
│ ├── package.js
│ └── package.json
├── built.html
└── index.html
esrijs-bower-dojo
npm install
arcgis-js-api
will be downloaded by bowerarcgis-js-api
repository will be cached by bower and take less time to downloaddependencies
and/or devDependencies
will download via npm (Grunt plugins including grunt-dojo
)npm run build
and press return
npm run clean
and press return to delete the built applicationThe Dojo build system accepts a build configuration profile. A sample build profile is available in the Bower dojo sample in the jsapi-resources repository on GitHub. The key is to define your build packages, which you can learn more about in this AMD loader tutorial. In addition to packages, you should understand what a layer file is, which is essentially a single file that is composed of many modules and their dependencies.
layers: {
'dojo/dojo': {
boot: true,
customBase: true,
include: [
'app/main', // Your application entry point
'esri/dijit/Attribution' // a dynamically loaded module
]
},
// Note: As of 3.18 it is recommended that users create a separate
// built layer for the VectorTileLayer implementation module.
'esri/layers/VectorTileLayerImpl': {
include: [
'esri/layers/VectorTileLayerImpl'
]
}
}
This tells the Dojo build system to build the dojo/dojo.js
file and to include other files into it.
This will get you an optimized single-file that you can use to deploy your application.
Please see the sample build profile
for more details.
For both options (clone or download), you need to copy the source files from
PATH-TO-REPO/jsapi-resources/bower/requirejs
to your esrijs-bower-requirejs
directory.
The contents of your directory should appear as follows:
esrijs-bower-requirejs
├── .bowerrc
├── Gruntfile.js
├── README.md
├── bower.json
├── package.json
└── src
├── app
│ └── main.js
├── built.html
└── index.html
esrijs-bower-requirejs
npm install
arcgis-js-api
will be downloaded by bowerarcgis-js-api
repository will be cached by bower and take less time to downloaddependencies
and/or devDependencies
will download via npm (Grunt plugins including grunt-contrib-requirejs
and uglify-js
)npm run build
and press return
npm run clean
and press return to delete the built applicationThe RequireJS Optimizer has some limitations when trying to build some of the Esri and Dojo modules. What this means is that you can get pretty close to a single-file release; however, some modules will still need to be dynamically loaded.
Many of the issues related to using the RequireJS Optimizer have to do with how it handles loader plugins during the build process.
An example of a loader plugin is the dojo/has plugin, that can do conditional loading of modules. The RequireJS Optimizer will attempt to execute these plugins as it sees them in a module.
However, the RequireJS Optimizer by default runs in a Node environment and does not have JavaScript host objects such as document that may be used by a loader plugin. The Dojo build tools work around this issue. You can setup the build configuration to work around most of these use cases. You would need to tell the RequireJS Optimizer to ignore modules that will cause an error with loader plugins.
paths: {
'dojox/gfx': 'empty'
}
This is the syntax you would use to tell the RequireJS Optimizer to not load the module during the build process. Some Dojo plugins have RequireJS counterparts that can be swapped out during the build process, so you can do something like this.
paths: {
'dojo/text': 'text/text'
}
This syntax tells the RequireJS Optimizer to load the text/text
module in place of the dojo/text
module allowing your build to complete.
Attempting to build many modules into a single file may require a little trial and error. Some modules will attempt to dynamically load modules when they are needed, which means they are not picked up by the build process. If you notice some files dynamically loaded after you do a build, you can try and force them into your built file.
include: [
'esri/dijit/Attribution'
]
This syntax will tell the RequireJS Optimizer to add this module and its dependencies to your output file. You can find more details in the RequireJS build configuration file. Note that it is recommended that users also create a built file for the VectorTile implementation module as shown in the configuration file.