This is a dotCMS OSGi plugin that delivers a custom Angular portlet using Webpack Module Federation. The plugin bundles an Angular frontend as a federated remote module, deploys it into dotCMS at runtime, and registers a portlet that loads the Angular app inside the dotCMS admin backend.
- Build -- Maven builds the Angular frontend (via
frontend-maven-plugin) and packages it alongside the Java OSGi activator into a single bundle JAR. - Deploy -- When the bundle starts, the
Activatorcopies the frontend dist files from inside the JAR todotAdmin/plugins/ng-portlet/and registers the portlet defined inconf/portlet.xml. - Load -- dotCMS loads
remoteEntry.jsvia Module Federation, calls the exposedmount()function, and bootstraps the Angular app inside the portlet iframe. - Undeploy -- When the bundle stops, the activator unregisters the portlet and deletes the deployed frontend files.
.
├── pom.xml # Maven build (OSGi bundle + frontend build)
├── src/
│ └── main/
│ ├── java/com/dotcms/ngportlet/
│ │ ├── Activator.java # OSGi activator -- registers portlet & deploys files
│ │ └── FileMoverUtil.java # Copies frontend assets from JAR to dotCMS filesystem
│ └── resources/conf/
│ └── portlet.xml # Portlet descriptor (name, Module Federation config)
└── frontend/ # Angular application (Nx workspace)
├── package.json
├── webpack.config.ts # Webpack Module Federation setup
├── module-federation.config.ts
├── project.json # Nx project config (build, serve, test, lint)
└── src/app/
├── remote-entry/
│ ├── entry.routes.ts # mount() function exposed via Module Federation
│ └── entry.component.ts # Shell component with router-outlet
└── features/
├── dashboard/ # Dashboard feature component
└── settings/ # Settings feature component
- Java 21+
- Maven 3.6+
- Node.js 22+ (automatically installed by
frontend-maven-pluginif not present) - A running dotCMS instance (v26.01+)
mvn clean installThis will:
- Install Node.js and npm (via
frontend-maven-plugin) - Run
npm installin thefrontend/directory - Build the Angular app for production (
npm run build:prod) - Copy the frontend dist into the bundle
- Package the OSGi bundle JAR at
target/dotcms-ngportlet-0.2.jar
Upload the generated JAR via the dotCMS Dynamic Plugins admin screen, or copy it to the felix/load directory of your dotCMS instance.
For live development with hot-reload against a running dotCMS instance:
cd frontend
npm install --legacy-peer-deps
npm startThis starts a dev server on https://localhost:4201 with CORS headers enabled. To point the portlet at the dev server, update portlet.xml:
<value>remote:https://localhost:4201/remoteEntry.js|ng_portlet|./Routes</value>When you're done developing, switch back to the production value:
<value>remote:/dotAdmin/plugins/ng-portlet/remoteEntry.js|ng_portlet|./Routes</value>- Update
portlet-nameand theangular-modulepath insrc/main/resources/conf/portlet.xml - Update the language key in
Activator.java - Update
destDirectoryInWarinFileMoverUtil.java - Update
output.uniqueNameand the MFnameinfrontend/webpack.config.ts
- Create a new component under
frontend/src/app/features/ - Wire it into the entry routes or mount logic in
frontend/src/app/remote-entry/entry.routes.ts
The Angular app is built as a Module Federation remote with the following configuration:
| Setting | Value |
|---|---|
| Remote name | ng_portlet |
| Library type | window |
| Entry file | remoteEntry.js |
| Exposed module | ./Routes |
Angular core libraries and RxJS are configured as shared singletons so they are not duplicated between the dotCMS host and this remote plugin.