From 3f8c259ab7efa04ea4b13e64ceec8708bc98c8b8 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 6 Jul 2026 11:20:09 +0200 Subject: [PATCH 1/4] refactor(server): Forward includedTasks/excludedTasks to graph.serve() Accept 'includedTasks' and 'excludedTasks' on serve()'s options and pass them through to graph.serve() as-is. The hardcoded exclusion list that used to live here (minify, generateLibraryPreload, generateComponentPreload, generateBundle) is dropped: the dev server now runs the same task set as a regular build unless the caller opts out via 'excludedTasks'. Enables the follow-up 'ui5 serve --include-task' / '--exclude-task' plumbing in @ui5/cli. --- packages/server/lib/server.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/server/lib/server.js b/packages/server/lib/server.js index 9d367386585..cee67f08326 100644 --- a/packages/server/lib/server.js +++ b/packages/server/lib/server.js @@ -138,6 +138,10 @@ async function _addSsl({app, key, cert}) { * @param {string} [options.ui5DataDir] Explicit UI5 data directory to use for the build cache. * Overrides the UI5_DATA_DIR environment variable, * the UI5 configuration file, and the default of ~/.ui5. + * @param {string[]} [options.includedTasks] A list of tasks to be added to the default execution set. + * Takes precedence over excludedTasks. + * @param {string[]} [options.excludedTasks] A list of tasks to be excluded from the default task + * execution set. * @param {Function} error Error callback. Will be called when an error occurs outside of request handling. * @returns {Promise} Promise resolving once the server is listening. * It resolves with an object containing the port, @@ -148,7 +152,7 @@ export async function serve(graph, { port: requestedPort, changePortIfInUse = false, h2 = false, key, cert, acceptRemoteConnections = false, sendSAPTargetCSP = false, simpleIndex = false, liveReload = false, serveCSPReports = false, cache = Cache.Default, - ui5DataDir, + ui5DataDir, includedTasks, excludedTasks, }, error) { const rootProject = graph.getRoot(); @@ -186,7 +190,8 @@ export async function serve(graph, { } const buildServer = await graph.serve({ initialBuildIncludedDependencies, - excludedTasks: ["minify", "generateLibraryPreload", "generateComponentPreload", "generateBundle"], + includedTasks, + excludedTasks, cache, ui5DataDir, }); From b23c66010e76ce113403537b958f97cc239899ec Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 6 Jul 2026 11:20:40 +0200 Subject: [PATCH 2/4] refactor(cli): Share --include-task / --exclude-task with 'ui5 serve' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both 'ui5 build' and 'ui5 serve' trigger a build internally and honour the same task filters, but until now only 'build' exposed the CLI flags. Add an 'applyBuildOptions(cli)' helper to lib/cli/options.js — same pattern as the existing 'applyProjectConfigOptions' / 'applyWorkspaceOptions' — and call it from both commands. 'serve.handler' forwards the values into the server config under the API names 'includedTasks' / 'excludedTasks' (mirroring 'build.handler'). Combined with the sibling refactor in @ui5/server, this means 'ui5 serve --exclude-task buildThemes' or 'ui5 serve --include-task minify' now Do The Right Thing. Existing serve-command tests asserted deepEqual on the full config bag passed to @ui5/server.serve — those blocks now include 'includedTasks: undefined, excludedTasks: undefined'. A new test covers the flags flowing through the handler. --- packages/cli/lib/cli/commands/build.js | 14 ++----------- packages/cli/lib/cli/commands/serve.js | 5 ++++- packages/cli/lib/cli/options.js | 23 +++++++++++++++++++++ packages/cli/test/lib/cli/commands/serve.js | 21 +++++++++++++++++++ 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/packages/cli/lib/cli/commands/build.js b/packages/cli/lib/cli/commands/build.js index c8d218abc45..af7d82890c9 100644 --- a/packages/cli/lib/cli/commands/build.js +++ b/packages/cli/lib/cli/commands/build.js @@ -1,5 +1,5 @@ import baseMiddleware from "../middlewares/base.js"; -import {applyProjectConfigOptions, applyWorkspaceOptions, dedupeArray} from "../options.js"; +import {applyProjectConfigOptions, applyWorkspaceOptions, applyBuildOptions, dedupeArray} from "../options.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("cli:commands:build"); @@ -13,6 +13,7 @@ const build = { build.builder = function(cli) { applyProjectConfigOptions(cli); applyWorkspaceOptions(cli); + applyBuildOptions(cli); return cli .command("jsdoc", "Build JSDoc resources", { handler: handleBuild, @@ -113,17 +114,6 @@ build.builder = function(cli) { default: false, type: "boolean" }) - .option("include-task", { - describe: "A list of tasks to be added to the default execution set. " + - "This option takes precedence over any excludes.", - type: "string", - array: true - }) - .option("exclude-task", { - describe: "A list of tasks to be excluded from the default task execution set", - type: "string", - array: true - }) .option("framework-version", { describe: "Overrides the framework version defined by the project. " + "Takes the same value as the version part of \"ui5 use\"", diff --git a/packages/cli/lib/cli/commands/serve.js b/packages/cli/lib/cli/commands/serve.js index 3a21e227b7f..e70924bc53f 100644 --- a/packages/cli/lib/cli/commands/serve.js +++ b/packages/cli/lib/cli/commands/serve.js @@ -2,7 +2,7 @@ import path from "node:path"; import os from "node:os"; import process from "node:process"; import baseMiddleware from "../middlewares/base.js"; -import {applyProjectConfigOptions, applyWorkspaceOptions, dedupeArray} from "../options.js"; +import {applyProjectConfigOptions, applyWorkspaceOptions, applyBuildOptions, dedupeArray} from "../options.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("cli:commands:serve"); @@ -16,6 +16,7 @@ const serve = { serve.builder = function(cli) { applyProjectConfigOptions(cli); applyWorkspaceOptions(cli); + applyBuildOptions(cli); return cli .option("port", { describe: "Port to bind on (default for HTTP: 8080, HTTP/2: 8443)", @@ -207,6 +208,8 @@ serve.handler = async function(argv) { sendSAPTargetCSP: !!argv.sapCspPolicies, serveCSPReports: !!argv.serveCspReports, cache: argv.cache, + includedTasks: argv["include-task"], + excludedTasks: argv["exclude-task"], }; if (serverConfig.h2) { diff --git a/packages/cli/lib/cli/options.js b/packages/cli/lib/cli/options.js index 8c1412b4ca8..d48f3eb01f2 100644 --- a/packages/cli/lib/cli/options.js +++ b/packages/cli/lib/cli/options.js @@ -76,3 +76,26 @@ export function applyWorkspaceOptions(cli) { }) .coerce(["workspace-config", "workspace"], dedupeArray); } + +/** + * Adds the shared build-related options ("--include-task" and "--exclude-task") + * to the given yargs instance. Both the "ui5 build" and "ui5 serve" commands + * trigger a build internally and honour the same task filters. + * + * @param {object} cli The yargs instance + * @returns {object} The yargs instance + */ +export function applyBuildOptions(cli) { + return cli + .option("include-task", { + describe: "A list of tasks to be added to the default execution set. " + + "This option takes precedence over any excludes.", + type: "string", + array: true + }) + .option("exclude-task", { + describe: "A list of tasks to be excluded from the default task execution set", + type: "string", + array: true + }); +} diff --git a/packages/cli/test/lib/cli/commands/serve.js b/packages/cli/test/lib/cli/commands/serve.js index 7cd5f0fb383..ffab26787f0 100644 --- a/packages/cli/test/lib/cli/commands/serve.js +++ b/packages/cli/test/lib/cli/commands/serve.js @@ -123,6 +123,8 @@ test.serial("ui5 serve: default", async (t) => { serveCSPReports: false, simpleIndex: false, liveReload: true, + includedTasks: undefined, + excludedTasks: undefined, } ]); t.is(typeof server.serve.getCall(0).args[2], "function"); @@ -165,6 +167,8 @@ test.serial("ui5 serve --h2", async (t) => { serveCSPReports: false, simpleIndex: false, liveReload: true, + includedTasks: undefined, + excludedTasks: undefined, } ]); @@ -198,6 +202,8 @@ test.serial("ui5 serve --accept-remote-connections", async (t) => { serveCSPReports: false, simpleIndex: false, liveReload: true, + includedTasks: undefined, + excludedTasks: undefined, } ]); }); @@ -452,6 +458,21 @@ test.serial("ui5 serve --live-reload overrides ui5.yaml liveReload setting", asy t.is(server.serve.getCall(0).args[1].liveReload, true); }); +test.serial("ui5 serve --include-task / --exclude-task", async (t) => { + const {argv, serve, server} = t.context; + + argv["include-task"] = ["minify"]; + argv["exclude-task"] = ["buildThemes", "generateResourcesJson"]; + + serve.handler(argv); + await t.context.handlerReady; + + t.is(server.serve.callCount, 1); + t.deepEqual(server.serve.getCall(0).args[1].includedTasks, ["minify"]); + t.deepEqual(server.serve.getCall(0).args[1].excludedTasks, + ["buildThemes", "generateResourcesJson"]); +}); + test.serial("ui5 serve with ui5.yaml port setting", async (t) => { const {argv, serve, server, getServerSettings} = t.context; From b33eee87b1eaebf47b592fb3ee33f7425b0b117d Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Wed, 8 Jul 2026 10:50:29 +0200 Subject: [PATCH 3/4] test(server): Update expectations for full dev-server task set The dev server no longer skips 'minify', 'generateLibraryPreload', 'generateComponentPreload', or 'generateBundle', so two main.js assertions on application.a's built output need adjusting: - /versionTest.js now carries the //# sourceMappingURL trailer appended by 'minify'. - The root index of application.a lists 15 entries instead of 9: the extra six come from 'minify' (test-dbg.js, test.js.map, versionTest-dbg.js, versionTest.js.map) and 'generateComponentPreload' (Component-preload.js, Component-preload.js.map). --- packages/server/test/lib/server/main.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/server/test/lib/server/main.js b/packages/server/test/lib/server/main.js index 1044fef7016..8e2e0849f0c 100644 --- a/packages/server/test/lib/server/main.js +++ b/packages/server/test/lib/server/main.js @@ -7,6 +7,11 @@ import {isolatedUi5DataDir} from "../../utils/buildCacheIsolation.js"; let request; let server; +// Node.js itself tries to parse sourceMappingURLs in all JavaScript files. This is unwanted and might even lead to +// obscure errors when dynamically generating Data-URI soruceMappingURL values. +// Therefore use this constant to never write the actual string. +const SOURCE_MAPPING_URL = "//" + "# sourceMappingURL"; + // Start server before running tests test.before(async (t) => { const graph = await graphFromPackageDependencies({ @@ -66,7 +71,8 @@ test("Get resource from application.a with replaced version placeholder (/versio } t.is(res.statusCode, 200, "Correct HTTP status code"); t.regex(res.headers["content-type"], /application\/javascript/, "Correct content type"); - t.is(res.text, "console.log(`1.0.0`);\n", "Correct response"); + // The 'minify' task rewrites the served file and appends a sourceMappingURL + t.is(res.text, "console.log(`1.0.0`);\n" + SOURCE_MAPPING_URL + "=versionTest.js.map", "Correct response"); }); test("Get resource from application.a (/i18n/i18n.properties) with correct content-type", async (t) => { @@ -716,7 +722,10 @@ test("Get index of resources", async (t) => { t.is(res.statusCode, 200, "Correct HTTP status code"); t.is(res.headers["content-type"], "text/html; charset=utf-8", "Correct content type"); t.is(/(.*)<\/title>/i.exec(res.text)[1], "Index of /", "Found correct title"); - t.is(res.text.match(/<li/g).length, 9, "Found correct amount of <li> elements"); + // 1 header row + 3 directories (i18n, resources, test-resources) + 11 files: + // index.html, manifest.json, versionTest.html and 8 files produced by the build tasks + // (Component-preload.js{,.map}, test.js{,.map}, test-dbg.js, versionTest.js{,.map}, versionTest-dbg.js) + t.is(res.text.match(/<li/g).length, 15, "Found correct amount of <li> elements"); }), request.get("/resources").then((res) => { t.is(res.statusCode, 200, "Correct HTTP status code"); From f3105aad6371567270871c8044371bb0ca84dfa0 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger <m.beutlberger@sap.com> Date: Wed, 8 Jul 2026 11:16:01 +0200 Subject: [PATCH 4/4] docs(server): Standard Tasks now matches the builder. Document CLI options --- internal/documentation/docs/pages/Server.md | 6 +----- internal/documentation/docs/updates/migrate-v5.md | 15 ++++++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/internal/documentation/docs/pages/Server.md b/internal/documentation/docs/pages/Server.md index a6a8637493b..64d6ae46155 100644 --- a/internal/documentation/docs/pages/Server.md +++ b/internal/documentation/docs/pages/Server.md @@ -144,11 +144,7 @@ Answers all non-read requests (POST, PUT, DELETE, etc.) that have not been answe 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` +As with the UI5 Builder, a set of standard tasks is being executed during a server build. Individual tasks can be included or excluded using the respective CLI options `--include-task` and `--exclude-task`. ::: info See [Builder Standard Tasks](./Builder.md#standard-tasks) for more explanation about each task. diff --git a/internal/documentation/docs/updates/migrate-v5.md b/internal/documentation/docs/updates/migrate-v5.md index d30f12b9f4c..c9db7b58dac 100644 --- a/internal/documentation/docs/updates/migrate-v5.md +++ b/internal/documentation/docs/updates/migrate-v5.md @@ -17,14 +17,17 @@ Or update your global install via: `npm i --global @ui5/cli@next` - **@ui5/cli: Option `--cache-mode` has been renamed to `--snapshot-cache`** -- **@ui5/cli: Project/Workspace options are now scoped per command** +- **@ui5/cli: Project/Workspace options are now scoped per command, incorrect usage now produces an error** -- **@ui5/server: Live Reload is enabled by default for `ui5 serve`** - -- **@ui5/cli: `ui5 serve` renders a live status banner in interactive terminals** +- **@ui5/server: By default, the server now runs all configured build tasks and serves the build result instead of transforming resources dynamically** - **@ui5/server: Standard middleware `serveThemes` and `testRunner` have been removed** +- **@ui5/cli: `ui5 serve` enables Live Reload by default** + +- **@ui5/cli: `ui5 serve` renders a status banner in interactive terminals** + + ## Node.js and npm Version Support This release requires **Node.js version v22.20.0 and higher or v24.0.0 and higher (v23 is not supported)** as well as npm v8 or higher. @@ -70,7 +73,9 @@ If you plan to execute a build only once (for example during a CI run), consider ### 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)). +The UI5 Server now performs a build of the project. When started with `ui5 serve`, the same set of standard and custom tasks as `ui5 build` is executed. See [Server Standard Tasks](../pages/Server.md#standard-tasks) for more details. + +Individual tasks can be included or excluded via the `--include-task` and `--exclude-task` CLI options, identical to the `ui5 build` command. For example, `ui5 serve --exclude-task minify` would skip the minification build task. 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).