From 12e901151c512ade379d1e25a0dc4ac5b5de900b Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Thu, 9 Jul 2026 11:52:42 +0200 Subject: [PATCH 1/2] Offer CLI option to exclude/include tasks in UI5 server (#1447) - **refactor(project): Own the dev-server default task exclusions** - **refactor(server): Forward includedTasks/excludedTasks to graph.serve()** - **refactor(cli): Share --include-task / --exclude-task with 'ui5 serve'** JIRA: CPOUI5FOUNDATION-1276 --- internal/documentation/docs/pages/Server.md | 6 +---- .../documentation/docs/updates/migrate-v5.md | 15 ++++++++---- 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 +++++++++++++++++ packages/server/lib/server.js | 9 ++++++-- packages/server/test/lib/server/main.js | 13 +++++++++-- 8 files changed, 79 insertions(+), 27 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). 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; 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, }); 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 39c3bbbc370ea3b93bd401148418d2b55e115554 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 02:52:22 +0000 Subject: [PATCH 2/2] ci(github-actions): Bump actions/stale from 10 to 10.3.0 Bumps [actions/stale](https://github.com/actions/stale) from 10 to 10.3.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v10...v10.3.0) --- updated-dependencies: - dependency-name: actions/stale dependency-version: 10.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml index 55fbe08e1ab..6239e173cd4 100644 --- a/.github/workflows/issues.yml +++ b/.github/workflows/issues.yml @@ -11,7 +11,7 @@ jobs: name: Flag and close stale issues runs-on: ubuntu-latest steps: - - uses: actions/stale@v10 + - uses: actions/stale@v10.3.0 with: stale-issue-message: 'This issue has been automatically marked as stale because it has been open for 60 days with no activity. It will be closed in 10 days if no further activity occurs.' stale-issue-label: 'stale'