Ui5Library
Introduction
A Ui5Library is a frontend-only artifact in LaravelUi5 that encapsulates a reusable UI5 library developed outside the Laravel application. Typical use cases include formatting utilities, reusable UI components, or shared business logic intended to be consumed by multiple UI5 apps.
Each library is integrated into the Laravel app as part of a Ui5Module, and can later be discovered, versioned, and served through the LaravelUi5 registry.
📝 Note
A module can contain either a UI5 app or a UI5 library — but never both.
Conceptual Overview
LaravelUi5 supports importing fully built UI5 libraries and wrapping them as native Laravel modules. This integration includes:
- Direct access to all build assets (e.g., preload files, message bundles).
- Rich metadata extracted from
.library,package.json, andui5.yaml. - Clean namespacing on both the backend (PHP) and frontend (JavaScript).
A library module is a package like an app module, and it may carry backend artifacts where it needs them — a Resource or an Action that ships alongside its controls is a legitimate shape. Most libraries need none and serve purely as shared dependencies.
How to Generate
Use the following Artisan command to generate a new UI5 library:
php artisan ui5:lib Charts --create --package-prefix=acme --php-ns-prefix=AcmeThis assumes a source folder exists next to the host in one of the following forms:
../ui5-charts-lib/ ← LaravelUi5 naming convention, always searched
../com.acme.charts/ ← SAP Easy UI5 convention, searched with --js-ns-prefix=com.acmeThe folder names the module: ui5-charts-lib becomes ui5/Charts, and the package acme/charts.
Before running the command, make sure to build the library via:
npm install && npm run build📝 Scaffolding the source side with
yo easy-ui5When you generate the UI5 source project via SAP's Easy UI5 generator, it will ask "Would you like to omit the namespace in thesrcandtestfolder?" — answerY. LaravelUi5 reads the built library fromdist/resources/{namespace-as-path}/, whichui5 buildproduces correctly either way; but the flatsrc/layout is whatui5:libhas been exercised against, and it keeps the source tree shallow. The namespace-foldedsrc/variant is untested with the LaravelUi5 generator — pick the flat one unless you have a reason not to.
Options
| Option | Description |
|---|---|
--create | Scaffold a new library module (fails if it already exists) |
--refresh | Refresh metadata and assets from the source project |
--no-build | Skip the UI5 build before importing assets (build runs by default) |
--package-prefix | Required on --create. Composer vendor of the package, e.g. acme |
--php-ns-prefix | Required on --create. PHP namespace prefix, e.g. Acme |
--js-ns-prefix | Optional. Also look for an Easy UI5 source folder, e.g. com.acme |
⚠️ The identity options have no defaults. A
changed in 3.0The generator no longer falls back to our own vendor names.--createwithout them aborts before doing anything and prints a complete command line; a malformed value aborts too.--refreshneeds neither. There is no--vendor: a library's vendor comes from its.library. The UI5 namespace is not an option either — it comes from the built.library, which is why--js-ns-prefixonly widens the search for the source folder.
⚠️ Pass
--createor--refreshexplicitly. Without either, the command only reports whether the module exists, names the flag to use, and writes nothing.
Output
Upon successful execution, the following artifacts are generated inside the Laravel project:
ui5/Charts/
├── composer.json ← Composer package file (written once)
├── src/
│ ├── ChartsLibrary.php ← Library metadata class
│ ├── ChartsModule.php ← Module wrapper (written once)
│ └── ChartsServiceProvider.php ← Laravel provider (written once)
└── resources/ui5/ ← UI5 assets (preloads, messages, etc.)composer.json and the provider make the library a package: its name(acme/charts), the PSR-4 root over src/, and the provider under extra.laravel.providers. --create writes both once and --refresh leaves them alone, exactly as for an app. The command closes by printing the host registration — two composer commands and the line for config/ui5.php below.
The build assets are copied from the following folder:
../ui5-charts-lib/dist/resources/com/acme/charts/Metadata Resolution
LaravelUi5 reads library metadata from three locations in the source folder — but only one of them supplies the values that end up in the class.
ui5.yaml
Supplies the UI5 namespace, which is what tells the generator where to look for everything else:
metadata:
name: com.acme.charts.library XML
The real metadata source. The generator reads the built descriptor at dist/resources/{namespace-as-path}/.library and takes all five values from it:
.library element | Becomes |
|---|---|
<name> | NAMESPACE |
<version> | the module's VERSION, at --create only |
<title> | TITLE |
<documentation> | DESCRIPTION |
<vendor> | getVendor() |
Because it reads the built file, a missing dist/ is a hard error naming the build command rather than a class full of placeholders: a Missing .library file error that names the project folder and the build script to run.
package.json
Supplies the build command the generator runs (and names in that error). The library's version reaches the class through .library, not from here — though the UI5 build is what copies it across, so the two agree by construction.
Class Structure
ChartsLibrary.php
Extends AbstractUi5Library and implements Ui5LibraryInterface. Identity is baked in as class constants at generate time — read from the source project, then written into the class:
use LaravelUi5\Core\Ui5\AbstractUi5Library;
class ChartsLibrary extends AbstractUi5Library
{
public const string NAMESPACE = 'com.acme.charts';
public const string TITLE = 'Charts';
public const string DESCRIPTION = 'Shared charting controls.';
public function getVendor(): string
{
return 'Acme GmbH';
}
}The matching getters — getNamespace(), getTitle(), getDescription() — come from the HasArtifactIdentity trait; they read the constants, they do not re-read ui5.yaml or package.json at runtime. A --refresh re-derives the values and rewrites the class. changed in 7.0The version is the module's (ChartsModule::VERSION), written once at --create from <version> and kept by hand after that; --refresh no longer touches it.
All five values come from the built .library descriptor — see Metadata Resolution above.
getType() (returning CoreArtifactType::Library), getModule() and getSource() come from the base and are not re-declared.
⚠️ A library has no base/leaf split — and this class is rewritten. Unlike Ui5App,
ui5:libemits a single Library class and--refreshrewrites it in full, so anything you hand-add here is lost on the next refresh. That is safe by design: a library carries no developer-authored members — no OData schema, no manifest fragment, no access gate — so there is nothing a leaf would need to protect. The PHP namespace is the one exception; likeui5:app,--refreshreads it back out of the existing class and aborts rather than clobber it if it cannot be parsed.
ChartsModule.php
The namespace-keyed container. It names the Library in ARTIFACT_ROOT as its root artifact and derives its own namespace from ChartsLibrary::NAMESPACE.
Unlike the Library class, the Module is written once at --create and never regenerated — because its ARTIFACTS list is where you register the module's sub-artifacts by hand, and a refresh would wipe those registrations. So the ownership line in a library module runs between the two files: the Library is the framework's, the Module is yours.
Module Integration
Point Composer at the module and require it, as the generator prints:
composer config repositories.charts path ui5/Charts
composer require acme/charts:@devEach library is part of a domain-specific module. Modules are registered as a class-only array in your application's config/ui5.php — the registry derives the namespace from the module's root artifact (here, from ChartsLibrary::NAMESPACE):
// config/ui5.php
return [
'modules' => [
\Acme\Charts\ChartsModule::class,
],
];No keyed slugs. The namespace is single-sourced from the Library class, and every asset URL is derived from it.
Best Practices
- Keep each library focused on a single responsibility
- Follow semantic versioning in
package.json - Use consistent naming between the JS namespace, folder name, and PHP class
- Avoid bundling business logic into libraries — delegate that to apps