Skip to Content
Technical Articles
Author's profile photo Wouter Lemaire

Using UI5 Libraries in CF approuter

With SCP Neo almost being deprecated, more and more developers are making the move to SCP CloudFoundry. Some may have already a lot of experience with CF but many things are not clear to everyone, at least not yet ? .

One of the things I faced was the usage of UI5 libraries. As a UI5 developer for several years now, I like to make everything as reusable as possible. In that case, UI5 libraries are the key. In this blog I’m going to share the challenges that I’ve faced and how to solve them.

Before we start, I want to thank Yuval and his team for the big help to make this work!

Create the UI5 library

First step is to create the UI5 Library. Currently there is no official UI5 Library template for CloudFoundry in Yeoman nor in the Business Application Studio available. (Correct me if I’m wrong here ? )

Instead I used the UI5 Freestyle template in the BAS:

In this template I used “SAPUI5 Application” to be able to go through the wizard:

For my example I used the Central AppRouter:

You need to provide a unique name which will be used to generate a unique url in the Central Approuter.

In case you would add the library in the same mta as the consuming UI5 app, you need to use the same id for both modules.

But it’s better to keep the library in a separate mta because it’s meant to be reusable and consumed by several other mta’s.

In the end the wizard will generate a UI5 project. Therefor delete the “webapp” folder and define the module as a library in the ui5.yaml file.

Now we can create a “src” folder with the content of the library. The content of the library can be generated from the Web IDE Full-Stack or a Yeoman generator:

You can also do this manually based on my example:

Make sure that the library has this structure in the end:

I’m only using an example control for demo purpose.

Build library

First attention point. You need to make sure the library contains the correct building scripts for building and deploying the library to CF. The result in the dist folder is important to be able to deploy and have access to the library from your UI5 app.

Add the following scripts to the package.json:

