About bundles
An app built on top of the App Runtime is composed out of several bundles. Bundles contain the code and resources to build up the whole app. A single bundle typically provides one feature or tool.
Here are some examples of what a bundle could provide:
- 
Display a welcome window with configurable content when an app is started.
 - 
Display a form and send its data to a backend service.
 - 
Add geometries provided by a web service to the map.
 
map.apps comes with a bunch of bundles pre-installed that allow to compose rich mapping applications.
You can browse the bundles of a map.apps instance using the JS Registry service: http(s)://<host>/<mapapps-context>/resources/jsregistry/root.
Examples:
- 
https://demos.conterra.de/mapapps/resources/jsregistry/root (con terra’s public instance)
 - 
http://locahost:9090/resources/jsregistry/root (your development instance, for example)
 
Structure of a bundle
A bundle is folder that has the following structure:
mybundle/
├── nls/
│   ├── de/
│   │   └── bundle.js
│   └── bundle.js
├── AClass.js
├── Activator.js
├── manifest.json       // required
└── module.js
mybundle/- 
Folder containing all files of a bundle. Should be the same name as the bundle defines in the
manifest.jsonfile. nls/- 
Folder containing all internationalization (i18n) language files.
The details of internationalization are described in the chapter Bundle internationalization. manifest.json- 
The bundle manifest file.
See below for a small introduction into the bundle manifest. module.js- 
The bundle layer file that triggers loading of all JavaScript files required by the bundle.
The section Bundle layer file explains all the details and options. AClass.js- 
Implementation class with certain functionality. Often such classes provide the implementation of a component declared in the bundle manifest.
 Activator.js- 
A bundle activator implementation class. A bundle activator can hook into the bundle’s lifecycle and implement special behavior on bundle startup and shutdown.
 
Bundle manifest
The most important file of a bundle is the manifest.json file, the bundle manifest.
The bundle manifest provides bundle metadata and defines the functionality provided by the bundle.
A pretty simple bundle manifest might look like this:
manifest.json file{
  "name": "mybundle",   (1)
  "version": "1.0",     (2)
  "components": [       (3)
    {
        "name": "ComponentA",
        "impl": "AClass"
    }
  ]
}
| 1 | The official name of the bundle, this should match the name of the folder (required). | 
| 2 | The version identifier of the bundle (required). | 
| 3 | An array of component configurations declared by the bundle. | 
The name of a bundle is used as an identifier within the App Runtime and must be unique among all bundles. Each bundle has to define a version number. It should be incremented if the bundle is changed.
A manifest can have a lot of properties that are listed in the reference of manifest properties.
Bundle dependencies
If a bundle requires another bundle to be installed in the app to work correctly, this requirement should explicitly be expressed in the bundle manifest:
{
  ...
  "dependencies": {
    "map-init" : "^4.14.0"    // <name> : <version range expression>
  },
  ...
  "optionalDependencies": {
    "coordinatetransformer" : "^4.14.0"
  },
  ...
}
The App Runtime tests if the required bundles are installed and ensures that theses bundles are started before the bundle that is declaring the dependency. If a bundle has an implementation class dependency to another bundle (if it needs a class of another bundle), declare this dependency to ensure that the needed class is loaded before the bundle is started.
Bundle layer file
When the App Runtime first starts a bundle it looks for the bundle layer file and loads it. This bundle layer file is responsible to load all required JavaScript files of the bundle. A file is required to be loaded if it provides a class that implements a component or bundle activator declared in the bundle manifest.
By default a bundle layer file is assumed to be named module.js.
It  typically looks like this:
export { MyService, AnotherService } from "./Services";
export { FooActivator as Activator } from "./activators";
It just re-exports all required classes, optionally making them available under a different name.
| 
 Older bundles might use other styles to load the right classes: 
 | 
Now, consider the following bundle with the module.js file outlined above:
mybundle/
├── activators.js
├── manifest.json
├── module.js
├── Services.js
└── util.js
The bundle manifest declares two components and an activator:
{ ...
  "activator": "Activator",         // required class: Activator
  "components": [
      {
          "name": "MyService"       // required class: MyService
      },
      {
          "name": "Service2",       // required class: AnotherService
          "impl": "AnotherService"
      }
  ]
  ...
}
The bundle layer file module.js loads all required classes, so the App Runtime can start the bundle.
Bundles without a layer file
Some bundles don’t need to provide a layer file.
This is mainly because they implement a library or define an API, and don’t declare any components themselves.
Instead they are dependencies for other bundles and get imported directly.
In that case you need to set "layer" : "" in the bundle manifest.
Otherwise the App Runtime will try to load a file named module.js and fail with an error if it does not exist.
Bundle internationalization
Bundles support internationalization, so you can display messages in bundles, based on the user-selected language, for example.
Defining resources
To provide language-specific strings, a bundle must have a folder nls/ containing bundles.js files structured like this:
mybundle/
└── nls/                    // fixed folder name for i18n resources
    ├── de/                 // German i18n resource directory
    │   └── bundle.js       // German i18n resource file
    └── bundle.js           // root i18n resource file (en)
The root i18n file mybundle/nls/bundle.js contains the English resources.
Only this root i18n file needs to wrap the resource properties in a root element:
export default {
  root: {
    bundleName: "My Bundle",
    bundleDescription: "The bundle provides some functionality."
  },
  "de": true  // declare other available languages; only required in this root i18n file
};
The file mybundle/nls/de/bundle.js contains the German resources.
export default {
  bundleName: "Mein Modul",
  bundleDescription: "Das Modul bietet Funktionen."
};
Referencing resources
A common requirement is to access i18n properties from component instances.
But you can also use ${resourceKey} expressions to access i18n properties directly inside the bundle manifest.
The next sample shows how to implement a language-aware bundle title:
manifest.json file{
  ...
  "title": "${bundleName}",
  ...
}
Bundle lifecycle
A bundle has a defined lifecycle that starts when it is installed into the App Runtime. The lifecycle defines the states a bundle can be in. You can hook into the lifecycle of a bundle by implementing a bundle activator or by listening to bundle events.
The following diagram illustrates a bundle’s states and their transitions:
| State | Description | 
|---|---|
INSTALLED  | 
This is the initial state of a bundle after the installation into the runtime.  | 
RESOLVED  | 
This state is reached during the first start of the bundle. It means that the bundle layer is loaded successfully.  | 
STARTING  | 
The bundle is in the start process.  | 
ACTIVE  | 
The bundle is successfully started and ready to operate.  | 
STOPPING  | 
The bundle is shutting down.  | 
UNINSTALLED  | 
The bundle is uninstalled from the runtime and cannot be restarted again.  | 
Bundle activator
The bundle activator is a special class that a bundle can optionally provide. The App Runtime calls the bundle activator when the bundle that declares it is started or stopped.
A bundle activator needs to be declared in the bundle manifest using the activator property:
{
  ...
  "activator" : "AClassName"
  ...
}
The App Runtime calls the start or stop method of the activator class.
export default class {
    start(bundleContext) {
      // do something
    }
    stop(bundleContext) {
      // clean up
    }
}
A bundle activator can return a Promise in its start method.
The App Runtime waits until the Promise is resolved before setting the state of the bundle to ACTIVE.
import Promise from "apprt-core/Promise";
export default class {
  start() {
     return new Promise((resolve) => {
        setTimeout(function() {
          resolve(true);
        }, 100);
     });
  }
}
The main class for interacting with the App Runtime is the BundleContext, which provides all methods to manipulate bundle states, register for framework events or use the service layer.