👋 This is a community project and there is no official support for this package! Feel free to use it, open issues, contribute, and help answering questions.
The UI5 tooling extensions include a custom middleware and a custom task which allow to use NPM package names for AMD-like dependencies, e.g.:
# Install a dev dependency to Chart.js (https://www.chartjs.org/)
npm install chart.js
// use Chart.js as a AMD-like dependency
sap.ui.define([
"chart.js"
], function(chartjs) {
[...]
alert(chartjs.version);
[...]
})
Once the UI5 application is finally built, the Chart.js dependency will be copied into the dist/resources
folder with the proper namespace. In case of Chart.js above, there is no namespace and thus the location will be dist/resources/chart.js.js
.
- Requires at least
@ui5/[email protected]
(to supportspecVersion: "3.0"
)
⚠️ UI5 Tooling Compatibility All releases of this tooling extension using the major version3
require UI5 Tooling V3. Any previous releases below major version3
(if available) also support older versions of the UI5 Tooling. But the usage of the latest UI5 Tooling is strongly recommended!
npm install ui5-tooling-modules --save-dev
The following configuration options are relevant for the task
and the middleware
:
-
debug:
boolean|string
Enables debug logging (defaults tofalse
), by setting value to"verbose"
the extension will log even more detailed -
skipCache:
boolean
For development scenarios, the module cache can be disabled by setting this option to true. Normally, if a module changes (e.g. bundledefs), this change is detected and the bundle is recreated. This just forces the regeneration always (defaults tofalse
) -
persistentCache:
boolean
experimental feature With this option, the bundle information will be persistent and will be available again after the restart of the development server or for the next execution of your build task. The bundle information is stored in the working directory in the folder.ui5-tooling-modules
folder. It's recommended to put this folder into.gitignore
(defaults tofalse
) -
keepDynamicImports:
boolean|String[]
experimental feature An arrays of NPM package names for which the dynamic imports with a generic target module (e.g.import(anyUrl)
) will not be converted into arequire
based polyfill. If the value is a boolean, it activates/deactivates the feature for all modules (by default it is active!). This experimental feature is useful in scenarios loading ES modules dynamically from generic URLs. All dynamic imports resolving a concrete module (e.g.import("jspdf")
) will be converted into chunks and loaded with arequire
call. -
skipTransform:
boolean|String[]
experimental feature Array of glob patterns to verify whether the module transformation should be skipped for the modules which are matching the glob pattern. If the value is aboolean
then the transformation can be skipped in general by setting the value totrue
. The configuration can be incorporated from thecustomConfiguration
of a dependency using that middleware, e.g. a library can provide itscustomConfiguration
for the application project like this (and can reuse the configuration internally via YAML anchors):specVersion: "3.0" metadata: name: com.myorg.mylib type: library customConfiguration: ui5-tooling-modules: &cfgModules skipTransform: - "@luigi-project/container/dist/anypath/**" builder: customTasks: - name: ui5-tooling-modules-task afterTask: replaceVersion configuration: <<: *cfgModules
-
inject:
Map<String, String|String[]>
experimental feature A map of Globals which are injected as imports to an NPM package to handle cases in which functions need to be poly- or ponyfilled. The configuration is aligned with definition of the Globals in the @rollup/plugin-inject:configuration: inject: # import setImmediate from 'set-immediate-shim' setImmediate: set-immediate-shim # import { Promise } from 'es6-promise' Promise: - es6-promise - Promise # import { Promise as P } from 'es6-promise' P: - es6-promise - Promise # import $ from 'jquery' $: jquery # import * as fs from 'fs' fs: - 'fs' - '*'
-
chunksPath:
boolean|string
Relative path for the chunks to be stored into (if value istrue
, chunks are put into the closest modules folder which was the default behavior in the3.5.x
release of the tooling extension) -
legacyDependencyResolution:
boolean
Re-enables the legacy dependency resolution of the tooling extension which allows to use entry points fromdevDependencies
of the project. By default, only thedependencies
maintained in the projects'package.json
and the transitive dependencies are considered for the entry points and all other entry points are ignored. (available since new minor version3.7.0
which introduces a new dependency resolution fordependencies
only) -
additionalDependencies:
string[]
List of additional dependency names to include into the bundling. By default all dependencies and their transitive dependencies are considered. In some cases it is useful to also include devDependencies, e.g. when re-packaging a thirdparty package. If you want to exclude this dependency from being a transitive dependency then you can put it into the devDependencies and list it in this configuration option (but keep in mind that this may exclude the dependency from some check tools!) -
minify:
boolean
experimental feature Flag to indicate that the generated code should be minified (in case of excluding thirdparty resources from minification in general, this option can be used to minify just the generated code)
The following configuration options are relevant for the task
and the middleware
which allow you to directly configure rollup plugins which is used as follows:
configuration:
pluginOptions: # map of plugin options
webcomponents: # the name of the rollup plugin
skip: true # configuration
The available plugin configuration options are:
-
pluginOptions.webcomponents.skip:
boolean
Flag to skip the transformation of Web Components to UI5 Controls a.k.a. Seamless Web Components support. This allows to directly require the Web Components modules from NPM packages and use them as UI5 Controls. The NPM packages providing Web Components must include a Custom Elements Manifest declared in thecustomElements
field in thepackage.json
. (defaults tofalse
) -
pluginOptions.webcomponents.force:
boolean
Flag to force the transformation of Web Components to UI5 Controls a.k.a. Seamless Web Components support. In some cases, in which the framework version cannot be part of theui5.yaml
, you can force the transformation. (defaults totrue
) -
pluginOptions.webcomponents.scoping:
boolean
Flag to disable the Custom Elements Scoping of UI5 Web Components. This allows to load multiple versions of UI5 Web Components into a single application without conflicts. This feature is enabled by default and can be disabled if needed. (defaults totrue
) -
pluginOptions.webcomponents.enrichBusyIndicator:
boolean
experimental flag Flag to include the BusyIndicator support from into the generated Web Components package module. (defaults tofalse
) -
pluginOptions.webcomponents.includeAssets:
boolean
experimental flag Flag to include all assets into the thirdparty folder: such as all themes and languages. Although they will be lazily loaded the generation process will slow down and you will have many additional files. All dynamic imports will reside inside the_dynamics
folder within the thirdparty folder. (defaults tofalse
)
The following configuration options are just relevant for the task
:
-
prependPathMappings:
boolean
Prepends the path mappings for the UI5 loader to theComponent.js
which allows to run the Component using 3rd party modules in e.g. Fiori launchpad environments (defaults tofalse
) -
addToNamespace:
boolean|string
Puts 3rd party modules into the namespace of the Component to make them Component-local. All used 3rd party modules will be moved by default into the sub-namespacethirdparty
of the Component namespace at build time. If you use a string as value ofaddToNamespace
you can define a custom namespace, e.g.my/namespace/for/libs
which will be nested in the Components' namespace. With that option you can run your application using 3rd party modules in a Fiori launchpad environment. In some cases (wrong dependency rewrite, wish to keep 3rd party modules in theresources
path, ...) it might be necessary to disable this option. (defaults totrue
, disables prependPathMappings when set totrue
)⚠️ While this works great for any non-UI5 3rd party module, there are limitations for the consumption of UI5 modules from custom control 3rd party modules (NPM packages). The UI5 module names (used forObject.extend(...)
, aggregation types, ...) are not rewritten and this may cause issues. UI5 assumes that the used module path (slash syntax) is matching the module name (dot syntax). This can lead to issues forObject.isA(...)
checks, Renderer lookups (when not inlined or referenced by module), or for any other API which derives the module name from the module path or vice versa. If you encounter such issues you may consider to disable the option and instruct the loader viasap.ui.loader.config({ paths: ... })
to load the resources properly. -
removeScopePrefix:
boolean
Removes the scope prefix@
from the namespace/path of the 3rd party module when adding it to the namespace with the addToNamespace option. -
providedDependencies:
String[]
An array of NPM package names which will be available in the development server via the middleware but will be ignored for the build process via the task. Provided dependencies are considered as being provided by the application runtime rather than it must be shipped with the current project. Provided dependencies will ignore any of the configurations above. -
includeAssets:
Map<String, String[]>
experimental feature A map of NPM package names to list of glob patterns which defines the assets to be included. The list of glob patterns can be omitted in case of copying all resources of the NPM package.
The following configuration options are just relevant for the middleware
:
- watch:
boolean
experimental flag For development scenarios, the server is listening to changes of the source files of the project and its dependencies and triggers the generation of the bundle if the used NPM packages have been changed (defaults totrue
)
- Define the dependency in
$yourapp/package.json
:
"devDependencies": {
// ...
"ui5-tooling-modules": "*"
// ...
}
- Configure it in
$yourapp/ui5.yaml
:
The configuration for the custom task:
builder:
customTasks:
- name: ui5-tooling-modules-task
afterTask: replaceVersion
The configuration for the custom middleware:
server:
customMiddleware:
- name: ui5-tooling-modules-middleware
afterMiddleware: compression
⚠️ In case your application is using a proxy suchfiori-tools-proxy
, the proxy must run afterui5-tooling-modules-middleware
middleware. Otherwise proxy will try to serve the resources for your installed npm package instead ofui5-tooling-modules-middleware
. You can achieve this by settingafterMiddleware: ui5-tooling-modules-middleware
infiori-tools-proxy
middleware.
🔥 TIP 🔥
YAML anchors are a great feature to avoid redundancies in .yaml
files. You can share the configuration of the task
and the middleware
in the following way:
ui5.yaml
customConfiguration:
ui5-tooling-modules: &cfgModules
debug: true
keepDynamicImports:
- "@luigi-project/container"
[...]
server:
customMiddleware:
- name: ui5-tooling-modules-middleware
afterMiddleware: compression
configuration:
<<: *cfgModules
[...]
builder:
customTasks:
- name: ui5-tooling-modules-task
afterTask: replaceVersion
configuration:
<<: *cfgModules
addToNamespace: true
With this approach you can ensure that you have a consistent configuration across your task
and middleware
.
The custom middleware is listening to incoming requests and checks those requests to match npm packages. E.g. a dependency to chart.js
will cause a request to resource/chart.js.js
. The middleware now derives the module name which is "chart.js"
and uses require.resolve("chart.js")
to lookup the npm package for it. If an npm package exists, the middleware is using rollup
to create a custom AMD bundle for the npm package which uses sap.ui.define
instead of define
.
The custom task is scanning all AMD dependencies of all modules and tries to resolve the module names. If a module has been found a custom bundle will be created in the proper namespace of the module, e.g. @apollo/client/core
will create a custom bundle at dist/resources/@apollo/client/core.js
.
Please use the GitHub bug tracking system to post questions, bug reports or to create pull requests.
Any type of contribution (code contributions, pull requests, issues) to this showcase will be equally appreciated.
This work is dual-licensed under Apache 2.0 and the Derived Beer-ware License. The official license will be Apache 2.0 but finally you can choose between one of them if you use this work.
When you like this stuff, buy @vobu a beer or buy @pmuessig a coke when you see them.