Note: When building an application with dependencies that are available as npm packages, it will probably be easier to use the ol package and follow the instructions there.
The OpenLayers code uses the Closure Library, and it is compiled with the Closure Compiler. Using OpenLayers in an application does not require using Closure. But using Closure in an OpenLayers application is possible. And this is what this tutorial is about.
When you want to include OpenLayers as separate script without bundling with your application, follow the Creating custom builds tutorial instead.
This tutorial will teach you how to set up an OpenLayers application based on
the closure-util
node package,
which provides utilities for working with Closure. Using closure-util
is one
way to use Closure in a web application, but there are others. This tutorial
just covers the "closure-util
" way.
The closure-util
documentation is available on the closure-util
readme
page. You
don't need to read the closure-util
documentation to follow this tutorial,
but it's available in closure-util
's readme
file if you
need it.
Also, the sample application built in this tutorial is available on GitHub.
This tutorial will show you how to use the Closure Compiler to compile an application and OpenLayers together. Compiling the application code together with the OpenLayers code has a number of advantages.
First of all, it allows you to only "pay" for the OpenLayers code your application uses, as the compiler will exclude the OpenLayers code that the application doesn't use. And there is no need to write and maintain a list of "exports", which is necessary when creating custom builds of OpenLayers.
Also, compiling the application and OpenLayers together allows using OpenLayers functions and objects that are not part of the official OpenLayers 3 API. Using non-API functions and objects may be risky, but it is mitigated by the fact that the compiler will complain if you use functions or objects that are not in OpenLayers anymore.
First, create a directory for the application. We will name that directory
openlayers-closure-application
in this tutorial.
$ mkdir openlayers-closure-application
Now change to that directory:
$ cd openlayers-closure-application
Our application will be a node
application, and the openlayers
and
closure-util
node packages will be downloaded from the node package registry
using the npm
command line tool.
So we're going to create a package.json
file for the application, which every
node application includes. This file basically includes metadata for the
application.
Create the application's package.json
file:
$ npm init
You can pretty much use the default answers to the questions npm init
asks
you.
Now install OpenLayers using:
$ npm install openlayers --save
The --save
flag persists the openlayers
dependency in the application's
package.json
file. You can edit package.json
to verify that the dependency
was added.
closure-util
is a dependency of the openlayers
package, so it should have
been installed with openlayers
. Use the following to verify that
closure-util
is installed:
$ ./node_modules/openlayers/node_modules/.bin/closure-util
command argument is required
Usage: node closure-util <command> [options]
command
update-compiler Update the Compiler
update-library Update the Library
update Update both the Library and the Compiler
build Build with Closure Compiler
serve Start the development server
Options:
-l LEVEL, --loglevel LEVEL Log level [info]
You're now going to create a JavaScript file that creates an OpenLayers map. This is the file that we will define the application's entry point.
First of all create an src
directory at the root of the application:
$ mkdir src
Now add a file main.js
to src
, with the following content:
goog.provide('app');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Tile');
goog.require('ol.source.OSM');
/**
* @type {ol.PluggableMap}
*/
app.map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [0, 0],
zoom: 4
})
});
goog.provide('app')
creates the namespace app
for the application. The
goog.require
statements that follow define the OpenLayers constructors and
namespaces that the application uses. The rest of the code just creates the
OpenLayers map as you would do in any OpenLayers application.
We're now going to compile the application and OpenLayers together, using the
Closure Compiler and closure-util
. For this we need to create a JSON config
file, that we will then pass as an input file to the closure-util
command.
The minimum config file looks like this:
{
"lib": [
"node_modules/openlayers/src/**/*.js",
"node_modules/openlayers/build/ol.ext/**/*.js",
"src/**/*.js"
],
"compile": {
"closure_entry_point": "app",
"externs": [
"node_modules/openlayers/externs/bingmaps.js",
"node_modules/openlayers/externs/cartodb.js",
"node_modules/openlayers/externs/closure-compiler.js",
"node_modules/openlayers/externs/esrijson.js",
"node_modules/openlayers/externs/geojson.js",
"node_modules/openlayers/externs/proj4js.js",
"node_modules/openlayers/externs/tilejson.js",
"node_modules/openlayers/externs/topojson.js"
],
"define": [
"ol.ENABLE_WEBGL=false"
],
"js": [
"node_modules/openlayers/src/ol/typedefs.js",
"node_modules/openlayers/externs/olx.js",
"node_modules/openlayers/externs/oli.js"
],
"extra_annotation_name": [
"api", "observable"
],
"rewrite_polyfills": "false",
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true
}
}
Create a config.json
file with the above content at the root of the
application directory.
We can now use closure-util
to compile the code:
$ ./node_modules/openlayers/node_modules/.bin/closure-util build config.json app.js
The resulting app.js
file, which you can view in your editor if you're
curious, includes a minified version of the application code (main.js
), and
the OpenLayers code that the application code uses.
Here is a version of config.json
with more compilation checks enabled:
{
"lib": [
"node_modules/openlayers/src/**/*.js",
"node_modules/openlayers/build/ol.ext/**/*.js",
"src/**/*.js"
],
"compile": {
"closure_entry_point": "app",
"externs": [
"node_modules/openlayers/externs/bingmaps.js",
"node_modules/openlayers/externs/cartodb.js",
"node_modules/openlayers/externs/closure-compiler.js",
"node_modules/openlayers/externs/esrijson.js",
"node_modules/openlayers/externs/geojson.js",
"node_modules/openlayers/externs/proj4js.js",
"node_modules/openlayers/externs/tilejson.js",
"node_modules/openlayers/externs/topojson.js"
],
"define": [
"ol.ENABLE_WEBGL=false"
],
"js": [
"node_modules/openlayers/src/ol/typedefs.js",
"node_modules/openlayers/externs/olx.js",
"node_modules/openlayers/externs/oli.js"
],
"jscomp_error": [
"*"
],
"jscomp_off": [
"unknownDefines",
"lintChecks",
"analyzerChecks"
],
"extra_annotation_name": [
"api", "observable"
],
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true
}
}
You can now go ahead and create a simple HTML for the application. Create
a index.html
file with the following content at the root the application
directory:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="node_modules/openlayers/css/ol.css" type="text/css">
<title>Simple example</title>
<style>
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>
Note that the page includes a script
tag referencing the app.js
file,
which is the file resulting from the compilation.
You are done!
As a bonus, we're going to show how to use closure-util
to run the
application in "debug" mode, where the original application and OpenLayers
scripts are loaded one by one in the page.
Start the closure-util
development server:
$ ./node_modules/openlayers/node_modules/.bin/closure-util serve config.json
Now change the script
tag to the following in the index.html
file:
<script src="@?main=src/main.js" type="text/javascript"></script>
Reload the page in your browser and you should see that scripts are now loaded individually, making debugging much easier.