In places throughout this book, we've credited the full functionality that OpenLayers offers out of the box with its capacity to help build powerfully capable web-mapping applications. We've also been consciously aware of the fact that this well equipped capability comes with the price of a larger download size.
However, this recipe will show you how to construct a custom minified build of OpenLayers that will include only the code from the library that's fundamental for your specific application requirements.
To demonstrate this, we'll create a custom build, which is made suitable to run an earlier recipe from this book: Creating a simple full screen map in Chapter 1, Web Mapping Basics.
The source code for this recipe can be found in ch07/ch07-custom-openlayers-build.
The OpenLayers build tools has two dependencies that need to be installed on your machine: Node.js (https://nodejs.org) and Java 1.7 SDK (http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html). More recent versions of Java should be okay too.
We're going to perform the following steps from the command line. So, this is via Terminal on Mac or Linux or through the Command Prompt on Windows.
ch07/ch07-custom-openlayers-build:
cd ch07/ch07-custom-openlayers-build
npm package manager to install OpenLayers, which will contain all the necessary source files to construct a custom build, which creates the node_modules/openlayers directory on installation:
npm install openlayers
build-config.json), which will outline the customization of our own OpenLayers library build:{
"exports": [
"ol.Map",
"ol.View",
"ol.layer.Tile",
"ol.source.OSM",
"ol.control.defaults",
"ol.Collection#extend",
"ol.control.FullScreen"
],
"compile": {
"externs": [
"externs/oli.js",
"externs/olx.js"
],
"define": [
"goog.DEBUG=false",
"ol.ENABLE_DOM=false",
"ol.ENABLE_WEBGL=false",
"ol.ENABLE_PROJ4JS=false",
"ol.ENABLE_VECTOR=false",
"ol.ENABLE_IMAGE=false"
],
"compilation_level": "ADVANCED",
"output_wrapper": ";(function(){%output%})();",
"manage_closure_dependencies": true
}
}node:
node node_modules/openlayers/tasks/build.js build -config.json custom-ol3-build.min.js
The npm package manager is installed with Node.js by default (one of the dependencies listed in the Getting ready section of this recipe). When we run npm install openlayers, this downloads the latest version of OpenLayers from the npm registry (https://www.npmjs.com/package/openlayers) and places it inside the node_modules/openlayers local directory. This creates the node_modules directory if it doesn't already exist. This download of OpenLayers includes all the source files that are needed to run the custom build.
Before we explain the contents of the build configuration file that we just created, let's take another look at the application code:
var map = new ol.Map({
view: new ol.View({
center: [-15000, 6700000], zoom: 5
}),
layers: [
new ol.layer.Tile({source: new ol.source.OSM()})
],
controls: ol.control.defaults().extend([
new ol.control.FullScreen()
]), target: 'js-map'
});With this in mind, let's breakdown the configuration JSON into separate pieces for explanation, as follows:
"exports": [ "ol.Map", "ol.View", "ol.layer.Tile", "ol.source.OSM", "ol.control.defaults", "ol.Collection#extend", "ol.control.FullScreen" ],
The first property of the JSON object, namely exports, expects an array of strings. These strings specify the names (symbols) that your application code uses. These strings can also define patterns with the use of * and #. For example, "exports": ["*"] will include everything. However, you don't want to do this!
Most of the preceding exports will be self-explanatory from observing what's used in the JavaScript application code. However, it's worth picking up one particular entry that we have in this list, and this is "ol.Collection#extend".
In order to append our HTML5 fullscreen control to the map, we've extended the default list of controls, a list of the ol.Collection type. The ol.Collection class has a method called extend, which, by default, won't be included in our build even if we have an entry of "ol.Collection", as this entry will only export the namespace and constructor, not the prototype methods, such as extend.
To include this method, we use the # pattern to export just the extend method from ol.Collection. If we wanted all the methods, we can perform "ol.Collection#*".
"compile": {
"externs": [
"externs/oli.js",
"externs/olx.js"
],Next is the compile property, which accepts many properties and values other than the ones seen in this example. These options are for the Google Closure Compiler, the workhorse behind this build (the compiler that runs with Java).
The first property that we include is externs, which is for external names used in the code being compiled. OpenLayers documents that the inclusion of oli.js and olx.js are mandatory. You can find a list of all the available externs properties inside the node_modules/openlayers/externs directory.
"define": [ "goog.DEBUG=false", "ol.ENABLE_DOM=false", "ol.ENABLE_WEBGL=false", "ol.ENABLE_PROJ4JS=false", "ol.ENABLE_VECTOR=false", "ol.ENABLE_IMAGE=false" ],
The define property lists some constants that will be used at compile time. This is an opportunity to customize the final output of the build. For us, we exclude as much code as possible to meet our needs and reduce the size of the file.
We are using the default canvas renderer for our map, so we exclude the DOM and WebGL renderers. We are not performing any projection transformations, so we exclude Proj4js integration too. We're also not using vector layers or image layers, so they're excluded as well. There are more feature toggles that are available, and we encourage you to search through the compiled debug version of OpenLayers to discover others that may be of interest.
"compilation_level": "ADVANCED",
"output_wrapper": ";(function(){%output%})();",
"manage_closure_dependencies": trueFinally, we assign values to three other properties. First, use the most advanced compilation from Google Closure Compiler (this keeps our code nice and minified). Second, specify the JavaScript that wraps the compiled code. Third, ensure that closure dependencies are managed (this is recommended by OpenLayers).
With all this configuration in place, it's time to trigger the build, as follows:
node node_modules/openlayers/tasks/build.js build-config.json custom -ol3-build.min.js
The line begins with node, which is the program used to execute the file (build.js) passed in as the first argument: node_modules/openlayers/tasks/build.js.
The second argument points to our custom build configuration file (build-config.json), which is where we've specified the options for the compiler.
The third argument is for the destination of the compiled JavaScript. If this file doesn't exist, it'll be created for us.
It may take a moment to run, but once this has completed the build, we'll have a new file, namely custom-ol3-build.min.js, that we can reference from our HTML file.
If you take a look at the normal size of the full OpenLayers library (node_modules/openlayers/dist/ol.js), it weighs in at about half a megabyte. However, our custom build weighs in at 109 KB. This is a considerably lower file size, and well worth the extra effort, especially when supporting mobile devices.
For the majority of custom builds, modifications to the preceding configuration file properties listed will suffice. However, for full control of the range of compiler options at your fingertips, visit https://github.com/openlayers/closure-util/blob/master/compiler-options.txt for more information.
OpenLayers also has some good documentation of the configuration file and related tasks. If you'd like some extra reading to understand the different sections of config better, then visit https://github.com/openlayers/ol3/blob/master/tasks/readme.md.