Implementation of the [Kubernetes Controller] pattern over custom resources specifying front-end web components to be dynamically integrated into a user interface application shell.
This is experimental concept design of micro-fronts architecture, considering declarative definition of micro-front-ends as part of the kubernetes API custom resource definitions, and leveraging the web components technology. This enables to approach development of particular micro-front ends in a similar way as is done with development of the cloud-native micro services.
The central part of the concept is kubernetes controller - ufe-controller
, which watches resources of a kind WebComponent
(see [./deploy/crd.yaml]) deployed to the cluster and compiles the them into the form of the front-end configuration. The embedded web server provides the application shell to integrate the configured web coponents, and proxies the requests to mikro front end server.
The microfrontends are assumed to serve web-component package module, with dedicated web component to serve as a micro front. It can also serve various other elements to be display in specific contexts.
The project is of educational nature.
The controller is provided as a configurable docker image milung/ufe-controller. It can be deployed into the kubernetes cluster using the manifests in the [./configs/k8s/kustomize] folder, which also includes kustomization.yaml
manifest. In the default setup the controller starts to observe WebComponent resources in all namespaces.
After installation you can navigate to ufe-controller
web ui, e.g. executing the command
kubectl port-forward service/ufe-controller 8080:80
and navigating the browser to [http://localhost:8080]. You should see an empty application shall waiting for some WebComponent
-s being deployed to the cluster.
A sample deployment with a demo web application is available in the folder [./examples/kustomize]
Let's assume your micro front-end is implementing a custom web component with element tag my-web-app
, and is served by a kubernetes service my-frontend
in the namespace my-namespace
. To integrate this web component application into the controller`s application shell, the following resource has to be deployed to the cluster:
apiVersion: fe.milung.eu/v1
kind: WebComponent
metadata:
name: my-web-app
spec:
module-uri: http://my-frontend.my-namespace/modules/web-components.esm.js
# it is recommended to always use namespaced domain of the service, as ufe controller
# can be running in different namespace
navigation:
- element: my-web-app # element tag to use in app shell when navigating to /my-web-page,
path: my-web-page # when user navigates to subpath ./my-web-page, the specific element
# will gain controll of the application shell`s content area
title: My Wanderfull Micro App # title to be displayed to end user (e.g. on landing page)
details: This is my wanderfull example functionality
preload: false # if set to true the module will be loaded imediately after loading
# the landing page, otherwise it will be loaded only when needed
proxy: true # if set to false then module uri must be accessible from the user network
# and may require futher configuration to enable cross origin loading
hash-suffix: v1alpha1 # optional suffix when proxy-ing the module. Changing it value will force
# to refresh cache, and avoids issues with cached versus actual version
The full specification of custom resource can be seen in crd.yaml
The backend of the controller can be configured by setting environment variables, below is a list of the currently supported variable:
Env. Variable | Default Value | Description |
---|---|---|
ACCEPTS_LANGUAGES | en | List of semicolon, or comma separated language codes that are supported. If there is match between Accept-Language header and this list, then language of html element is set to such language. In case there is no match then html language is set to the first language in this list |
APP_ICON_LARGE | ./assets/icon/icon.png | link to application icon used in manifest" Shall be 512*512 pixels |
APP_ICON_SMALL | ./assets/icon/icon.png | link to application icon used in manifest" Shall be 64*64 pixels |
APPLICATION_DESCRIPTION | Some detailed description of the applivation to be part of the index.html meta. Language specific descriptions are also possible, e.g. APPLICATION_DESCRIPTION_EN_US |
|
APPLICATION_SHELL_CONTEXT | application-shell | context of the dynamic web component that is used to retrieve the application shell - used to build the top-level element in the page body |
APPLICATION_TITLE_SHORT | Shell | Short version of the language fallback application title, language specific titles are also possible, e.g. APPLICATION_TITLE_SHORT_EN_US |
APPLICATION_TITLE | Application shell | Language fallback application title, language specific titles are also possible, e.g. APPLICATION_TITLE_EN_US |
BASE_URL | \ | Base URL of the server, all absolute links are prefixed with this address |
FAVICON_ICO | ./assets/icon/favicon.ico | link to favicon used as if in<link rel="icon" href="${FAVICON}"> |
FORCED_REFRESH_PERIOD_SECONDS | 60 | Period in seconds, when the configuration is forced to be refreshed independently of the k8s watching status |
HTTP_CSP_HEADER | default-src 'self'; font-src 'self'; script-src 'strict-dynamic' 'nonce-{NONCE_VALUE}'; worker-src 'self'; manifest-src 'self'; style-src 'self' 'strict-dynamic'; | Content Security Policy header directives for serving the root SPA html page. The placeholder {NONCE_VALUE} will be automatically replaced by the random nonce text used to augment <script> elements in the html file. |
HTTP_PORT | 80 | HTTP port the server is listening on. |
MANIFEST_TEMPLATE | manifest.template.json | Path to the manifest.json template file to be used when registering PWA application. The path must be within the scope of the /app/www folder and relative to it. The file may contains mustache plaholders. |
OBSERVE_NAMESPACES | Comma separated list of namespaces in which to look for webcomponents to be served by this instance | |
PWA_MODE | disabled | (experimental) if set to "pwa" then service worker will be registered and PWA functionality will be provided by the service worker |
SERVICE_WORKER | sw.mjs | Path to the script to be served as sw.mjs file when registering PWA application. The path must be within the scope of the /app/www/modules folder and relative to it |
SW_VERSION | v1 | Version of the service worker, used to force the browser to update the service worker |
SW_SKIP_FETCH | Comma separated list of regular expressions against request paths which should not be fetched by the service worker. All paths that contains /api/ string, or requests to other domains are implicitly skipped reagrdless of this setting. All other requests, including requests toward web components are served with cache-first startegy |
|
TOUCH_ICON | ./assets/icon/icon.png | link to favicon used as if in <link rel="apple-touch-icon" hred="${TOUCH_ICON}" |
USER_ID_HEADER | x-forwarded-email | incomming request`s header name (lowercase) specifying the user identifier, typically email |
USER_NAME_HEADER | x-forwarded-user | incomming request`s header name (lowercase) specifying the user name |
USER_ROLES_HEADER | x-forwarded-groups | incomming request`s header name (lowercase) specifying the list of user roles (or groups) |
WEBCOMPONENTS_SELECTOR | comma separate list of key-value pairs, used to filter WebComponent resources handled by this controller |
The project is of educational nature
All endpoints may be prefixed by BASE_URL
path.
Endpoint | Description |
---|---|
/app-icons/<navigation path> |
The navigation entry may specify the icon for the application, to be used in the fronted. In such case the icon can be retrieved under this endpoint, given the <navigation path> matches the property path of the given navigation entry. |
/fe_config |
Serves application/json object that describes the current applications, context and modules collected by the controller. Used in the frontend for dynamic loading of the web components. See interface UfeCOnfiguration in [./web-ui/src/services/ufe-registry.tsx] for the type definition. |
/healtz |
Health check of the controller |
/web-components/<namespace>/<name> |
In the case the WebComponent witn the matadata <name> and <namespace> is configured with the property proxy: true , then its module and all relative assets are served under this path |
/ |
All other paths are routed to frontend single page applicatio - see below description. |
The index.html
page is initially empty and loads the /fe_config
json object, that describes the applications, contexts, and a basic user identity. The object is exposed at window.ufeRegistry
, if you need a direct access. Once the page loads, the script decides, which web component to load as an application shell. It will use the built-in web component with the element tag ufe-default-shell
. It is possible to to replace the application shell by configuring the controller with the environment variable APPLICATION_SHELL_CONTEXT
and registering WebComponent
with such context element. Eventually, the complete built- in user interface may be ignored, and some custom front-end application shell used, while using only ufe-controller
endpoints described above.
The static resources for the UI are under the path /app/www
, you may eventually mount additional assets there, or replace the prepared assets. When serving the index.html
, the controller preprocess it and replaces some parts with predefined environment variables, using the {{mustache}} syntax. Additionally, all script elements in the index.html
has added dynamically generated nonce.
In the case you want to load content from other origins, you may need to adapt the environment variable HTTP_CSP_HEADER
, otherwise the request will be blocked by browsers.
Following web components are available for use in the hosted web components:
-
ufe-app-router
application router to host the current path's application as specified by the navifation section in CRD. The attributehome-component
specifies which component shall be hosted at the root path - defaults toufe-application-card
-
ufe-application-cards
- displays a card per registered navigation section in CRD. Attributeselector
allows to narrow the list of applications/navigations based on their labels. -
ufe-application-cards
- similar to above but displays amwc-list
of application titles. -
ufe-context
- display sequence of the elements mentioned in the CRD's resources undercontext elements
sections, that matches attributecontext
. Attributeselector
allows to futher narrow the list of the elements by the elements labels.This element accepts following slots:
beforeAll
- placed before the sequence of the elements being displayedafterAll
- placed after the sequence of the elements being displayedbeforeEach
- placed before each element being displayedafterEach
- placed after each element being displayed
See also ufe-registry package
-
Creating custom list of navigable elements and placeholder for displaying the current app:
import { Component, Host, h, State, Prop } from '@stencil/core'; import { Router } from 'stencil-router-v2'; import { getUfeRegistryAsync, UfeRegistry} from "ufe-registry" @Component({ tag: 'my-shell', styleUrl: 'my-shell.css', shadow: true, }) export class MyShell { @Prop() router: Router; // use subrouter if your app is hosted in another web-component ufeRegistry: UfeRegistry; async componentWillLoad() { this.ufeRegistry = await getUfeRegistryAsync() // wait for UfeRegistry being available } render() { const apps = this.ufeRegistry.navigableApps() // get list of application registered in cluster <my-shell> <navigation-panel> <tabs> {apps.map( app => { const active = false (<app-tab label={app.title} {...this.ufeRegistry.href(app.path, this.router || this.ufeRegistry.router)} active={app.isActive} ></app-tab> )})} </tabs> </navigation-panel> <ufe-app-router></ufe-app-router> // shows the webcomponent of the currently active app </my-shell> }