Destroyed Exports Files (markdown)
-105
@@ -1,105 +0,0 @@
|
||||
## Exporting constructors, methods and functions
|
||||
|
||||
Alongside js files, the `src` directory includes "exports files" (e.g. `src/ol/map.exports`). The export files declare symbols and properties that the library exports. (See the [Closure Compiler docs](https://developers.google.com/closure/compiler/docs/api-tutorial3?hl=fr#export) to know more about _exporting_.)
|
||||
|
||||
For example the `src/ol/map.exports` file includes this:
|
||||
|
||||
```
|
||||
@exportClass ol.Map ol.MapOptions
|
||||
@exportProperty ol.Map.prototype.addLayer
|
||||
```
|
||||
|
||||
This declares that the `ol.Map` symbol, and that the `ol.Map.prototype.addLayer` property, should be *exported*, i.e. made available to library's users.
|
||||
|
||||
Exports files are processed by the `bin/generate-exports` script, using the `--exports` switch. This script receives a list of exports files as its input, and outputs JavaScript code including calls to Closure's `goog.exportSymbol` and `goog.exportProperty` functions.
|
||||
|
||||
As an example, try the following:
|
||||
|
||||
python bin/generate-exports.py --exports src/objectliterals.jsdoc src/ol/map.exports
|
||||
|
||||
The `build.py` script places the output of `generate-exports --exports` into the `build/src/external/src/exports.js` file. This script thus takes care of exporting the symbols and properties that make up the OpenLayers 3 API. It is used as an input file for the `ol.js` build, and is therefore included in `ol.js` after compilation.
|
||||
|
||||
## Exporting options objects
|
||||
|
||||
All the (exported) constructors are _single-argument constructors_, they take one argument, `options`, which is a JavaScript literal object. Here is, for example, how options are passed to the `ol.Map` constructor:
|
||||
|
||||
var map = new ol.Map({
|
||||
layers: [
|
||||
new ol.layer.TileLayer({
|
||||
source: new ol.source.OSM()
|
||||
})
|
||||
],
|
||||
target: 'map'
|
||||
});
|
||||
|
||||
The constructors' options objects, and their properties, are declared in the `src/objectliterals.jsdoc` file. The options objects themselves are declared using the `@typedef` keyword, while properties are declared using the `@property` keyword. This is, for example, how the `ol.Map` constructor's options are declared:
|
||||
|
||||
```
|
||||
/**
|
||||
* Object literal with config options for the map.
|
||||
* @typedef {Object} ol.MapOptions
|
||||
* @property {Array.<ol.control.Control>|undefined} controls Controls initially
|
||||
* added to the map.
|
||||
* @property {ol.Collection|undefined} interactions Interactions.
|
||||
* @property {Array.<ol.layer.Layer>|ol.Collection|undefined} layers Layers.
|
||||
* @property {ol.RendererHint|undefined} renderer Renderer.
|
||||
* @property {Array.<ol.RendererHint>|undefined} renderers Renderers.
|
||||
* @property {Element|string|undefined} target The container for the map.
|
||||
* @property {ol.IView|undefined} view The map's view. Currently
|
||||
* {@link ol.View2D} is available as view.
|
||||
*/
|
||||
```
|
||||
|
||||
[Note: config objects and properties are declared in a specific (separate) file because they may be shared by multiple constructors. For example the `ol.source.Vector` constructor currently takes an `ol.source.SourceOptions` options object, and `ol.source.SourceOptions` is a generic/base type that may be used for other constructors. We may want to change that in the future, and force each constructor to have its own config object type. In this way config objects and properties could be declared in the same file as their corresponding constructors.]
|
||||
|
||||
This file is also processed with the `bin/generate-exports` script, but using the `--externs` and `--typedef` switches.
|
||||
|
||||
The `generate-exports --externs` generates Closure externs from the `@typedef` and `@property` directives. The `build.py` script places these externs in the `build/src/external/externs/types.js` file, which is used as a regular externs file by the Closure compiler (see `buildcfg/ol.json`).
|
||||
|
||||
The `generate-exports --typedef` command generate typedef's for the object literals declared with `@typedef` and `@property`. The `build.py` script places the typedef's in the `build/src/external/src/types.js`, which, like `exports.js`, is used as an input file for the ol.js build (see `buildcfg/ol.json`).
|
||||
|
||||
Externs define types for options objects created by library's users, while typedef's define types created internally by the library.
|
||||
|
||||
## The oli.js externs file
|
||||
|
||||
The `externs/oli.js` file defines externs for functions that may be defined in application code and called by the library. For the library to be able to call user-defined functions, these functions should not be renamed within the library.
|
||||
|
||||
For example, `oli.js` includes the following definition:
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @return {undefined} Undefined.
|
||||
*/
|
||||
oli.control.Control.prototype.setMap = function(map) {};
|
||||
|
||||
This will prevent the Compiler from renaming `setMap` internally, allowing the creation of custom controls defining their own `setMap` functions. (The `ol.control.Control.prototype.setMap` function is also exported, making it possible to call it from child implementations.)
|
||||
|
||||
http://ol3js.org/en/master/examples/custom-controls.html provides an example for creating custom controls.
|
||||
|
||||
## Under the hood
|
||||
|
||||
`build/src/internal/src/requireall.js` is used in the `build.py build-all` target to ensure that all source files are passed to the compiler.
|
||||
|
||||
Before reading on, you should have a thorough understand of how the Closure Compiler handles exports and externs.
|
||||
|
||||
The exports/externs/typedefs system is required so that the same source files can be used in several modes:
|
||||
|
||||
1. Uncompiled (i.e. `mode=RAW`)
|
||||
2. Application and ol3 library compiled together
|
||||
3. ol3 library compiled, application uncompiled
|
||||
|
||||
Cases 1 are 2 similar: no exports are needed (except for `ol.Object` property `get` and `set` methods whose names must be preserved), and object literals passed to single argument constructors are defined as `@typedef`s so that they can be type checked and the compiler can rename their properties. Everything is "internal".
|
||||
|
||||
Case 3 is more complicated: we need to ensure that the appropriate library functions are exported so they can be used by application code. However, anything that is exported will be included in the built library and so increase the library size, hence the need for custom builds. Coarse-grained control over the custom build contents is achieved by deciding which `.exports` files to pass to the compiler. Object literals to single argument constructors are more complicated: these are supplied by the application, so the compiled library must not rename their properties. So, in "external" mode, in addition to the `@typedef`s, each object literals must be shadowed by an `@extern` declaration that declares an `@interface` in the `olx` namespace. A separate namespace is needed to avoid conflicts with the `ol` namespace used internally. Furthermore, a shadow derived class (e.g. `ol.MapExport`) is defined for each exported class that transparently translates the un-renamed external object literal into a possibly renamed internal object literal. This derived class is exported as its parent class by a cunning rename when it's exported. Easy, huh?
|
||||
|
||||
Luckily, all this complexity is handled by the `generate-exports` script. The ol3 developer need only add his declarations to the `.exports` files and everything is auto-generated from this single source.
|
||||
|
||||
### Approaches that don't work
|
||||
|
||||
#### Using the `@export` annotation
|
||||
|
||||
Using `@export` in the source code means that all exported symbols would always be exported, this prevents custom builds.
|
||||
|
||||
#### Using the `@expose` annotation
|
||||
|
||||
This also prevents custom builds, as well as increasing the generated code size.
|
||||
Reference in New Issue
Block a user