Skip to content

UI5 Shims

Marco Beier edited this page Feb 6, 2021 · 5 revisions

What is a Shim?

Find the proper explanation here in wikipedia. In short a Shim is a compatibility extension to enable you to use newer, more advanced features, functions or tools in your current project environment. Another word for Shim would be Polyfill although not completely the same they both exist for the same reason ~ "a polyfill is a shim for a browser API".

Within this documentation I'll be demonstrating one of the most recurring use-cases for Shims in UI5:

  • Including an external library that you've pulled into your project either via npm (node_modules) or manually into a libs-folder within your application (pre-build library).

Manual - Library Shim

Imagine our project structure being like the following.

.webapp
├── controller
│   ├── Base.js
│   ├── Home.controller.js
├── css
│   └── style.css
├── i18n
├── libs
│   └── marked.min.js
├── model
├── resources
├── util
│   └── marked.js
├── view
│   ├── Home.view.xml
├── Component.js
├── index.html
└── manifest.json

Important is that we've pulled our external library, here marked.js, manually into our project (the libs folder). It is a minified, pre-build version of the library. Physically our external library now 'sits' in our application but we cannot use it yet. We need a way to pull in the dependency at runtime and get access to the object of the library in order to use it.

We do this by configuring the sap.ui.loader within our component.js file. I chose to do this within the component.js file to have configuration steps on a central point of my application. You could also just do this right before actually defining the dependency within your respective controller or other files.

The path to the library consists of <namespace.projectname.folder.file> it's a mapping to the virtual path within the application at runtime. The value of exports has to match the object that is being exported by the library. For example for the library highlight.js it's not just highlight, it's actually hljs => {exports: "hljs"}.

Check out the sap.ui.loader namespace.

sap.ui.loader.config({
    async: true,
    shim: {
        "sapmarco/projectpages/libs/marked.min": {
            amd: true,
            exports: "marked",
        }
    },
});

In order to consume the library you just use sap.ui.define as you're used to.

sap.ui.define(["sapmarco/projectpages/libs/marked.min"], function (Marked) {
    "use strict";

    Marked.setOptions({
        highlight: function (code, lang) {
            //do something in here
        }
    });
});

UI5-Tooling - Project-Shim

Imagine our project structure being like the following.

.webapp
├── controller
│   ├── Base.js
│   ├── Home.controller.js
├── css
│   └── style.css
├── i18n
├── model
├── resources
├── util
│   └── marked.js
├── view
│   ├── Home.view.xml
├── Component.js
├── index.html
└── manifest.json
package.json
ui5.yaml

What changed? We're not longer required to use a custom prebuild library file within a libs folder. Instead we make use of the package.json file and the UI5-Tooling with it's configuration file, the ui5.yaml.

The package.json not only holds references to our application dependencies, in here we also have a "ui5 dependency array". This array is filled with dependencies that should be known to the UI5-Tooling. Whether or not the tooling is picking those dependencies up can be checked with the ui5 tree command in your console.

"dependencies": {
        "marked": "^1.1.0",
},
"ui5": {
        "dependencies": [
                "marked",
        ]
}

The following is an example configuration for the marked.js library. You can find another example for lodash here.

---
specVersion: "2.2"
type: project-shim
metadata:
  name:  projectpages.thirdparty
kind: extension
shims:
  configurations:
    marked: # name of module as in package.json
      specVersion: "2.2"
      type: module
      metadata:
        name: marked
      resources:
        configuration:
          paths:
            /resources/thirdparty/marked/: "" # virtual path mapping

In order to consume the library you just use sap.ui.define as you're used to. Beware that your parameter inside the following function will just be a placeholder as you're using the actual object of the library and none that get's imported due to declaring & loading the dependency here. Example: parameter of our function is called markedjs at runtime however this will be undefined and we will have access to the actual marked object from the library.

The path of the library within the node_modules folder is mapped to the /resources/thirdparty/marked path at runtime. Inside this folder we can look for our library file marked.min the .js gets appended by the framework when requiring it.

Check out Path Mapping of Modules as the "Project-Shim" we're using here is also of type module.

sap.ui.define(["thirdparty/marked/marked.min"], function (markedjs) {
    "use strict";

    marked.setOptions({
        highlight: function (code, lang) {
            //do something in here
        }
    });
});

Credits

Clone this wiki locally