Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions internal/documentation/docs/pages/Builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,30 @@ sap.ui.define([], () => {
text-decoration: inherit;
}
</style>

## Build Cache Control

The UI5 Builder integrates **build caches**. Instead of rebuilding everything from scratch, the UI5 Builder tracks which resources have changed and which build tasks need to be re-executed:

You can control the build cache behavior using the `--cache` option:

- `--cache Default` (default): Use the cache if available, create it if missing
- `--cache Force`: Only use the cache; fail if the cache is unavailable or invalid
- `--cache ReadOnly`: Use existing cache but don't update it (useful for CI/CD)
- `--cache Off`: Disable caching entirely and always perform a full rebuild

Example:
```sh
ui5 build --cache Off
```
In this scenario, when a source file is changed, always perform a full rebuild, even if this source version existed previously.

::: info
By default, the build cache is stored inside UI5 CLI's Data Dir (`~/.ui5/buildCache/`). You can customize the location (see [Changing UI5 CLI's Data Directory](./Troubleshooting#changing-ui5-cli-s-data-directory)).
:::

::: info
By default, build caches created by `ui5 build` and `ui5 serve` are **separate and cannot be mixed**. Each command executes a distinct set of tasks, resulting in separate caches tailored to its specific use case. For more details on server caching, see the [UI5 Server documentation](./Server.md).
:::


45 changes: 44 additions & 1 deletion internal/documentation/docs/pages/Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Please be aware of the following risks when using the server:
## Standard Middleware

::: info Removed Middleware
The `serveThemes` middleware has been removed in UI5 CLI v5. Theme compilation is now handled by the `buildThemes` build task during the incremental build, which pre-compiles all theme CSS files. The resulting CSS files (including `library.css`, `library-RTL.css`, `library-parameters.json`, and CSS Variables resources) are served via the `serveResources` middleware, providing the same functionality with better performance through build-time compilation and caching.
The `serveThemes` middleware has been removed in UI5 CLI v5. Theme compilation is now handled by the `buildThemes` build task, which pre-compiles all theme CSS files. The resulting CSS files (including `library.css`, `library-RTL.css`, `library-parameters.json`, and CSS Variables resources) are served via the `serveResources` middleware, providing the same functionality with better performance through build-time compilation and caching.

Custom middleware previously referencing `serveThemes` via `beforeMiddleware` or `afterMiddleware` will continue to work with automatic remapping and a deprecation warning. See the [v5 migration guide](../updates/migrate-v5.md) for details.
:::
Expand Down Expand Up @@ -87,6 +87,49 @@ Answers all non-read requests (POST, PUT, DELETE, etc.) that have not been answe
### serveIndex
In case a directory has been requested, this middleware renders an HTML with a list of the directory's content.

## Standard Tasks
As with the UI5 Builder, a set of standard tasks is being executed during a server build. However, the following tasks are being **excluded by default**:
- `minify`
- `generateLibraryPreload`
- `generateComponentPreload`
- `generateBundle`

::: info
See [Builder Standard Tasks](./Builder.md#standard-tasks) for more explanation about each task.
:::

## Build Cache Control

The UI5 Server performs a build of the projects by utilizing **build caches**.

You can control the build cache behavior using the `--cache` option:

- `--cache Default` (default): Use the cache if available, create it if missing
- `--cache Force`: Only use the cache; fail if the cache is unavailable or invalid
- `--cache ReadOnly`: Use existing cache but don't update it (useful for CI/CD)
- `--cache Off`: Disable caching entirely and always perform a full rebuild

Example:
```sh
ui5 serve --cache Off
```
In this scenario, when a source file changes and a request comes in, the server always performs a full rebuild, even if this source version existed previously.

::: info
By default, build caches created by `ui5 build` and `ui5 serve` are **separate and cannot be mixed**. Each command executes a distinct set of tasks, resulting in separate caches tailored to its specific use case. For more details on builder caching, see the [UI5 Builder documentation](./Builder.md).
:::

### Watch Mode Behavior

Once started with `ui5 serve`, the server automatically monitors changes to the source files throughout the session. When a request arrives, it checks for cached results first and only triggers a rebuild of the respective resources and tasks if no cache is available.

- **Monitored files**: All files in your project's source directories (`src/`, `webapp/`, `test/`, etc.)
- **Not monitored**: Configuration files (`ui5.yaml`, `package.json`), custom task implementations, and dependency files

::: info
Changes to configuration files or custom tasks require a server restart to take effect.
:::

## SSL Certificates
When starting the UI5 Server in HTTPS- or HTTP/2 mode, for example by using UI5 CLI parameter `--h2`, you will be prompted for the automatic generation of a local SSL certificate if necessary.

Expand Down
129 changes: 106 additions & 23 deletions internal/documentation/docs/pages/extensibility/CustomTasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ A custom task implementation needs to return a function with the following signa
* Namespace of the project currently being built
* @param {string} parameters.options.configuration
* Custom task configuration, as defined in the project's ui5.yaml
* @param {string[] | undefined} parameters.changedProjectResourcePaths
* List of changed resource paths since last execution.
* Only used if the task supports differential builds (supportsDifferentialBuilds=true).
* Returns undefined if unsupported or no cache is available.
* @param {string[] | undefined} parameters.changedDependencyResourcePaths
* List of changed dependency resource paths since last execution.
* Only used if the task supports differential builds (supportsDifferentialBuilds=true).
* Returns undefined if unsupported or no cache is available.
* @param {string} parameters.options.taskName
* Name of the custom task.
* This parameter is only provided to custom task extensions
Expand Down Expand Up @@ -166,6 +174,14 @@ export default async function({dependencies, log, options, taskUtil, workspace})
* Namespace of the project currently being built
* @param {string} parameters.options.configuration
* Custom task configuration, as defined in the project's ui5.yaml
* @param {string[] | undefined} parameters.changedProjectResourcePaths
* List of changed resource paths since last execution.
* Only used if the task supports differential builds (supportsDifferentialBuilds=true).
* Returns undefined if unsupported or no cache is available.
* @param {string[] | undefined} parameters.changedDependencyResourcePaths
* List of changed dependency resource paths since last execution.
* Only used if the task supports differential builds (supportsDifferentialBuilds=true).
* Returns undefined if unsupported or no cache is available.
* @param {string} parameters.options.taskName
* Name of the custom task.
* This parameter is only provided to custom task extensions
Expand Down Expand Up @@ -286,15 +302,60 @@ module.exports.determineRequiredDependencies = async function({availableDependen
```
:::

### "Cache-aware" Tasks

Due to UI5 Builder and UI5 Server supporting **build caches** of task data, custom tasks can opt into this behavior to improve performance. To do this, export optional callback functions in your task implementation:

#### `supportsDifferentialBuilds()`

::: code-group
```js [ESM]
/**
* Indicates whether the task supports differential builds
*
* Tasks that support differential builds can use incremental cache invalidation,
* processing only changed resources rather than rebuilding from scratch.
*
* @public
* @returns {boolean} True if differential builds are supported
*/
export function supportsDifferentialBuilds() {
return true;
}
```

```js [CommonJS]
/**
* Indicates whether the task supports differential builds
*
* Tasks that support differential builds can use incremental cache invalidation,
* processing only changed resources rather than rebuilding from scratch.
*
* @public
* @returns {boolean} True if differential builds are supported
*/
module.exports.supportsDifferentialBuilds = function() {
return true;
}
```

When this returns `true`, your task's main function receives an additional parameter `changedProjectResourcePaths`. This parameter provides an array of changed resource paths (strings) since its last execution. The task then processes only those resources instead of all resources. If this callback isn't provided or returns a falsy value, your task can't use incremental cache invalidation and processes all resources from scratch.

::: info Best Practices for Cache-aware Tasks
1. **Keep tasks deterministic**: Given the same inputs, always produce the same outputs
2. **Opt into differential builds carefully**: Only set `supportsDifferentialBuilds = true` if your task can safely process files independently
:::

### Examples

The following code snippets show examples for custom task implementations.

### Example: lib/tasks/renderMarkdownFiles.js
#### Example: lib/tasks/renderMarkdownFiles.js
Comment thread
matz3 marked this conversation as resolved.

This example is making use of the `resourceFactory` [TaskUtil](https://ui5.github.io/cli/v5/api/@ui5_project_build_helpers_TaskUtil.html)
API to create new resources based on the output of a third-party module for rendering Markdown files. The created resources are added to the build
result by writing them into the provided `workspace`.
In addition, this task supports differential builds, which re-process only changed resources.

::: code-group

Expand All @@ -305,26 +366,37 @@ import renderMarkdown from "./renderMarkdown.js";
/*
* Render all .md (Markdown) files in the project to HTML
*/
export default async function({dependencies, log, options, taskUtil, workspace}) {
export default async function({dependencies, log, options, taskUtil, workspace, changedProjectResourcePaths}) {
const {createResource} = taskUtil.resourceFactory;
const textResources = await workspace.byGlob("**/*.md");
await Promise.all(textResources.map(async (resource) => {
const markdownResourcePath = resource.getPath();

log.info(`Rendering markdown file ${markdownResourcePath}...`);
const htmlString = await renderMarkdown(await resource.getString(), options.configuration);

// Note: @ui5/fs virtual paths are always (on *all* platforms) POSIX. Therefore using path.posix here
const newResourceName = path.posix.basename(markdownResourcePath, ".md") + ".html";
const newResourcePath = path.posix.join(path.posix.dirname(markdownResourcePath), newResourceName);

const markdownResource = createResource({
path: newResourcePath,
string: htmlString
});
await workspace.write(markdownResource);
}));
let textResources;

if (changedProjectResourcePaths) {
textResources = await Promise.all(changedProjectResourcePaths.map((resource) => workspace.byPath(resource)));
} else {
textResources = await workspace.byGlob("**/*.md");
}

await Promise.all(textResources.map(async (resource) => {
const markdownResourcePath = resource.getPath();

log.info(`Rendering markdown file ${markdownResourcePath}...`);
const htmlString = await renderMarkdown(await resource.getString(), options.configuration);

// Note: @ui5/fs virtual paths are always (on *all* platforms) POSIX. Therefore using path.posix here
const newResourceName = path.posix.basename(markdownResourcePath, ".md") + ".html";
const newResourcePath = path.posix.join(path.posix.dirname(markdownResourcePath), newResourceName);

const markdownResource = createResource({
path: newResourcePath,
string: htmlString
});
await workspace.write(markdownResource);
}));
};

export function supportsDifferentialBuilds() {
return true;
}
```

```js [CommonJS]
Expand All @@ -334,10 +406,17 @@ const renderMarkdown = require("./renderMarkdown.js");
/*
* Render all .md (Markdown) files in the project to HTML
*/
module.exports = async function({dependencies, log, options, taskUtil, workspace}) {
module.exports = async function({dependencies, log, options, taskUtil, workspace, changedProjectResourcePaths}) {
const {createResource} = taskUtil.resourceFactory;
const textResources = await workspace.byGlob("**/*.md");
await Promise.all(textResources.map(async (resource) => {
let textResources;

if (changedProjectResourcePaths) {
textResources = await Promise.all(changedProjectResourcePaths.map((resource) => workspace.byPath(resource)));
} else {
textResources = await workspace.byGlob("**/*.md");
}

await Promise.all(textResources.map(async (resource) => {
const markdownResourcePath = resource.getPath();

log.info(`Rendering markdown file ${markdownResourcePath}...`);
Expand All @@ -354,6 +433,10 @@ module.exports = async function({dependencies, log, options, taskUtil, workspace
await workspace.write(markdownResource);
}));
};

module.exports.supportsDifferentialBuilds = function() {
return true;
}
```
:::

Expand All @@ -364,7 +447,7 @@ Tasks should ideally use the reader/writer APIs provided by UI5 CLI for working

:::

### Example: lib/tasks/compileLicenseSummary.js
#### Example: lib/tasks/compileLicenseSummary.js

This example is making use of multiple [TaskUtil](https://ui5.github.io/cli/v5/api/@ui5_project_build_helpers_TaskUtil.html)
APIs to retrieve additional information about the project currently being built (`taskUtil.getProject()`) and its direct dependencies
Expand Down
46 changes: 44 additions & 2 deletions internal/documentation/docs/updates/migrate-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,48 @@ UI5 CLI 5.x introduces **Specification Version 5.0**, which enables the new Comp

Projects using older **Specification Versions** are expected to be **fully compatible with UI5 CLI v5**.

## Build Cache

UI5 CLI v5 introduces **builds with caching** for both the `ui5 build` and `ui5 serve` commands. This fundamental architectural change significantly improves build performance by reusing cached results from previous builds. It also simplifies development with the server by making most custom middleware obsolete.

### What Changed

**Previous Behavior (v4 and earlier):**
- Every source change resulted in a full rebuild of all projects
- Every build re-executed all tasks
- No caching between builds or server sessions
- Custom middleware was required for special actions

**New Behavior (v5):**
- Only relevant projects are rebuilt
- Only modified resources and affected tasks are re-processed
- Some custom middleware is now obsolete as it can be replaced with build tasks

### Impact on Your Workflow

- **First build**: Probably slightly slower as the cache is populated with all build outputs
- **Subsequent builds**: Significantly faster — only modified resources and affected tasks are reprocessed
- **Quick iterations**: Changes to individual files typically rebuild very quickly
- **Cross-session**: Caches are used between server restarts and build runs

### For `ui5 build`

When `ui5 build` is executed, build caches are automatically serialized and reused when available.

::: tip Tip for Single Builds (e.g. CI/CD)
If you plan to execute a build only once (for example during a CI run), consider using `--cache "Off"` (see [Build Cache Control](../pages/Builder.md#build-cache-control)) to skip cache serialization.
:::

### For `ui5 serve`

The UI5 Server now performs a build of the project. When started with `ui5 serve`, a similar build to `ui5 build` is executed containing standard and custom tasks (see [exceptions](../pages/Server.md#standard-tasks)).

During a server session, source changes are automatically monitored. When a request is made, the server detects this, tries to use caches, and only rebuilds when none are available. For more information, see [Watch Mode Behavior](../pages/Server.md#watch-mode-behavior).

::: tip Review custom middleware
Due to **build tasks now being executed in server sessions**, custom middleware becomes obsolete if a corresponding task can perform the same actions (for example, Typescript transpilation). However, custom middleware for non-build purposes, such as proxies, are not affected by this and are still a valid use case.
:::

## Rename of Command Option

With UI5 CLI v5, the option `--cache-mode` (for commands `ui5 build` and `ui5 serve`) has been renamed to `--snapshot-cache`.
Expand Down Expand Up @@ -210,13 +252,13 @@ The test suite is now served under the standard `/test-resources/` path with the

The following middleware has been removed from the [standard middlewares list](../pages/Server.md#standard-middleware):

* `serveThemes` — Theme compilation (LESS to CSS) is now handled by the `buildThemes` build task during the incremental build, rather than on demand during runtime. The resulting CSS files are served via the `serveResources` middleware. This change improves performance through build-time compilation and caching while maintaining the same functionality.
* `serveThemes` — The `buildThemes` build task now handles theme compilation (LESS to CSS). Because server sessions now also perform builds, this task runs during a server start instead of on demand during runtime. The resulting CSS files are served by the `serveResources` middleware. This change improves performance through build-time compilation and caching while maintaining the same functionality.

**Backward Compatibility:**
If your project or any custom middleware references a removed middleware via `beforeMiddleware` or `afterMiddleware`, UI5 CLI will automatically remap the reference to the nearest remaining middleware and log a deprecation warning. Your custom middleware will still be executed in the expected order.

**What Changed:**
- Theme CSS files (`library.css`, `library-RTL.css`, etc.) are now **pre-built** during the incremental build
- Theme CSS files (`library.css`, `library-RTL.css`, etc.) are now **pre-built**
- Files are served via `serveResources` instead of being compiled on demand
- The same CSS files are available at the same URLs as before

Expand Down
Loading