"scripts": {
    "build": "npm run clean && ui5 build --include-task=generateManifestBundle generateCachebusterInfo && npm run flatten && npm run clean-after-flatten && cp ./xs-app.json dist  && npm run zip",
    "zip": "cd dist && npx bestzip ../ *",
    "flatten": "cp -r dist/resources/be/wl/examplelibrary/* dist && cp dist/resources/be/wl/examplelibrary/.library dist ",
    "clean": "npx rimraf dist",
    "clean-after-flatten": "rm -rf dist/resources dist/test-resources"


This script will not only build the library but also make the folder structure flat. This was my first mistake ? I thought this was only needed when deploying to ABAP. It’s also required for deploying to CF. The deploy will look for the manifest file at the top level of the dist folder. It’s also needed to make the correct mapping for your namespace to the library.

Consume library in app

Just like you would consume any other UI5 library, add it to the list of lib in the dependencies section of sap.ui5:

Start using it in your view:

Run in BAS

Now, here comes the second attention point. Running in BAS requires a different path to the library. Compared to the Central AppRouter, BAS doesn’t use the service id in the url. You need to define a mapping in the resourceroots property of UI5 SDK bootstrap script in the index.html.

Resourceroots contains a mapping between the name of the library (including the namespace) and the path. The path will be the id of the library which is the namespace + name without the dots.

It’s important to not do this in the manifest. Otherwise it will not work in the Central Approuter. In BAS you start the app from the index.html page (which contains the resourceroots property) and in cFLP (with the Central AppRouter) it starts from the Component.js which has no resource roots property.


Next attention point, you have to copy the library into the same project as the app. Currently BAS is not able to access libraries from another mta/project. (You do not have to delete the library from the mta when you want to deploy. The library is not configured in the mta and won’t be deployed)

This also requires additional config. Go to the “run” settings of your app, right click and click on “Show in file”:

Add ,\”dist\” to “MOCK_LOOKUP_DIRS”:

When you now restart the app, it will search for all the webapp and dist folders in the current mta/project.

This should do the trick to run your app in BAS and load the library.

Run in Central AppRouter

After deploying the library to the HTML5 App Repo, you can start using them in the Fiori Launchpad.

First sync the apps in portal:

Make the tiles and test the apps, for this you can use the following blog post:

As soon as you added them as a tile to FLP, the app will run and load the library without any additional config. FLP will start the app from the component.js and so won’t use the resourceroots mapping defined in the index.html

Run in HTML5 App Repo

Until now, I’ve only tested the app in BAS and FLP using the Central Approuter. But maybe you want a stand-alone app? Or you just want to test it first in the HTML5 App Repo.

To do so, you need to change the resourceroots path in index.thml to the path that also contains the service id (without dots) in the url. The service id and library id are separated with a dotslike this:

,”be.wl.ScannerAppLibrary”: “/bewlscanner.bewlScannerAppLibrary”

I did this for my demo app of the QR Scanner app:

Keep attention that this will only work in the HTM5 App Repo and FLP but not in BAS. The solution for this is in the next topic.

You can find the apps in the HTML5 App Repo here:

In some trial accounts this menu item is not yet available. In that case you can still access the apps from the HTML5 Appr Repo with the following command:

“cf html5-list -u -d”

Run everywhere

This is an ugly workaround but if you really want to test in BAS, HTML5 App Repo and cFLP do the following.

  1. Remove resource roots from index
  2. Remove library dependency from manifest.json
  3. Add the following to the component.js
    //to make it work in app studio
    sap.ui.getCore().loadLibrary("be.wl.ScannerAppLibrary", "/bewlScannerAppLibrary/be/wl/ScannerAppLibrary");
    //to make it work in central approuter and HTML5 App Repo
    sap.ui.getCore().loadLibrary("be.wl.ScannerAppLibrary", "/bewlscannerapp.bewlScannerAppLibrary/resources/be/wl/ScannerAppLibrary");

Here you have an example:

Additional information

Use the same SAP Cloud service id for all the apps/libraries in the same mta.

Every other mta can have his own SAP Cloud service id.

Try to keep the library in a separate mta. It’s designed to be consumed by other apps which will not all be in the same mta. Do not put one app in the same mta and another app separated. Keeping the library separated allows you to do updates without having a direct relationship with other apps.



Example of app and library in separated mta’s (recommended approach):


Example of app and library in one mta:


Example of app and library that run in BAS, HTML5 App Repo and FLP (not the best solution):


Again a big thanks to Yuval Morad and his team for all the help to make this work!

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Jorge Sousa Villafaina
      Jorge Sousa Villafaina

      Very useful! Thanks a lot!

      Author's profile photo Mio Yasutake
      Mio Yasutake

      This is what I have been looking for.

      Thanks for sharing!


      Author's profile photo Mio Yasutake
      Mio Yasutake

      Hi Wouter,

      I have cloned your project and was able to run it successfully in the CF Launchpad.

      However, if I try to consume the library from my own UI5 app, the Launchpad (or central app router?) tries to fetch the library resources from, instead of HTML5 app repo.

      What I have done is only to add dependency to manifest.json and use the library in App.view.xml (as described in your blog).


              "dependencies": {
                  "minUI5Version": "1.66.0",
                  "libs": {
                      "sap.ui.core": {},
                      "sap.m": {},
                      "sap.ui.layout": {},


      	<Shell id="shell">
      		<App id="app">
      				<Page id="page" title="{i18n>title}">
                              <x:Example text="Example app consuming library in CF"/>                    

      Do you have any idea where this difference is coming from?

      Author's profile photo Wolfgang Röckelein
      Wolfgang Röckelein

      We see the same wrong behaviour unfortunatly and also still have no solution for this.

      Author's profile photo Wouter Lemaire
      Wouter Lemaire
      Blog Post Author

      Try cloning from the branch library-fix


      in master I removed the library reference in the manifest

      "dependencies": {
      "minUI5Version": "1.60.1",
      "libs": {
      "sap.ui.core": {},
      "sap.m": {},
      "sap.ui.layout": {},

      Author's profile photo Mio Yasutake
      Mio Yasutake

      Hi Wouter Lemaire and Wolfgang Röckelein,

      The reason why my app could not call the library was because it was using instance-level destination.

      Once I changed it to subaccount level destination, it started to work.

      I assume that if the library and the consuming app belong to different destination instances, library cannot be loaded.

      I'm thinking of using this Managed Approuter approach so that the library and the app are connected to the same destination instance.

      Author's profile photo David Sooter
      David Sooter

      Hi Wouter,

      I created a small dummy library but cant seem to get it to work. Can i use it in a local development enviroment as well ( vscode) and i was having some issues deploying the app. I think im laking some general knowledge as to how to deploy a library and reuse it. Do you have any ideas of recomended reading to help me along?

      Author's profile photo aurelien albert
      aurelien albert

      Thanks Wouter Lemaire , very useful!

      Author's profile photo Wolfgang Röckelein
      Wolfgang Röckelein

      Thanks Wouter Lemaire for this blog!

      What we use to make this work in BAS and VSC without disturbing everything else is this:

      • have for development libraries and apps as directories next to each other on the same level
      • have the libraries as local relative dependencies ( file:../abc ) in the package.json of the apps
      • Use fiori tools and fiori-tools-servestatic middleware with the configuration
              - path: /resources/com
                src: "dist/resources/com/"
        where both com are the starting characters of our library ids like the be in your case

      npm install will thus the build the libraries also and will make them available in dist for the test run with fiori tools. Thus one could even make changes to app and library without comitting and test your changes, you just need to invoke npm install after any library change.

      Author's profile photo Wouter Lemaire
      Wouter Lemaire
      Blog Post Author

      That’s even better, thanks for sharing! Would be even better to share an example app or make a pull request on my example 😉

      Author's profile photo Henning Pohlhausen
      Henning Pohlhausen

      Thanks for the blog, it helped for Portal deployment.


      One addition for Standalone/Launching from index.html: When consuming the library via npm, the resource root for the library is not needed, "it just works", assuming the ui5 core is loaded from local ressources, as recommended in the UI5 documentation.


      Do you have an idea, how to tell the FLP to use "local resources" from the app (./resources folder)?

      I experience the same issue as Mio Yasutake, but the fix of using subaccount destinations does not only not work, but the HTML5 application is not listed with the other HTML5 applications anymore.



      Author's profile photo Wouter Lemaire
      Wouter Lemaire
      Blog Post Author

      Some parts are changed in the meanwhile, I should give this blog post an update. The move of the library is not needed anymore. Maybe you could open a question for this problem..

      Author's profile photo Yen Shen, Ben Lim
      Yen Shen, Ben Lim

      Hi Wouter Lemaire ,

      I'm having error when tried to Build mta.yaml of the UI5 library app.

      The error I received was "Could not built the "ExampleUI5Library" module: could not execute the "npm run build:cf" command: exit status 1

      Is there any updates from BAS to deploy library type application?



      Author's profile photo John Long
      John Long


      This indicates your UI5 app is not exposing a package.json script called buid:cf. Open the package.jsaon for your relevant UI5 app and append

      "build:cf": "ui5 build preload --clean-dest --config ui5-deploy.yaml --include-task=generateManifestBundle generateCachebusterInfo"
      to the existing scripts. This assumes you've run npm run deploy cf against your UI5 application.
      Author's profile photo John Long
      John Long


      I'm wondering that is the best approach to expose a subaccount destination using `OAuth2UserTokenExchange` to allow other UI5 apps consume the library? I've followed the tutorial and the library is deployed and loading correctly when I hit it directly in the browser.

      The library is using a managed approuter, so I've appended the following destination to the ExampleLibrary-destination-content module;

      - Authentication: OAuth2UserTokenExchange
      Name: com_balta_exampleLibrary_srv_ExampleLibrary
      TokenServiceInstanceName: ExampleLibrary-xsuaa-service
      TokenServiceKeyName: uaa_ExampleLibrary-key
      URL: '~{srv-api/srv-url}' be.wl.exampleLibrary
      The destination is created but when I enabled `HTML5.DynamicDestination: true` in the destination, the URL defined in the destination is not found.
      I've tried to manually configure an `OAuth2UserTokenExchange` destination using the service key properties generated for `ExampleLibrary-xsuaa-service` but that seems to fail with a callback login issue.
      The question is! What is the best approach to expose this library at subaccount level to allow other apps consume it? Ideadlly using a destination as such;
      "source": "^/resources/bewlexamplelibrary/(.*)$",
      "target": "/$1",
      "destination": "ExampleLibraryOAuthDest",
      "authenticationType": "xsuaa",
      "csrfProtection": false
      I dont fully understand how the `html5-apps-repo-rt` service works? Is this the only way to expose the library, which is to serve the static content of the HTML5 applications?
      Great tutorial too.
      Author's profile photo Mohamed Inayath
      Mohamed Inayath

      Hi Wouter Lemaire ,

      Example of app and library in separated mta’s (recommended approach):

      I was following the approach of having separate mta's and I could see the within the git:/CFUI5ExampleApp there is embedded library code:ExampleLibrary.

      Is this mandatory? Isn't the app is referring to the library within the app rather from external html5 repo?


      The embedded approach works however not the from the separate mta works.


      Author's profile photo Wouter Lemaire
      Wouter Lemaire
      Blog Post Author

      This was just for testing purpose. You should keep them separated.

      Author's profile photo Michael Smith
      Michael Smith

      Wouter Lemaire , is there a special way to deploy the library?  I used the "Deploy MTA Archive" from the context menu in BAS, but my library is not showing up in the HTML5 App Repository.  In the deploy log, I see the following error message:

      'Upload application content failed { CODE: '1001' } validation error: Could not find applications in the request.', error type 'Bad Request'
      Author's profile photo Wouter Lemaire
      Wouter Lemaire
      Blog Post Author

      The same as a ui5 app but the structure of a library is different. Make sure this is correct.

      Author's profile photo Michael Smith
      Michael Smith

      Wouter Lemaire , the "zip" script in the package.json was putting the file in the root folder rather than the dist folder.  Once I removed "../" from that script, the file was correctly put in the dist folder, so it could be copied to the resources folder.  That got rid of the error message, at least, but I still don't see the library in the HTML5 App repository - does it appear there only after a calling application is deployed?

      Author's profile photo Michael Smith
      Michael Smith

      Wouter Lemaire , I cloned your separate MTA repos, CFUI5ExampleApp and CFUI5ExampleLibrary.  Then, I removed the ExampleLibrary folder from the CFUI5ExampleApp project.  I built and deployed both.  They both appear in the HTML5 App repository; however, I click on the ExampleApp link there in the app repository, and it throws the 404 error shown below when attempting to access the library.js file.  Do you have a version of this that currently works in CF?


      Library error

      Author's profile photo Michael Smith
      Michael Smith

      Wouter Lemaire , I found the problem.  I made one small tweak to the bewlexamplelibrary reference in the index.html of the ExampleApp, re-built, re-deployed, and it worked!  I have created a pull request (as github user monkeytoad) for the correction.

      Thank you for a great blog on this subject!  I am now able to get my own library and application to work as well!

      Author's profile photo Christian Späh
      Christian Späh

      Hi Wouter Lemaire

      thanks for the tutorial. Does this approche work for reusing js-modules within an application and not a library? I am using this scenario in the NEO environment and I am wondering if I can transfer this setting with your blog post to cf.

      Kind regards,