logo

Are you need IT Support Engineer? Free Consultant

UI Composition with Application Frontend Service

  • By sujay
  • 18/05/2026
  • 11 Views

As UI application developers, we often find ourselves implementing the same functionality across multiple applications. The natural instinct is to extract that common code into reusable files that can be shared between projects. Traditionally, this is done in one of the following ways:

  • Development time. Copy-pasting shared files directly into each application's source code. This is the easiest way to start, but a maintenance nightmare. Any change to the common logic requires patching and redeploying every application that uses it. On top of that, the duplicated files increase the size of each application and slow down deployments.
  • Build/deploy time. Publishing shared code as an NPM package. This solves the problem of maintaining changes in multiple places, but still requires rebuilding and redeploying all affected applications. It also complicates the release lifecycle, since packages and applications must be released in a specific order.
  • Runtime. Hosting the shared code separately and accessing it via URL:
    • Directly from the client—eliminates code duplication and avoids rebuilding or redeploying applications, but introduces complexity around CORS/CSP restrictions and authentication/session management.
    • Via a server-side proxy—keeps the same user session and avoids CORS/CSP issues, but adds an extra network hop for every request to the shared resources.

All of these approaches work with Application Frontend service. However, in this post I want to show you a more efficient way to achieve UI composition—one that is unique to UIs hosted on Application Frontend service. In short, it is a form of runtime server-side composition, but without the overhead of extra network hops.

To demonstrate the possibilities of application-to-application reuse, we will walk through three common use cases that call for UI composition.

Reusable Application / Component

This use case applies when you have control over the consuming application's source code and want to embed a piece of reusable logic into it. The goal is to benefit from automatic updates to the shared code while preserving the consuming application's URL as the entry point for end users.

Figure 1. Reusable Application

To set this up, the consuming application's xs-app.json needs a route that points to the reusable application. This route uses an "application" property that references another Application Frontend application by name, optionally followed by @ and a specific version. The "source" property contains either a specific resource path or a regular expression that is different from the catch-all (.*) pattern. Path rewriting via the "target" property is also supported. For this use case, the route pointing to the reusable application is placed before the routes pointing to static resources of the consuming application itself.

Here is an example of the consuming application's xs-app.json:

{
  "errorPage": [
    { "status": [404], "path": "/error/404.html" }
  ],
  "routes": [{
    "source": "^/error/(.*)",
    "target": "/common/$1",
    "application": "mylib@1.0.0"
  }, {
    "source": "^(/|/index.html)$",
    "target": "/index.html",
    "service": "app-front"
  }, {
    "source": "/assets/.*",
    "service": "app-front"
  }]
}

This configuration assumes that another Application Frontend application exists with "sap.app/id" set to "mylib" in its manifest.json, deployed in the same BTP subaccount. There is nothing special required in the xs-app.json or manifest.json of the reusable application. For example, if mylib has the following routes:

{
  "routes": [{
    "source": "^/common/(.*)",
    "target": "/dist/$1",
    "service": "app-front"
  }]
}

then a browser request for a resource that does not match any route "source" pattern in the xs-app.json of consuming application (app1) will be redirected to:

https:​//app1-xyzab.eu10.appfront.cloud.sap/error/404.html

and will serve the /dist/404.html file from the mylib application. Any follow-up requests from the error page (for example, to load an illustration image) will also be served from mylib, as long as they use relative paths. This way, you can reuse the same error pages across multiple Application Frontend applications.

Application Extension

This use case applies when you don't have control over—or are not allowed to change—the source code of an existing application, yet you need to create a very similar application with minor modifications. End users will access both the original and the extended application via separate URLs.

Af-A2A-2.Svg

Figure 2. Application Extension

The implementation is very similar to the reusable application approach, but inverted: most requests to the extension application serve content from the original application, while the extension itself contains only the delta. In the extension's xs-app.json, the catch-all route points to the original application, and routes for specific paths that need to be overridden are placed before it.

The extension application's xs-app.json might look like this:

{
  "routes": [{
    "source": "^/view/App.view.xml",
    "service": "app-front"
  }, {
    "source": ".*",
    "application": "original"
  }]
}

In this example, the only static resource of extension application (besides xs-app.json and manifest.json) is a modified /view/App.view.xml. This lets you add, remove, or modify parts of the view while inheriting everything else from the original application.

UI Mashup

This use case is about integrating multiple existing UIs and data sources into a single unified application. The mashup has its own URL and behaves as a standalone application from a lifecycle perspective, yet it contains no UI artifacts of its own—only xs-app.json and manifest.json.

This may sound complex at first, but it is essentially a combination of the previous two patterns: the mashup application extends a base application, but instead of hosting override resources itself, it delegates to other applications that act as reusable components.

Af-A2A-3.Svg

Figure 3. UI Mashup

Let's look at a concrete example. Imagine a preview application that includes several embedded apps (deployed as part of the preview application itself) and a static apps.json file listing them. The preview application displays whichever embedded app the user selects inside a mobile shell, simulating how the app would look on a real mobile device. Now suppose you want this preview to be able to show any Application Frontend application deployed to your BTP subaccount, with the list of available applications served dynamically from a backend configured in the apps destination. A mashup application solves this.

Consider the following xs-app.json for the mashup application:

{
  "routes": [{
    "source": "^/apps.json",
    "destination": "apps"
  }, {
    "source": "^/app/(.*)",
    "application": "$1"
  }, {
    "source": ".*",
    "application": "preview"
  }]
}

With this configuration, the "application" property in the second route is resolved dynamically based on the request path. The static /apps.json is replaced with dynamic content from the backend, while all other requests fall through to the preview application.

Visibility

The application-to-application reuse relationships are part of Application Frontend application metadata, accessible via the API, CLI, and BTP Cockpit UI (on the application version dependencies screen). Application Frontend service provides not only design-time information about which application depends on which, but also live availability status of all dependencies. This makes it easy to spot issues—such as a missing reusable application or a stopped base application—without digging into the source code or analyzing runtime logs.

Af-A2A-Cockpit.png

Figure 4. BTP Cockpit Application Frontend Dependencies View

Conclusion

The application-to-application reuse feature of Application Frontend service is a powerful mechanism for UI composition that reduces both development and operational costs by improving:

  • Lifecycle management—There is no required order for releasing reusable and consuming applications. Consuming applications do not need to be redeployed to pick up new versions of shared code.
  • Security—No complex CORS/CSP configuration is needed. The browser treats reusable resources as if they were an integral part of the consuming application. A shared user session between consuming and reusable applications ensures consistent sign-out without orphaned “zombie” sessions.
  • Performance—Since all participants in the composition are Application Frontend applications, there are no redundant network calls from the runtime to itself. Application Frontend is aware of all deployed applications and can perform recursive routing target resolution without making extra outbound requests.
  • Extensibility—Base applications do not need to define extensibility points, hooks, or any other upfront preparations. You don't have to touch existing applications. Every Application Frontend application can be reused, extended, or composed into a mashup out of the box.

Source link

Leave a Reply

Your email address will not be published. Required fields are marked *