How to compile a bundle with Rollup
map.apps projects that use ct-mapapps-gulp-js to build the project (like map.apps for Developers does) can enable the JavaScript module bundler Rollup to compile the code of a bundle.
The benefits are:
-
Reduced amount of output files.
-
Optimized code and thus reduced size of bundles.
-
Ability to control which files of a bundle can be imported by other bundles.
This guide explains how to compile bundles of your map.apps project with Rollup.
Checklist
To follow this guide, you need:
-
a map.apps project based on map.apps for Developers, version 4.15.0 or higher.
Step 1: Enable Rollup compilation for a bundle
Before you start to enable Rollup in any bundle, first set your project to a clean state:
-
Stop the development server if it is running.
-
Clean the build folder by running
mvn cleanin the project root folder.
To enable a Rollup build for a bundle, follow the steps below. You need to execute the steps for each bundle that should be compiled with Rollup.
-
Make sure the development server is stopped.
-
Create a new file called
build.config.jsin your bundle’s root directory, next to yourmanifest.json, with the following content:module.exports = { type: "bundle", entryPoints: ["./module"] //module.js is the only entry point here };List all JavaScript files in
entryPointsthat must be available from outside of your bundle, for example because they’re used by the App Runtime (e.g.module.js) or because they’re imported by other bundles at runtime. Don’t list internal files, they will be detected and bundled by Rollup automatically. -
Replace all imports of
dojo/text!<file>and usetext!instead:// before: import textContent from "dojo/text!./templates/myTemplate.html"; // after: import textContent from "text!./templates/myTemplate.html";The path must be a relative path to a file in the current bundle.
Step 2: Replace imports by exports in module.js
Before using Rollup the typical content inside a module.js is:
import from "./myFileA";
import from "./myFileB";
In a Rollup build such a module.js file will end up as empty file, because none of the imports are used inside the file itself.
To avoid this, change the import statements to export statements like this:
// if myFileA has a default export and myFileB has named exports
export { default as MyComponentClass } from "./myFileA";
export * from "./myFileB";
Step 3: Check the components in the manifest
Make sure that all components defined in the manifest.json of your bundle are exported in module.js.
Example 1: Component only defines a "name"
If a component only defines the name property, you don’t need to change the manifest.json file.
Instead, make sure the class defined in the name property is exported in module.js.
{
"name": "mybundle",
"version": "1.0.0",
"components": [
{
"name": "MyComponentClass"
}
]
}
Export the class MyComponentClass in module.js like this:
export { default as MyComponentClass } from "./MyComponentClass";
Example 2: Component defines the "impl" property for a local file
If a component defines the impl property referencing a local file, it is recommended to remove the impl entry from the component definition.
Instead, export the the class defined in the name property in the module.js file
Change a component definition like this:
{
"name": "mybundle",
"version": "1.0.0",
"components": [
{
"name": "MyWidgetClass",
"impl": "./widgets/MyWidgetClass"
}
]
}
to this, removing the impl property:
{
"name": "mybundle",
"version": "1.0.0",
"components": [
{
"name": "MyWidgetClass"
}
]
}
Then export the class in module.js like this:
export { default as MyWidgetClass } from "./widgets/MyWidgetClass";
Example 3: Multiple components define the impl property referencing the same local file
If the same local file is referenced by multiple components in their impl property, change the impl property to refererence the name of the class exported in the module.js file, instead.
In the following example, the components MyTool1 and MyTool2 reference the same local implementation file ./tools/SharedToolClass:
{
"name": "mybundle",
"version": "1.0.0",
"components": [
{
"name": "MyTool1",
"impl": "./tools/SharedToolClass"
},{
"name": "MyTool2",
"impl": "./tools/SharedToolClass"
}
]
}
Change the impl property to reference a class name like this:
{
"name": "mybundle",
"version": "1.0.0",
"components": [
{
"name": "MyTool1",
"impl": "SharedToolClass"
},{
"name": "MyTool2",
"impl": "SharedToolClass"
}
]
}
and export the class in module.js like this:
export { default as SharedToolClass } from "./tools/SharedToolClass";
Step 4: Examine the build output
When you start the development server, the bundles will be compiled. When the build is ready, the output for a bundle will look like this:
dependencies.json
manifest.json
module.js
module.js.map
Alongside the manifest.json you find the new file dependencies.json as well as a compiled .js and .js.map file for every entry point you defined in build.config.js.
Hints
Solving build errors "ERROR [bundles\mybundle] [plugin commonjs—resolver] Cannot import…"
When using Rollup to compile bundles, you may encounter errors due to unresolvable imports like this:
[11:24:04] >C:\dev\mapapps-4-developers\src\main\js\bundles\mybundle\mymodule.js
[INFO] [11:24:04] >...lint using ESLint
[INFO] [11:24:04] >...rollup C:/dev/mapapps-4-developers/src/main/js/bundles/mybundle
[INFO] 1 file linted
[INFO] [11:24:04] ERROR [bundles\mybundle] [plugin commonjs--resolver] Cannot import 'apprt-core/string-replace' from 'src\main\js\bundles\mybundle\mymodule.js': bundle 'apprt-core' must be listed as a dependency.
[INFO] [11:24:04] ERROR [bundles\mybundle] Failed to build
[INFO] [11:24:04] <finished
This is caused by missing dependencies entries in the bundle manifest.
To solve the error of the previous example, we have to add apprt-core as a dependency like this:
{
"name": "mybundle",
"version": "1.0.0",
"i18n": [],
"dependencies": {
"apprt-core": "^4.15.0"
},
"components": [
...
]
}