diff --git a/internal/documentation/docs/pages/Builder.md b/internal/documentation/docs/pages/Builder.md
index 69d1211bd17..5ac7c647c48 100644
--- a/internal/documentation/docs/pages/Builder.md
+++ b/internal/documentation/docs/pages/Builder.md
@@ -35,7 +35,7 @@ All available standard tasks are documented under **API -> @ui5/builder -> tasks
| [executeJsdocSdkTransformation](../api/module-@ui5_builder_tasks_jsdoc_executeJsdocSdkTransformation) | | | *disabled* 1 | |
| [minify](../api/module-@ui5_builder_tasks_minify) | enabled | enabled | enabled | |
| [generateFlexChangesBundle](../api/module-@ui5_builder_tasks_bundlers_generateFlexChangesBundle) | enabled | enabled | enabled | |
-| [generateLibraryManifest](../api/module-@ui5_builder_tasks_generateLibraryManifest) | | | enabled | |
+| [generateLibraryManifest](../api/module-@ui5_builder_tasks_generateLibraryManifest) | | | *disabled* 7 | |
| [enhanceManifest](../api/module-@ui5_builder_tasks_enhanceManifest) | enabled | enabled | enabled | |
| [generateComponentPreload](../api/module-@ui5_builder_tasks_bundlers_generateComponentPreload) | enabled | enabled | *disabled* 2 | |
| [generateLibraryPreload](../api/module-@ui5_builder_tasks_bundlers_generateLibraryPreload) | | | enabled | |
@@ -58,7 +58,8 @@ 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 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
diff --git a/internal/documentation/docs/pages/Configuration.md b/internal/documentation/docs/pages/Configuration.md
index 85e3884794f..f1d22177512 100644
--- a/internal/documentation/docs/pages/Configuration.md
+++ b/internal/documentation/docs/pages/Configuration.md
@@ -812,6 +812,10 @@ Version | UI5 CLI Release
### Specification Version 5.0
+**Breaking changes:**
+
+- The `generateLibraryManifest` build task is no longer executed for projects of type `library`. SAPUI5 distribution libraries (framework projects) are not affected. Libraries must provide a `manifest.json` directly in their source directory. See [Migrate to v5: generateLibraryManifest Task No Longer Executed](../updates/migrate-v5.md#generatelibrarymanifest-task-no-longer-executed) for details.
+
**Features:**
- Adds support for the new [`component`](./Project.md#component) project type for developing UI5 components — including application, reusable UI, and faceless components — which, unlike `application`-type projects, are served under their own namespace so multiple can coexist in one environment
diff --git a/internal/documentation/docs/updates/migrate-v5.md b/internal/documentation/docs/updates/migrate-v5.md
index b3fbe518ba3..ce7071a7a03 100644
--- a/internal/documentation/docs/updates/migrate-v5.md
+++ b/internal/documentation/docs/updates/migrate-v5.md
@@ -43,6 +43,23 @@ 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**.
+## generateLibraryManifest Task No Longer Executed
+
+::: info Specification Version 5.0 only
+This change only applies to library projects that upgrade their `specVersion` to `5.0` in `ui5.yaml`. Projects on **Specification Version 4.0 and lower are not affected**. **SAPUI5 distribution libraries (framework projects) are not affected**.
+:::
+
+With **Specification Version 5.0**, the [`generateLibraryManifest`](../api/module-@ui5_builder_tasks_generateLibraryManifest) build task is no longer executed for non-framework library projects. Libraries must provide a `manifest.json` directly in their source directory.
+
+**Action required** when upgrading a library project to Specification Version 5.0:
+
+- Ensure your library has a `manifest.json` in its source directory. If you would like to leverage the power of UI5 CLI, you could execute `ui5 build` using Specification Version `4.0` and copy the generated `manifest.json` file from the build result to the source directory of your library.
+- If no `manifest.json` is present, UI5 CLI commands such as `ui5 build`, `ui5 serve`, or `ui5 tree` will fail with an error.
+
+::: tip
+To see which standard tasks are executed for each project type, check out the [Standard Tasks](../pages/Builder#standard-tasks) table in the UI5 Builder page.
+:::
+
## 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.
diff --git a/packages/project/lib/build/definitions/library.js b/packages/project/lib/build/definitions/library.js
index a01df0e856f..2229d0b9815 100644
--- a/packages/project/lib/build/definitions/library.js
+++ b/packages/project/lib/build/definitions/library.js
@@ -95,7 +95,12 @@ export default function({project, taskUtil, getTask}) {
}
});
- tasks.set("generateLibraryManifest", {});
+ // For specVersion 5.0+, only execute for framework libraries
+ if (project.getSpecVersion().lt("5.0") || project.isFrameworkProject()) {
+ tasks.set("generateLibraryManifest", {});
+ } else {
+ tasks.set("generateLibraryManifest", {taskFunction: null});
+ }
tasks.set("enhanceManifest", {});
diff --git a/packages/project/lib/specifications/types/Library.js b/packages/project/lib/specifications/types/Library.js
index 7998a159349..43f12d7453a 100644
--- a/packages/project/lib/specifications/types/Library.js
+++ b/packages/project/lib/specifications/types/Library.js
@@ -194,6 +194,23 @@ class Library extends ComponentProject {
async _parseConfiguration(config, buildManifest) {
await super._parseConfiguration(config, buildManifest);
+ // For Specification Version 5.0+, non-framework libraries must provide a manifest.json
+ if (this.getSpecVersion().gte("5.0") && !this.isFrameworkProject()) {
+ try {
+ await this._getManifest();
+ } catch (err) {
+ throw new Error(
+ `Could not find required manifest.json for library project ${this.getName()}: ` +
+ `${err.message}\n\n` +
+ `Library projects using Specification Version 5.0 or higher must provide ` +
+ `a manifest.json directly in their source directory.\n` +
+ `For migration details, please refer to:\n` +
+ `https://ui5.github.io/cli/updates/migrate-v5/#generatelibrarymanifest-task-no-longer-executed`, {
+ cause: err
+ });
+ }
+ }
+
if (buildManifest) {
this._namespace = buildManifest.namespace;
return;
diff --git a/packages/project/test/lib/build/ProjectBuilder.integration.js b/packages/project/test/lib/build/ProjectBuilder.integration.js
index fd6cb4797fb..b4c2e5255d6 100644
--- a/packages/project/test/lib/build/ProjectBuilder.integration.js
+++ b/packages/project/test/lib/build/ProjectBuilder.integration.js
@@ -1624,6 +1624,11 @@ test.serial("Build library.d (Custom Library preload configuration)", async (t)
// This custom preload configuration generates a library-preload.js similar to a default one.
// However, it will omit a resource ("some.js") from the bundle.
+ // ui5-custom-preload-config.yaml uses specVersion 5.0, which requires a manifest.json
+ await fixtureTester._initialize();
+ await fs.writeFile(`${fixtureTester.fixturePath}/main/src/library/d/manifest.json`,
+ JSON.stringify({"sap.app": {"id": "library.d", "type": "library"}}, null, "\t"));
+
// #1 build (no cache, no changes)
await fixtureTester.buildProject({
graphConfig: {rootConfigPath: "ui5-custom-preload-config.yaml"},
@@ -3064,6 +3069,8 @@ sap.ui.define([
};
return thisLib;
});`);
+ await fs.writeFile(`${this.fixturePath}/node_modules/library.z/src/library/z/manifest.json`,
+ JSON.stringify({"sap.app": {"id": "library.z", "type": "library"}}, null, "\t"));
await fs.writeFile(`${this.fixturePath}/node_modules/library.z/src/library/z/.library`,
`
diff --git a/packages/project/test/lib/build/TaskRunner.js b/packages/project/test/lib/build/TaskRunner.js
index 2dd78996b34..c06859aa01a 100644
--- a/packages/project/test/lib/build/TaskRunner.js
+++ b/packages/project/test/lib/build/TaskRunner.js
@@ -27,7 +27,8 @@ function getMockProject(type) {
getMinificationExcludes: emptyarray,
getSpecVersion: () => {
return {
- gte: () => false
+ gte: () => false,
+ lt: () => true
};
},
getComponentPreloadPaths: () => [
diff --git a/packages/project/test/lib/build/definitions/library.js b/packages/project/test/lib/build/definitions/library.js
index 5f839d10b6e..22eaf7fb8bd 100644
--- a/packages/project/test/lib/build/definitions/library.js
+++ b/packages/project/test/lib/build/definitions/library.js
@@ -17,7 +17,8 @@ function getMockProject() {
getSpecVersion: () => {
return {
toString: () => "2.6",
- gte: () => true
+ gte: () => true,
+ lt: () => true
};
},
getMinificationExcludes: emptyarray,
@@ -187,7 +188,8 @@ test("Standard build with legacy spec version", (t) => {
project.getSpecVersion = () => {
return {
toString: () => "0.1",
- gte: () => false
+ gte: () => false,
+ lt: () => true
};
};
@@ -507,7 +509,8 @@ test("Minification excludes not applied for legacy specVersion", (t) => {
project.getSpecVersion = () => {
return {
toString: () => "2.5",
- gte: () => false
+ gte: () => false,
+ lt: () => true
};
};
project.getMinificationExcludes = () => ["**.html"];
@@ -639,6 +642,42 @@ test("buildThemes: Project is not root", (t) => {
}
}, "Correct buildThemes task definition");
});
+test("generateLibraryManifest: specVersion 5.0, non-framework project", (t) => {
+ const {project, taskUtil, getTask} = t.context;
+
+ project.getSpecVersion = () => {
+ return {
+ toString: () => "5.0",
+ gte: () => true,
+ lt: () => false
+ };
+ };
+ project.isFrameworkProject = () => false;
+
+ const tasks = library({project, taskUtil, getTask});
+
+ t.deepEqual(tasks.get("generateLibraryManifest"), {taskFunction: null},
+ "generateLibraryManifest is skipped for non-framework libraries on specVersion 5.0");
+});
+
+test("generateLibraryManifest: specVersion 5.0, framework project", (t) => {
+ const {project, taskUtil, getTask} = t.context;
+
+ project.getSpecVersion = () => {
+ return {
+ toString: () => "5.0",
+ gte: () => true,
+ lt: () => false
+ };
+ };
+ project.isFrameworkProject = () => true;
+
+ const tasks = library({project, taskUtil, getTask});
+
+ t.deepEqual(tasks.get("generateLibraryManifest"), {},
+ "generateLibraryManifest runs for framework libraries on specVersion 5.0");
+});
+
test("buildThemes: CSS Variables enabled", (t) => {
const {project, taskUtil, getTask} = t.context;
taskUtil.getBuildOption.returns(true);
diff --git a/packages/project/test/lib/specifications/types/Library.js b/packages/project/test/lib/specifications/types/Library.js
index da1589637d6..dbded0e0ef4 100644
--- a/packages/project/test/lib/specifications/types/Library.js
+++ b/packages/project/test/lib/specifications/types/Library.js
@@ -617,6 +617,49 @@ test.serial("_parseConfiguration: No preload exclude fallback for non-framework
t.is(getPreloadExcludesFromDotLibraryStub.callCount, 0, "_getPreloadExcludesFromDotLibrary has not been called");
});
+test.serial("_parseConfiguration: Missing manifest.json throws for specVersion 5.0 non-framework library",
+ async (t) => {
+ const {projectInput, sinon} = t.context;
+ projectInput.configuration.specVersion = "5.0";
+
+ sinon.stub(Library.prototype, "isFrameworkProject").returns(false);
+ sinon.stub(Library.prototype, "_getManifest").rejects(
+ new Error("Could not find manifest.json file for project library.d"));
+ sinon.stub(Library.prototype, "_getNamespace").resolves("library/d");
+
+ const error = await t.throwsAsync(new Library().init(projectInput));
+
+ t.true(error.message.includes("Could not find required manifest.json for library project library.d"),
+ "Error message mentions missing manifest.json");
+ t.true(error.message.includes("migrate-v5"),
+ "Error message references the migration guide");
+ });
+
+test.serial("_parseConfiguration: Missing manifest.json is allowed for specVersion 5.0 framework library",
+ async (t) => {
+ const {projectInput, sinon} = t.context;
+ projectInput.configuration.specVersion = "5.0";
+
+ sinon.stub(Library.prototype, "isFrameworkProject").returns(true);
+ sinon.stub(Library.prototype, "_getManifest").rejects(
+ new Error("Could not find manifest.json file for project library.d"));
+
+ await t.notThrowsAsync(new Library().init(projectInput),
+ "No error thrown for framework library without manifest.json");
+ });
+
+test.serial("_parseConfiguration: Missing manifest.json is allowed for specVersion 4.0 library", async (t) => {
+ const {projectInput, sinon} = t.context;
+ projectInput.configuration.specVersion = "4.0";
+
+ sinon.stub(Library.prototype, "isFrameworkProject").returns(false);
+ sinon.stub(Library.prototype, "_getManifest").rejects(
+ new Error("Could not find manifest.json file for project library.d"));
+
+ await t.notThrowsAsync(new Library().init(projectInput),
+ "No error thrown for specVersion 4.0 library without manifest.json");
+});
+
test("_getManifest: Reads correctly", async (t) => {
const {projectInput, sinon} = t.context;