Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion lib/lbt/bundle/Resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class BundleResolver {
* in the resource pool.
*/
const missingModules = Object.create(null);
const ignoreMissingModules = pool.getIgnoreMissingModules();
/**
* Names of modules that are included in non-decomposable bundles.
* If they occur in the missingModules, then this is not an error.
Expand Down Expand Up @@ -123,7 +124,7 @@ class BundleResolver {
done = pool.findResourceWithInfo(resourceName)
.catch( (err) => {
// if the caller provided an error message, log it
if ( msg ) {
if ( msg && !ignoreMissingModules ) {
missingModules[resourceName] ??= [];
missingModules[resourceName].push(msg);
}
Expand Down
197 changes: 161 additions & 36 deletions lib/tasks/bundlers/generateLibraryPreload.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import semver from "semver";
import {getLogger} from "@ui5/logger";
const log = getLogger("builder:tasks:bundlers:generateLibraryPreload");
import moduleBundler from "../../processors/bundlers/moduleBundler.js";
Expand Down Expand Up @@ -106,6 +107,73 @@ function getBundleDefinition(namespace, excludes) {
};
}

function getBundleInfoPreloadDefinition(namespace, excludes, coreVersion) {
const sections = [{
mode: "preload",
filters: [
`${namespace}/library.js`,
],
resolve: true
},
{
mode: "bundleInfo",
name: `${namespace}/library-content.js`,
filters: getDefaultLibraryPreloadFilters(namespace, excludes),
resolve: false,
resolveConditional: false,
renderer: true
}];

if (coreVersion) {
const parsedVersion = semver.parse(coreVersion);
let targetUi5CoreVersionMajor = parsedVersion.major;

// legacy-free versions include changes of the upcoming major version
// so we should treat them the same as the next major version
if (
parsedVersion.prerelease.includes("legacy-free") ||
parsedVersion.prerelease.includes("legacy-free-SNAPSHOT") // Maven snapshot version
) {
targetUi5CoreVersionMajor += 1;
}
if (parsedVersion) {
if (targetUi5CoreVersionMajor >= 2) {
// Do not include manifest.json in UI5 2.x and higher to allow for loading it upfront for all libraries
sections.unshift({
mode: "provided",
filters: [
`${namespace}/manifest.json`,
]
});
}
}
}

return {
name: `${namespace}/library-preload.js`,
sections,
};
}

function getContentBundleDefinition(namespace, excludes) {
return {
name: `${namespace}/library-content.js`,
sections: [{
mode: "provided",
filters: [
`${namespace}/library.js`,
],
resolve: true
}, {
mode: "preload",
filters: getDefaultLibraryPreloadFilters(namespace, excludes),
resolve: false,
resolveConditional: false,
renderer: true
}]
};
}

function getDesigntimeBundleDefinition(namespace) {
return {
name: `${namespace}/designtime/library-preload.designtime.js`,
Expand Down Expand Up @@ -258,6 +326,7 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
}
const coreVersion = taskUtil?.getProject("sap.ui.core")?.getVersion();
const allowStringBundling = taskUtil?.getProject().getSpecVersion().lt("4.0");
const createBundleInfoPreload = !!process.env.UI5_CLI_EXPERIMENTAL_BUNDLE_INFO_PRELOAD;
const execModuleBundlerIfNeeded = ({options, resources}) => {
if (skipBundles.includes(options.bundleDefinition.name)) {
log.verbose(`Skipping generation of bundle ${options.bundleDefinition.name}`);
Expand Down Expand Up @@ -390,42 +459,98 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
const libraryNamespaceMatch = libraryIndicatorPath.match(libraryNamespacePattern);
if (libraryNamespaceMatch && libraryNamespaceMatch[1]) {
const libraryNamespace = libraryNamespaceMatch[1];
const results = await Promise.all([
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getBundleDefinition(libraryNamespace, excludes),
bundleOptions: {
optimize: true,
ignoreMissingModules: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
bundleOptions: {
optimize: true,
ignoreMissingModules: true,
skipIfEmpty: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
bundleOptions: {
optimize: false,
ignoreMissingModules: true,
skipIfEmpty: true
}
// Note: Although the bundle uses optimize=false, there is
// no moduleNameMapping needed, as support files are excluded from minification.
},
resources
})
]);
let results;
if (!createBundleInfoPreload) {
// Regular bundling
results = await Promise.all([
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getBundleDefinition(libraryNamespace, excludes),
bundleOptions: {
optimize: true,
ignoreMissingModules: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
bundleOptions: {
optimize: true,
ignoreMissingModules: true,
skipIfEmpty: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
bundleOptions: {
optimize: false,
ignoreMissingModules: true,
skipIfEmpty: true
}
// Note: Although the bundle uses optimize=false, there is
// no moduleNameMapping needed, as support files are excluded from minification.
},
resources
})
]);
} else {
log.info(
`Using experimental bundling with bundle info preload ` +
`for library ${libraryNamespace} in project ${projectName}.`);
// Experimental bundling with bundle info preload
results = await Promise.all([
execModuleBundlerIfNeeded({
options: {
bundleDefinition:
getBundleInfoPreloadDefinition(libraryNamespace, excludes, coreVersion),
bundleOptions: {
optimize: true,
ignoreMissingModules: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getContentBundleDefinition(libraryNamespace, excludes),
bundleOptions: {
optimize: true,
ignoreMissingModules: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
bundleOptions: {
optimize: true,
ignoreMissingModules: true,
skipIfEmpty: true
}
},
resources
}),
execModuleBundlerIfNeeded({
options: {
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
bundleOptions: {
optimize: false,
ignoreMissingModules: true,
skipIfEmpty: true
}
// Note: Although the bundle uses optimize=false, there is
// no moduleNameMapping needed, as support files are excluded from minification.
},
resources
})
]);
}
const bundles = Array.prototype.concat.apply([], results).filter(Boolean);
return Promise.all(bundles.map(({bundle, sourceMap} = {}) => {
if (bundle) {
Expand Down
9 changes: 6 additions & 3 deletions test/lib/lbt/bundle/AutoSplitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ function createMockPool(dependencies) {
name: "x.view.xml"
}, {
name: "c.properties"
}]
}],
getIgnoreMissingModules: () => false,
};
}

Expand Down Expand Up @@ -165,7 +166,8 @@ test("integration: Extreme AutoSplitter with numberOfParts 50", async (t) => {
});
return {info};
},
resources: modules.map((res) => ({name: res}))
resources: modules.map((res) => ({name: res})),
getIgnoreMissingModules: () => false,
};
const autoSplitter = new AutoSplitter(pool, new BundleResolver(pool));
const bundleDefinition = {
Expand Down Expand Up @@ -208,7 +210,8 @@ test("integration: AutoSplitter with bundleInfo", async (t) => {
const info = new ModuleInfo(name);
return {info};
},
resources: modules.map((res) => ({name: res}))
resources: modules.map((res) => ({name: res})),
getIgnoreMissingModules: () => false,
};
const autoSplitter = new AutoSplitter(pool, new BundleResolver(pool));
const bundleDefinition = {
Expand Down