Skip to content
Open
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
6 changes: 1 addition & 5 deletions internal/documentation/docs/pages/Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 10 additions & 5 deletions internal/documentation/docs/updates/migrate-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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).

Expand Down
14 changes: 2 additions & 12 deletions packages/cli/lib/cli/commands/build.js
Original file line number Diff line number Diff line change
@@ -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");

Expand All @@ -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,
Expand Down Expand Up @@ -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\"",
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/lib/cli/commands/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand All @@ -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)",
Expand Down Expand Up @@ -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) {
Expand Down
23 changes: 23 additions & 0 deletions packages/cli/lib/cli/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
}
21 changes: 21 additions & 0 deletions packages/cli/test/lib/cli/commands/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -165,6 +167,8 @@ test.serial("ui5 serve --h2", async (t) => {
serveCSPReports: false,
simpleIndex: false,
liveReload: true,
includedTasks: undefined,
excludedTasks: undefined,
}
]);

Expand Down Expand Up @@ -198,6 +202,8 @@ test.serial("ui5 serve --accept-remote-connections", async (t) => {
serveCSPReports: false,
simpleIndex: false,
liveReload: true,
includedTasks: undefined,
excludedTasks: undefined,
}
]);
});
Expand Down Expand Up @@ -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;

Expand Down
9 changes: 7 additions & 2 deletions packages/server/lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>UI5_DATA_DIR</code> environment variable,
* the UI5 configuration file, and the default of <code>~/.ui5</code>.
* @param {string[]} [options.includedTasks] A list of tasks to be added to the default execution set.
* Takes precedence over <code>excludedTasks</code>.
* @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<object>} Promise resolving once the server is listening.
* It resolves with an object containing the <code>port</code>,
Expand All @@ -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();

Expand Down Expand Up @@ -186,7 +190,8 @@ export async function serve(graph, {
}
const buildServer = await graph.serve({
initialBuildIncludedDependencies,
excludedTasks: ["minify", "generateLibraryPreload", "generateComponentPreload", "generateBundle"],
includedTasks,
excludedTasks,
cache,
ui5DataDir,
});
Expand Down
13 changes: 11 additions & 2 deletions packages/server/test/lib/server/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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>(.*)<\/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");
Expand Down
Loading