diff --git a/internal/documentation/docs/pages/Builder.md b/internal/documentation/docs/pages/Builder.md
index 5ac7c647c48..1f3a3e63efc 100644
--- a/internal/documentation/docs/pages/Builder.md
+++ b/internal/documentation/docs/pages/Builder.md
@@ -58,7 +58,7 @@ All available standard tasks are documented under **API -> @ui5/builder -> tasks
3 Enabled in `self-contained` build, which disables `generateComponentPreload` and `generateLibraryPreload`
4 Enabled for projects defining a [bundle configuration](./Configuration.md#custom-bundling)
5 Can be enabled for framework projects via the `includeTask` option. For other projects, this task is skipped
-6 Disabled for the server due to a corresponding middleware producing the same output
+6 Disabled for the server (`ui5 serve` and `ui5 build for-server`) due to a corresponding middleware producing the same output
7 Enabled for Specification Version 4.0 and lower, and for framework projects. For other projects using Specification Version 5.0 and higher, this task is skipped
### minify
@@ -227,6 +227,8 @@ The cache may grow over time. It can be deleted at any time to reclaim disk spac
::: 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).
+
+To pre-populate the cache that `ui5 serve` reuses, run `ui5 build for-server`. It executes the same task set as the server (for example, it skips `generateVersionInfo`, which the server generates on the fly) and only warms the cache without writing a build result to the destination directory. A subsequent `ui5 serve` then reuses those cached results.
:::
diff --git a/packages/cli/lib/cli/commands/build.js b/packages/cli/lib/cli/commands/build.js
index bd9c9d00c80..928325301f4 100644
--- a/packages/cli/lib/cli/commands/build.js
+++ b/packages/cli/lib/cli/commands/build.js
@@ -32,6 +32,14 @@ build.builder = function(cli) {
builder: noop,
middlewares: [baseMiddleware]
})
+ .command("for-server",
+ "Build the project into the shared build cache for reuse by 'ui5 serve'. " +
+ "Aligns the task set with the server (e.g. skips 'generateVersionInfo') and does not " +
+ "write the build result to the destination directory.", {
+ handler: handleBuild,
+ builder: noop,
+ middlewares: [baseMiddleware]
+ })
.option("include-all-dependencies", {
describe: "Include all dependencies in the build result. " +
"This is equivalent to '--include-dependency \"*\"'",
@@ -215,6 +223,8 @@ async function handleBuild(argv) {
},
selfContained: command === "self-contained",
jsdoc: command === "jsdoc",
+ server: command === "for-server",
+ cacheOnly: command === "for-server",
includedTasks: argv["include-task"],
excludedTasks: argv["exclude-task"],
outputStyle: argv["output-style"],
diff --git a/packages/cli/test/lib/cli/commands/build.js b/packages/cli/test/lib/cli/commands/build.js
index d439bde5cf7..1dca6308013 100644
--- a/packages/cli/test/lib/cli/commands/build.js
+++ b/packages/cli/test/lib/cli/commands/build.js
@@ -52,6 +52,8 @@ function getDefaultBuilderArgs() {
createBuildManifest: false,
selfContained: false,
jsdoc: false,
+ server: false,
+ cacheOnly: false,
includedTasks: undefined,
excludedTasks: undefined,
outputStyle: "Default"
@@ -120,6 +122,19 @@ test.serial("ui5 build jsdoc", async (t) => {
t.deepEqual(builder.getCall(0).args[0], expectedBuilderArgs, "JSDoc build called with expected arguments");
});
+test.serial("ui5 build for-server", async (t) => {
+ const {build, argv, builder, expectedBuilderArgs} = t.context;
+
+ argv._.push("for-server");
+
+ await build.handler(argv);
+
+ expectedBuilderArgs.server = true;
+ expectedBuilderArgs.cacheOnly = true;
+ t.deepEqual(builder.getCall(0).args[0], expectedBuilderArgs,
+ "for-server build called with expected arguments");
+});
+
test.serial("ui5 build --framework-version", async (t) => {
const {build, argv, graphFromPackageDependenciesStub} = t.context;
diff --git a/packages/project/lib/build/ProjectBuilder.js b/packages/project/lib/build/ProjectBuilder.js
index 4d28d9ad0e6..cdb780c1028 100644
--- a/packages/project/lib/build/ProjectBuilder.js
+++ b/packages/project/lib/build/ProjectBuilder.js
@@ -23,6 +23,11 @@ class ProjectBuilder {
* @typedef {object} @ui5/project/build/ProjectBuilder~BuildConfiguration
* @property {boolean} [selfContained=false] Flag to activate self contained build
* @property {boolean} [jsdoc=false] Flag to activate JSDoc build
+ * @property {boolean} [server=false]
+ * Flag to activate a server-aligned build. Disables tasks whose output the server generates
+ * on the fly (currently generateVersionInfo) by default, matching the task set
+ * used by @ui5/server. The disabled tasks can still be re-enabled via
+ * includedTasks.
* @property {boolean} [createBuildManifest=false]
* Whether to create a build manifest file for the root project.
* This is currently only supported for projects of type 'library' and 'theme-library'
@@ -195,6 +200,10 @@ class ProjectBuilder {
* @param {boolean} [parameters.includeRootProject=true] Whether to include the root project
* @param {Array.} [parameters.includedDependencies=[]] List of dependencies to include
* @param {Array.} [parameters.excludedDependencies=[]] List of dependencies to exclude
+ * @param {@ui5/project/build/ProjectBuilder~DependencyIncludes} [parameters.dependencyIncludes]
+ * Alternative to the includedDependencies and excludedDependencies parameters.
+ * Allows for a more sophisticated configuration for defining which dependencies should be built.
+ * If this is provided, the other mentioned parameters are ignored.
* @param {AbortSignal} [parameters.signal] Signal to abort the build
* @param {Function} [projectBuiltCallback] Callback invoked after each project is built
* @returns {Promise} Promise resolving with array of processed project names
@@ -202,10 +211,11 @@ class ProjectBuilder {
async build({
includeRootProject = true,
includedDependencies = [], excludedDependencies = [],
+ dependencyIncludes,
signal,
}, projectBuiltCallback) {
const requestedProjects = this._determineRequestedProjects(
- includeRootProject, includedDependencies, excludedDependencies);
+ includeRootProject, includedDependencies, excludedDependencies, dependencyIncludes);
return await this.#build(requestedProjects, projectBuiltCallback, signal);
}
diff --git a/packages/project/lib/build/helpers/BuildContext.js b/packages/project/lib/build/helpers/BuildContext.js
index 4d398e98a1c..3d25f555807 100644
--- a/packages/project/lib/build/helpers/BuildContext.js
+++ b/packages/project/lib/build/helpers/BuildContext.js
@@ -18,6 +18,7 @@ class BuildContext {
constructor(graph, taskRepository, { // buildConfig
selfContained = false,
jsdoc = false,
+ server = false,
createBuildManifest = false,
outputStyle = OutputStyleEnum.Default,
includedTasks = [], excludedTasks = [],
@@ -69,6 +70,7 @@ class BuildContext {
this._buildConfig = {
selfContained,
jsdoc,
+ server,
createBuildManifest,
outputStyle,
includedTasks,
diff --git a/packages/project/lib/build/helpers/composeTaskList.js b/packages/project/lib/build/helpers/composeTaskList.js
index dca89a180e3..34631577908 100644
--- a/packages/project/lib/build/helpers/composeTaskList.js
+++ b/packages/project/lib/build/helpers/composeTaskList.js
@@ -3,6 +3,8 @@
*
* Sets specific tasks to be disabled by default, these tasks need to be included explicitly.
* Based on the selected build mode (selfContained|preload), different tasks are enabled.
+ * When the server flag is set, tasks whose output the server generates on the fly
+ * (currently generateVersionInfo) are disabled by default.
* Tasks can be enabled or disabled. The wildcard * is also supported and affects all tasks.
*
* @private
@@ -11,7 +13,7 @@
* Build configuration
* @returns {Array} List of tasks to be executed
*/
-export default function composeTaskList(allTasks, {selfContained, jsdoc, includedTasks, excludedTasks}) {
+export default function composeTaskList(allTasks, {selfContained, jsdoc, server, includedTasks, excludedTasks}) {
let selectedTasks = allTasks.reduce((list, key) => {
list[key] = true;
return list;
@@ -59,6 +61,13 @@ export default function composeTaskList(allTasks, {selfContained, jsdoc, include
selectedTasks.generateFlexChangesBundle = false;
}
+ if (server) {
+ // The 'versionInfo' server middleware generates the version info on the fly, so a server
+ // build does not run generateVersionInfo. Keeping it out of the default set here lets
+ // 'ui5 serve' and 'ui5 build for-server' share one build-cache entry.
+ selectedTasks.generateVersionInfo = false;
+ }
+
// Exclude tasks
for (let i = 0; i < excludedTasks.length; i++) {
const taskName = excludedTasks[i];
diff --git a/packages/project/lib/graph/ProjectGraph.js b/packages/project/lib/graph/ProjectGraph.js
index 3a6cf7f5327..8ddc8e40e55 100644
--- a/packages/project/lib/graph/ProjectGraph.js
+++ b/packages/project/lib/graph/ProjectGraph.js
@@ -706,6 +706,14 @@ class ProjectGraph {
* part of the build result. If this is provided, the other mentioned parameters will be ignored.
* @param {boolean} [parameters.selfContained=false] Flag to activate self contained build
* @param {boolean} [parameters.jsdoc=false] Flag to activate JSDoc build
+ * @param {boolean} [parameters.server=false]
+ * Flag to activate a server-aligned build. Disables tasks whose output the server generates
+ * on the fly (currently generateVersionInfo) by default, so the build result
+ * matches what @ui5/server produces.
+ * @param {boolean} [parameters.cacheOnly=false]
+ * Only populate the build cache without writing the build result to destPath.
+ * Intended to warm the shared build cache that a subsequent ui5 serve reuses.
+ * When set, destPath and cleanDest are ignored.
* @param {boolean} [parameters.createBuildManifest=false]
* Whether to create a build manifest file for the root project.
* This is currently only supported for projects of type 'library' and 'theme-library'
@@ -725,7 +733,8 @@ class ProjectGraph {
destPath, cleanDest = false,
includedDependencies = [], excludedDependencies = [],
dependencyIncludes,
- selfContained = false, jsdoc = false, createBuildManifest = false,
+ selfContained = false, jsdoc = false, server = false, createBuildManifest = false,
+ cacheOnly = false,
includedTasks = [], excludedTasks = [],
outputStyle = OutputStyleEnum.Default,
cache = Cache.Default,
@@ -745,13 +754,28 @@ class ProjectGraph {
graph: this,
taskRepository: await this._getTaskRepository(),
buildConfig: {
- selfContained, jsdoc,
+ selfContained, jsdoc, server,
createBuildManifest,
includedTasks, excludedTasks, outputStyle,
cache
},
ui5DataDir,
});
+ if (cacheOnly) {
+ // Build to populate the cache only, without writing the result to a target directory.
+ // buildToTarget closes the CacheManager itself; the reader-based build() does not, so
+ // close it explicitly once the build has finished.
+ try {
+ await builder.build({
+ includeRootProject: true,
+ includedDependencies, excludedDependencies,
+ dependencyIncludes,
+ });
+ } finally {
+ builder.closeCacheManager();
+ }
+ return;
+ }
return await builder.buildToTarget({
destPath, cleanDest,
includedDependencies, excludedDependencies,
@@ -803,6 +827,9 @@ class ProjectGraph {
taskRepository: await this._getTaskRepository(),
buildConfig: {
selfContained, jsdoc,
+ // A serve is always a server-aligned build: disable tasks the server generates
+ // on the fly (e.g. generateVersionInfo). See composeTaskList.
+ server: true,
createBuildManifest,
includedTasks, excludedTasks,
outputStyle: OutputStyleEnum.Default,
diff --git a/packages/project/test/lib/build/BuildServer.integration.js b/packages/project/test/lib/build/BuildServer.integration.js
index 61832f020e8..318afbe9623 100644
--- a/packages/project/test/lib/build/BuildServer.integration.js
+++ b/packages/project/test/lib/build/BuildServer.integration.js
@@ -218,10 +218,6 @@ test.serial("Serve application.a, request application resource", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -251,8 +247,7 @@ test.serial("Serve application.a, request application resource", async (t) => {
// Note: replaceCopyright is skipped because no copyright is configured in the project
"replaceCopyright",
"enhanceManifest",
- "generateFlexChangesBundle",
- "generateVersionInfo"
+ "generateFlexChangesBundle"
]
}
}
@@ -319,10 +314,6 @@ test.serial("Serve application.a, create and delete a source file", async (t) =>
resource: "/created.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -354,8 +345,7 @@ test.serial("Serve application.a, create and delete a source file", async (t) =>
"escapeNonAsciiCharacters",
"replaceCopyright",
"enhanceManifest",
- "generateFlexChangesBundle",
- "generateVersionInfo"
+ "generateFlexChangesBundle"
]
}
}
@@ -377,13 +367,19 @@ test.serial("Serve application.a, create and delete a source file", async (t) =>
}
});
- // #5 the second file is no longer served, thus requesting it shouldn't trigger a rebuild
- // (all projects are still cached from the previous builds)
+ // #5 the second file is no longer served. Resolving the not-found lookup searches the
+ // dependencies, which builds the libraries for the first time (the server build no longer
+ // pre-builds them via generateVersionInfo).
await fixtureTester.requestResource({
resource: "/another.js",
notFound: true,
assertions: {
- projects: {}
+ projects: {
+ "library.d": {},
+ "library.a": {},
+ "library.b": {},
+ "library.c": {}
+ }
}
});
@@ -403,8 +399,7 @@ test.serial("Serve application.a, create and delete a source file", async (t) =>
"escapeNonAsciiCharacters",
"replaceCopyright",
"enhanceManifest",
- "generateFlexChangesBundle",
- "generateVersionInfo"
+ "generateFlexChangesBundle"
]
}
}
@@ -583,10 +578,9 @@ test.serial("Serve application.a, request application resource AND library resou
resources: ["/test.js", "/resources/library/a/.library"],
assertions: {
projects: {
- "library.d": {},
+ // Only the requested projects build. Libraries are no longer pulled in by
+ // generateVersionInfo, which the server build disables by default.
"library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -658,10 +652,6 @@ test.serial("Serve application.a with --cache=Default", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -690,8 +680,7 @@ test.serial("Serve application.a with --cache=Default", async (t) => {
"escapeNonAsciiCharacters",
"replaceCopyright",
"enhanceManifest",
- "generateFlexChangesBundle",
- "generateVersionInfo"
+ "generateFlexChangesBundle"
]
}
}
@@ -714,10 +703,6 @@ test.serial("Serve application.a with --cache=Off", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -741,10 +726,6 @@ test.serial("Serve application.a with --cache=Off", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -765,10 +746,6 @@ test.serial("Serve application.a with --cache=Off", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -791,10 +768,6 @@ test.serial("Serve application.a with --cache=Off", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -810,10 +783,6 @@ test.serial("Serve application.a with --cache=ReadOnly", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -846,8 +815,7 @@ test.serial("Serve application.a with --cache=ReadOnly", async (t) => {
"escapeNonAsciiCharacters",
"replaceCopyright",
"enhanceManifest",
- "generateFlexChangesBundle",
- "generateVersionInfo"
+ "generateFlexChangesBundle"
]
}
}
@@ -876,8 +844,7 @@ test.serial("Serve application.a with --cache=ReadOnly", async (t) => {
"escapeNonAsciiCharacters",
"replaceCopyright",
"enhanceManifest",
- "generateFlexChangesBundle",
- "generateVersionInfo"
+ "generateFlexChangesBundle"
]
}
}
@@ -894,10 +861,6 @@ test.serial("Serve application.a with --cache=Force (1)", async (t) => {
resource: "/test.js",
assertions: {
projects: {
- "library.d": {},
- "library.a": {},
- "library.b": {},
- "library.c": {},
"application.a": {}
}
}
@@ -1238,17 +1201,15 @@ test.serial("Source change during second build retries cleanly without no_cache
});
test.serial("Serve application.a (test exclusion of generateVersionInfo)", async (t) => {
- // This test verifies that the "generateVersionInfo" task
- // can be excluded from the server build via the "excludedTasks" config option.
+ // The server build (graph.serve, server:true) disables the "generateVersionInfo" task by
+ // default, because the "versionInfo" middleware generates the version info on the fly. This
+ // test verifies the default exclusion and that "includedTasks" can re-enable the task.
const fixtureTester = t.context.fixtureTester = await FixtureTester.create(t, "application.a");
- // #1 Exclude "generateVersionInfo":
- await fixtureTester.serveProject({
- config: {
- excludedTasks: ["generateVersionInfo"],
- }
- });
+ // #1 Default server build: "generateVersionInfo" is excluded by default. It does not pull in
+ // the libraries, so only application.a builds to serve the request.
+ await fixtureTester.serveProject();
// Request a resource to trigger the build:
await fixtureTester.requestResource({
@@ -1274,10 +1235,11 @@ test.serial("Serve application.a (test exclusion of generateVersionInfo)", async
await fixtureTester.teardown();
- // #2 Don't exclude tasks (includes "generateVersionInfo"):
+ // #2 Re-enable "generateVersionInfo" via includedTasks. It collects the version info of all
+ // libraries, so those get built as well.
await fixtureTester.serveProject({
config: {
- excludedTasks: [],
+ includedTasks: ["generateVersionInfo"],
}
});
diff --git a/packages/project/test/lib/build/ProjectBuilder.js b/packages/project/test/lib/build/ProjectBuilder.js
index 25d3d4fe614..ee9bd50f668 100644
--- a/packages/project/test/lib/build/ProjectBuilder.js
+++ b/packages/project/test/lib/build/ProjectBuilder.js
@@ -164,6 +164,30 @@ test("build", async (t) => {
t.is(executeCleanupTasksStub.callCount, 1, "_executeCleanupTasksStub got called once");
});
+test("build: forwards dependencyIncludes to _determineRequestedProjects", async (t) => {
+ const {graph, taskRepository, ProjectBuilder, sinon} = t.context;
+
+ const builder = new ProjectBuilder({graph, taskRepository});
+
+ const determineRequestedProjectsStub = sinon.stub(builder, "_determineRequestedProjects").returns([]);
+ // Short-circuit the actual build; we only assert the requested-projects resolution
+ sinon.stub(builder._buildContext, "getRequiredProjectContexts").resolves(new Map());
+ sinon.stub(builder, "_registerCleanupSigHooks").returns("cleanup sig hooks");
+ sinon.stub(builder, "_deregisterCleanupSigHooks");
+ sinon.stub(builder, "_executeCleanupTasks").resolves();
+
+ await builder.build({
+ includedDependencies: ["dep a"],
+ excludedDependencies: ["dep b"],
+ dependencyIncludes: "dependencyIncludes"
+ });
+
+ t.is(determineRequestedProjectsStub.callCount, 1, "_determineRequestedProjects got called once");
+ t.deepEqual(determineRequestedProjectsStub.getCall(0).args, [
+ true, ["dep a"], ["dep b"], "dependencyIncludes"
+ ], "_determineRequestedProjects got called with dependencyIncludes forwarded");
+});
+
test("build: Conflicting dependency parameters", async (t) => {
const {graph, taskRepository, ProjectBuilder} = t.context;
@@ -645,6 +669,7 @@ test.serial("_writeResults: Create build manifest", async (t) => {
excludedTasks: [],
includedTasks: [],
jsdoc: false,
+ server: false,
selfContained: false,
cache: "Default",
}, "createBuildManifest got called with correct build configuration");
diff --git a/packages/project/test/lib/build/helpers/BuildContext.js b/packages/project/test/lib/build/helpers/BuildContext.js
index 1e67e125c87..a2b8f3d9bd2 100644
--- a/packages/project/test/lib/build/helpers/BuildContext.js
+++ b/packages/project/test/lib/build/helpers/BuildContext.js
@@ -83,6 +83,7 @@ test("getBuildConfig: Default values", (t) => {
selfContained: false,
outputStyle: OutputStyleEnum.Default,
jsdoc: false,
+ server: false,
createBuildManifest: false,
includedTasks: [],
excludedTasks: [],
@@ -103,6 +104,7 @@ test("getBuildConfig: Custom values", (t) => {
selfContained: true,
outputStyle: OutputStyleEnum.Namespace,
jsdoc: true,
+ server: true,
createBuildManifest: false,
includedTasks: ["included tasks"],
excludedTasks: ["excluded tasks"],
@@ -113,6 +115,7 @@ test("getBuildConfig: Custom values", (t) => {
selfContained: true,
outputStyle: OutputStyleEnum.Namespace,
jsdoc: true,
+ server: true,
createBuildManifest: false,
includedTasks: ["included tasks"],
excludedTasks: ["excluded tasks"],
diff --git a/packages/project/test/lib/build/helpers/composeTaskList.js b/packages/project/test/lib/build/helpers/composeTaskList.js
index f1fb5f905c4..f82d71555a4 100644
--- a/packages/project/test/lib/build/helpers/composeTaskList.js
+++ b/packages/project/test/lib/build/helpers/composeTaskList.js
@@ -123,6 +123,51 @@ const allTasks = [
"generateBundle",
]
],
+ [
+ "composeTaskList: server=true excludes generateVersionInfo by default", {
+ archive: false,
+ selfContained: false,
+ jsdoc: false,
+ server: true,
+ includedTasks: [],
+ excludedTasks: []
+ }, [
+ "replaceCopyright",
+ "replaceVersion",
+ "replaceBuildtime",
+ "escapeNonAsciiCharacters",
+ "minify",
+ "buildThemes",
+ "generateLibraryManifest",
+ "generateFlexChangesBundle",
+ "generateComponentPreload",
+ "generateBundle",
+ "generateLibraryPreload",
+ ]
+ ],
+ [
+ "composeTaskList: server=true with includedTasks re-enables generateVersionInfo", {
+ archive: false,
+ selfContained: false,
+ jsdoc: false,
+ server: true,
+ includedTasks: ["generateVersionInfo"],
+ excludedTasks: []
+ }, [
+ "replaceCopyright",
+ "replaceVersion",
+ "replaceBuildtime",
+ "escapeNonAsciiCharacters",
+ "minify",
+ "buildThemes",
+ "generateLibraryManifest",
+ "generateVersionInfo",
+ "generateFlexChangesBundle",
+ "generateComponentPreload",
+ "generateBundle",
+ "generateLibraryPreload",
+ ]
+ ],
[
"composeTaskList: includedTasks / excludedTasks", {
archive: false,
diff --git a/packages/server/lib/serve/stack.js b/packages/server/lib/serve/stack.js
index 40c3ac09bd7..20bd2b1dfb3 100644
--- a/packages/server/lib/serve/stack.js
+++ b/packages/server/lib/serve/stack.js
@@ -34,9 +34,8 @@ const log = getLogger("server");
export async function buildRouter(graph, config, error, getDegradedError) {
const {
sendSAPTargetCSP = false, simpleIndex = false, liveReload = false, serveCSPReports = false,
- cache, ui5DataDir, includedTasks, webSocketToken = null,
+ cache, ui5DataDir, includedTasks, excludedTasks, webSocketToken = null,
} = config;
- let {excludedTasks} = config;
const rootProject = graph.getRoot();
const readers = [];
@@ -72,15 +71,10 @@ export async function buildRouter(graph, config, error, getDegradedError) {
initialBuildIncludedDependencies.push("sap.ui.core");
}
- // Explicitly exclude task "generateVersionInfo" for Server builds
- // because middleware "versionInfo" will generate the version info anyways.
- if (!Array.isArray(excludedTasks)) {
- excludedTasks = [];
- }
- if (!excludedTasks.includes("generateVersionInfo")) {
- excludedTasks = [...excludedTasks, "generateVersionInfo"];
- }
-
+ // graph.serve() runs a server-aligned build (server:true), which disables the
+ // "generateVersionInfo" task by default because the "versionInfo" middleware generates the
+ // version info on the fly. The default task set is owned by @ui5/project (composeTaskList),
+ // so no task filtering is applied here.
const buildServer = await graph.serve({
initialBuildIncludedDependencies,
includedTasks,
diff --git a/packages/server/test/lib/server/serve/stack.js b/packages/server/test/lib/server/serve/stack.js
index 480b030a064..f6e7925b74c 100644
--- a/packages/server/test/lib/server/serve/stack.js
+++ b/packages/server/test/lib/server/serve/stack.js
@@ -109,23 +109,10 @@ test("buildRouter() getDegradedError is undefined for the embedding path (no sup
"no degraded accessor is threaded when none was supplied");
});
-test("buildRouter() adds generateVersionInfo to excludedTasks when undefined", async (t) => {
- // The versionInfo middleware generates the version info, so the build must skip
- // the generateVersionInfo task. Verify it lands in the excludedTasks passed to
- // graph.serve() even when the caller excludes nothing.
- const buildServer = createBuildServer();
- const graph = createGraph(buildServer);
- const applyMiddleware = sinon.stub().resolves();
-
- const {buildRouter} = await importBuildRouter(applyMiddleware);
- await buildRouter(graph, {excludedTasks: undefined});
-
- t.true(graph.serve.calledOnce);
- const callArgs = graph.serve.firstCall.args[0];
- t.deepEqual(callArgs.excludedTasks, ["generateVersionInfo"]);
-});
-
-test("buildRouter() appends generateVersionInfo to existing excludedTasks", async (t) => {
+test("buildRouter() passes the caller's excludedTasks through unchanged", async (t) => {
+ // The versionInfo middleware generates the version info, so the build must skip the
+ // generateVersionInfo task. That default is now owned by graph.serve() (server:true) in
+ // @ui5/project, so stack.js no longer edits excludedTasks: verify it forwards them as-is.
const buildServer = createBuildServer();
const graph = createGraph(buildServer);
const applyMiddleware = sinon.stub().resolves();
@@ -136,23 +123,22 @@ test("buildRouter() appends generateVersionInfo to existing excludedTasks", asyn
t.true(graph.serve.calledOnce);
const callArgs = graph.serve.firstCall.args[0];
- t.deepEqual(callArgs.excludedTasks, ["anotherTask", "anotherTask2", "generateVersionInfo"]);
+ t.is(callArgs.excludedTasks, originalExcludedTasks,
+ "the caller's excludedTasks are forwarded unchanged, without appending generateVersionInfo");
t.deepEqual(originalExcludedTasks, ["anotherTask", "anotherTask2"],
"the caller's excludedTasks array is not mutated");
});
-test("buildRouter() keeps generateVersionInfo when already excluded", async (t) => {
+test("buildRouter() forwards an undefined excludedTasks without adding generateVersionInfo", async (t) => {
const buildServer = createBuildServer();
const graph = createGraph(buildServer);
const applyMiddleware = sinon.stub().resolves();
const {buildRouter} = await importBuildRouter(applyMiddleware);
- const originalExcludedTasks = ["anotherTask", "generateVersionInfo", "anotherTask2"];
- await buildRouter(graph, {excludedTasks: originalExcludedTasks});
+ await buildRouter(graph, {excludedTasks: undefined});
t.true(graph.serve.calledOnce);
const callArgs = graph.serve.firstCall.args[0];
- t.deepEqual(callArgs.excludedTasks, ["anotherTask", "generateVersionInfo", "anotherTask2"]);
- t.deepEqual(originalExcludedTasks, ["anotherTask", "generateVersionInfo", "anotherTask2"],
- "the caller's excludedTasks array is not mutated");
+ t.is(callArgs.excludedTasks, undefined,
+ "stack.js does not synthesize a generateVersionInfo exclusion");
});