Technical Articles
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: https://blogs.sap.com/2018/06/19/fastrack-your-ui5-development-with-ui5lab-yeoman-generator/
You can also do this manually based on my example: https://github.com/lemaiwo/CFUI5ExampleLibrary/tree/master/ExampleLibrary/src
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 ../ExampleLibrary-content.zip *",
"flatten": "cp -r dist/resources/be/wl/examplelibrary/* dist && cp dist/resources/be/wl/examplelibrary/.library dist ",
"clean": "npx rimraf ExampleLibrary-content.zip 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:
https://github.com/lemaiwo/UI5QRScannerApp/blob/library-fix/ScannerApp/webapp/index.html
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.
- Remove resource roots from index
- Remove library dependency from manifest.json
- Add the following to the component.js
if(location.host.indexOf("studio")>-1){
//to make it work in app studio
sap.ui.getCore().loadLibrary("be.wl.ScannerAppLibrary", "/bewlScannerAppLibrary/be/wl/ScannerAppLibrary");
}else{
//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: https://github.com/lemaiwo/UI5QRScannerApp/blob/master/ScannerApp/webapp/Component.js
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.
Resources
Example of app and library in separated mta’s (recommended approach):
- Library: https://github.com/lemaiwo/CFUI5ExampleLibrary
- App: https://github.com/lemaiwo/CFUI5ExampleApp
Example of app and library in one mta:
https://github.com/lemaiwo/UI5QRScannerApp/tree/library-fix
Example of app and library that run in BAS, HTML5 App Repo and FLP (not the best solution):
https://github.com/lemaiwo/UI5QRScannerApp
Again a big thanks to Yuval Morad and his team for all the help to make this work!
Very useful! Thanks a lot!
This is what I have been looking for.
Thanks for sharing!
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 https://sapui5.hana.ondemand.com, 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).
manifest.json
App.view.xml
Do you have any idea where this difference is coming from?
We see the same wrong behaviour unfortunatly and also still have no solution for this.
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": {},
"be.wl.ScannerAppLibrary":{}
}
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.
https://answers.sap.com/questions/13359910/html5-application-with-managed-approuter-sometimes.html
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.
Mio Yasutake What did you mean when you said "Once I changed it to subaccount level destination, it started to work." ?
It is about:
modules:
In the xs-app.json:
When application try o consuming the library:
https://cbcfc61btrial.launchpad.cfapps.us10.hana.ondemand.com/route-test-commons.routetestcommons/~100222144610+0000~/library-preload.js --------> Wrong this returning 404.
But when I put the version:
https://cbcfc61btrial.launchpad.cfapps.us10.hana.ondemand.com/route-test-commons.routetestcommons-1.0.0/~100222144610+0000~/library-preload.js ------> Works
Can you help me?
My git:
https://github.com/KCezar/sapstudies/tree/master
Hi Kefren Conceição,
Yes, here is what I did, and it worked for me.
I think you don't need the following part in xs-app.json.
The code below is xs-app.json configuration for my main app.
You might find the following blog series helpful.
https://blogs.sap.com/2022/02/08/designing-ui5-apps-for-sap-launchpad-service-part-2/
Regards,
Mio
Hi Mio Yasutake,
The blog is great, thank you so much for sharing, the Matthias Schmalz explanation is amazing, but I think that my scenario is related to the unreleased third part. I tell you that because my library has its own mta in a different destination.
Part of mta.yaml of the library.
Part of application mta.yaml file.
But the error itself is very curious because the stack error on the console has the right path for accessing the library, but the application uses the wrong path.
Wouter Lemaire takes a look, what do you think about it?
Mio Yasutake I push a new version on Git.
Matthias Schmalz My Git for this problem is open if want takes a look too. If you want, I put a comment in your blog too.
My Git Example: https://github.com/KCezar/sapstudies/tree/master
Hi Kefren,
there is an inconsistency in the service names, between the manifest of the lib
https://github.com/KCezar/sapstudies/blob/875c72b969c03c8b5340b894a1f76d3e970b0d64/routeTest/commons/src/route/test/commons/manifest.json#L47
and the destination in the mta
https://github.com/KCezar/sapstudies/blob/875c72b969c03c8b5340b894a1f76d3e970b0d64/routeTest/commons/mta.yaml#L27
At one location you use dots as separators and at the other you use -, however the names must match exactly.
Best regards
Matthias
Hi Matthias Schmalzthanks for the help, your observation fixed the error. I'll be uploading the version to git and leaving the example for those who want to study.
I thank Mio Yasutake for his kindness and Wouter Lemaire for the blog that led to the discussions.
I would like to know if Cloud Foundry certification is a good option for understanding SAP's CF. I would like to know what you guys think.
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?
Thanks Wouter Lemaire , very useful!
Thanks Wouter Lemaire for this blog!
What we use to make this work in BAS and VSC without disturbing everything else is this:
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.
That’s even better, thanks for sharing! Would be even better to share an example app or make a pull request on my example 😉
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.
Regards,
Henning
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..
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?
Regards,
Ben
Hi,
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
npm run deploy cf
against your UI5 application.What is the content of ui5-deploy.yaml?
Here is a sample
https://github.com/SAP-samples/fiori-tools-samples/blob/main/cap/cap-fiori-mta/app/feproject-ui/ui5-deploy.yaml
You can also look to add a deployment script that will generate this for you baesd on your project properites;
https://github.com/SAP-samples/fiori-tools-samples/blob/main/cap/cap-fiori-mta/app/feproject-ui/package.json#L12
John
Dear John,
according to migration guide of SAPUI5 tooling (https://sap.github.io/ui5-tooling/v3/updates/migrate-v3/), the generateManifestBundle step which is used in the documentation was removed. Unfortunately, the steps how to do the migration and what to use instead is missing in the documentation, there is only a general statement that we shall use the "own mechanism of the HTML5 repository", which I do not know and not find.
Can you give us more information how to do the replacement? Unfortunately, our project does not work anymore.
Best regards,
Christine
Hi,
The sample apps are not using v3. If you are migrating using Fiori Tools migrator then it should be pulling in the latest v3 version and all the appropiate scripts/configurations should be reflecting this change.
The following repo https://github.com/SAP-samples/fiori-tools-samples/tree/main/neo-migration details migrating an application to Fiori Tools. However, this repo is still referencing V3 so your configurations will be newer
Where are you seeing the comment "own mechanism of the HTML5 repository"?
John
Hi,
thank you for your quick respond!
The comment is from here: https://sap.github.io/ui5-tooling/v3/updates/migrate-v3/
The exact wording is:
"This task was only needed for the HTML5 repository in Cloud Foundry. Meanwhile, the HTML5 repository implemented its own mechanism, so the task is no longer needed"
Best regards,
Christine
Here is a draft PR https://github.com/SAP-samples/fiori-tools-samples/pull/25 with ui5/cli changes and some v3 cleanup tasks as well.
generateManifestBundle is no longer required.
John
Thanks a lot, John. We found our issue. The problem was not the generateManifestBundle itself, but a custom task that was registred with beforeTask "generateManifestBundle". We changed it and now it works.
Thanks a lot for your examples!
Best regards
Christine
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.
Thanks,
This was just for testing purpose. You should keep them separated.
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:
The same as a ui5 app but the structure of a library is different. Make sure this is correct.
Wouter Lemaire , the "zip" script in the package.json was putting the content.zip file in the root folder rather than the dist folder. Once I removed "../" from that script, the content.zip 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?
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
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!
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,
Christian.
Hi Wouter Lemaire,
As mentioned in your blog, The library and the application should be in one project.
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)
Did you know that the BAS support library and the application are not in the same mta/project now?
Hi Wouter,
I really appreciate this blog!
However , I have not managed to get the usage of a library working on CF.
Even when I clone your example project and build and then deploy to CF the library is not loaded:
Failed to load component for container container - ModuleError: failed to load 'be/wl/examplelibrary/library.js' from /bewlexampleLibrary.bewlexamplelibrary/library.js: script load error
ModuleError: failed to load 'be/wl/examplelibrary/library.js' from /bewlexampleLibrary.bewlexamplelibrary/library.js: script load error
at se (https://sapui5.hana.ondemand.com/resources/sap-ui-core.js:10:7148)
at ne.failWith (https://sapui5.hana.ondemand.com/resources/sap-ui-core.js:10:4989)
at HTMLScriptElement.i (https://sapui5.hana.ondemand.com/resources/sap-ui-core.js:10:10946)
Caused by: Error: script load error
at HTMLScriptElement.i (https://sapui5.hana.ondemand.com/resources/sap-ui-core.js:10:10988)
Is there something on CF itself to be done to get the library "visible"?
It seems that manifest entry is not sufficient. Also, I noticed the your lib has a different cloud service id than the app. I thought it had to be the same?
Help please!