Skip to content

Commit 476e3bb

Browse files
committed
[INTERNAL] generateLibraryPreload: Add experimental bundle-info preload
1 parent 68908e0 commit 476e3bb

File tree

3 files changed

+169
-40
lines changed

3 files changed

+169
-40
lines changed

lib/lbt/bundle/Resolver.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class BundleResolver {
5656
* in the resource pool.
5757
*/
5858
const missingModules = Object.create(null);
59+
const ignoreMissingModules = pool.getIgnoreMissingModules();
5960
/**
6061
* Names of modules that are included in non-decomposable bundles.
6162
* If they occur in the missingModules, then this is not an error.
@@ -123,7 +124,7 @@ class BundleResolver {
123124
done = pool.findResourceWithInfo(resourceName)
124125
.catch( (err) => {
125126
// if the caller provided an error message, log it
126-
if ( msg ) {
127+
if ( msg && !ignoreMissingModules ) {
127128
missingModules[resourceName] ??= [];
128129
missingModules[resourceName].push(msg);
129130
}

lib/tasks/bundlers/generateLibraryPreload.js

Lines changed: 161 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import semver from "semver";
12
import {getLogger} from "@ui5/logger";
23
const log = getLogger("builder:tasks:bundlers:generateLibraryPreload");
34
import moduleBundler from "../../processors/bundlers/moduleBundler.js";
@@ -106,6 +107,73 @@ function getBundleDefinition(namespace, excludes) {
106107
};
107108
}
108109

110+
function getBundleInfoPreloadDefinition(namespace, excludes, coreVersion) {
111+
const sections = [{
112+
mode: "preload",
113+
filters: [
114+
`${namespace}/library.js`,
115+
],
116+
resolve: true
117+
},
118+
{
119+
mode: "bundleInfo",
120+
name: `${namespace}/library-content.js`,
121+
filters: getDefaultLibraryPreloadFilters(namespace, excludes),
122+
resolve: false,
123+
resolveConditional: false,
124+
renderer: true
125+
}];
126+
127+
if (coreVersion) {
128+
const parsedVersion = semver.parse(coreVersion);
129+
let targetUi5CoreVersionMajor = parsedVersion.major;
130+
131+
// legacy-free versions include changes of the upcoming major version
132+
// so we should treat them the same as the next major version
133+
if (
134+
parsedVersion.prerelease.includes("legacy-free") ||
135+
parsedVersion.prerelease.includes("legacy-free-SNAPSHOT") // Maven snapshot version
136+
) {
137+
targetUi5CoreVersionMajor += 1;
138+
}
139+
if (parsedVersion) {
140+
if (targetUi5CoreVersionMajor >= 2) {
141+
// Do not include manifest.json in UI5 2.x and higher to allow for loading it upfront for all libraries
142+
sections.unshift({
143+
mode: "provided",
144+
filters: [
145+
`${namespace}/manifest.json`,
146+
]
147+
});
148+
}
149+
}
150+
}
151+
152+
return {
153+
name: `${namespace}/library-preload.js`,
154+
sections,
155+
};
156+
}
157+
158+
function getContentBundleDefinition(namespace, excludes) {
159+
return {
160+
name: `${namespace}/library-content.js`,
161+
sections: [{
162+
mode: "provided",
163+
filters: [
164+
`${namespace}/library.js`,
165+
],
166+
resolve: true
167+
}, {
168+
mode: "preload",
169+
filters: getDefaultLibraryPreloadFilters(namespace, excludes),
170+
resolve: false,
171+
resolveConditional: false,
172+
renderer: true
173+
}]
174+
};
175+
}
176+
109177
function getDesigntimeBundleDefinition(namespace) {
110178
return {
111179
name: `${namespace}/designtime/library-preload.designtime.js`,
@@ -258,6 +326,7 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
258326
}
259327
const coreVersion = taskUtil?.getProject("sap.ui.core")?.getVersion();
260328
const allowStringBundling = taskUtil?.getProject().getSpecVersion().lt("4.0");
329+
const createBundleInfoPreload = !!process.env.UI5_CLI_EXPERIMENTAL_BUNDLE_INFO_PRELOAD;
261330
const execModuleBundlerIfNeeded = ({options, resources}) => {
262331
if (skipBundles.includes(options.bundleDefinition.name)) {
263332
log.verbose(`Skipping generation of bundle ${options.bundleDefinition.name}`);
@@ -390,42 +459,98 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
390459
const libraryNamespaceMatch = libraryIndicatorPath.match(libraryNamespacePattern);
391460
if (libraryNamespaceMatch && libraryNamespaceMatch[1]) {
392461
const libraryNamespace = libraryNamespaceMatch[1];
393-
const results = await Promise.all([
394-
execModuleBundlerIfNeeded({
395-
options: {
396-
bundleDefinition: getBundleDefinition(libraryNamespace, excludes),
397-
bundleOptions: {
398-
optimize: true,
399-
ignoreMissingModules: true
400-
}
401-
},
402-
resources
403-
}),
404-
execModuleBundlerIfNeeded({
405-
options: {
406-
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
407-
bundleOptions: {
408-
optimize: true,
409-
ignoreMissingModules: true,
410-
skipIfEmpty: true
411-
}
412-
},
413-
resources
414-
}),
415-
execModuleBundlerIfNeeded({
416-
options: {
417-
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
418-
bundleOptions: {
419-
optimize: false,
420-
ignoreMissingModules: true,
421-
skipIfEmpty: true
422-
}
423-
// Note: Although the bundle uses optimize=false, there is
424-
// no moduleNameMapping needed, as support files are excluded from minification.
425-
},
426-
resources
427-
})
428-
]);
462+
let results;
463+
if (!createBundleInfoPreload) {
464+
// Regular bundling
465+
results = await Promise.all([
466+
execModuleBundlerIfNeeded({
467+
options: {
468+
bundleDefinition: getBundleDefinition(libraryNamespace, excludes),
469+
bundleOptions: {
470+
optimize: true,
471+
ignoreMissingModules: true
472+
}
473+
},
474+
resources
475+
}),
476+
execModuleBundlerIfNeeded({
477+
options: {
478+
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
479+
bundleOptions: {
480+
optimize: true,
481+
ignoreMissingModules: true,
482+
skipIfEmpty: true
483+
}
484+
},
485+
resources
486+
}),
487+
execModuleBundlerIfNeeded({
488+
options: {
489+
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
490+
bundleOptions: {
491+
optimize: false,
492+
ignoreMissingModules: true,
493+
skipIfEmpty: true
494+
}
495+
// Note: Although the bundle uses optimize=false, there is
496+
// no moduleNameMapping needed, as support files are excluded from minification.
497+
},
498+
resources
499+
})
500+
]);
501+
} else {
502+
log.info(
503+
`Using experimental bundling with bundle info preload ` +
504+
`for library ${libraryNamespace} in project ${projectName}.`);
505+
// Experimental bundling with bundle info preload
506+
results = await Promise.all([
507+
execModuleBundlerIfNeeded({
508+
options: {
509+
bundleDefinition:
510+
getBundleInfoPreloadDefinition(libraryNamespace, excludes, coreVersion),
511+
bundleOptions: {
512+
optimize: true,
513+
ignoreMissingModules: true
514+
}
515+
},
516+
resources
517+
}),
518+
execModuleBundlerIfNeeded({
519+
options: {
520+
bundleDefinition: getContentBundleDefinition(libraryNamespace, excludes),
521+
bundleOptions: {
522+
optimize: true,
523+
ignoreMissingModules: true
524+
}
525+
},
526+
resources
527+
}),
528+
execModuleBundlerIfNeeded({
529+
options: {
530+
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
531+
bundleOptions: {
532+
optimize: true,
533+
ignoreMissingModules: true,
534+
skipIfEmpty: true
535+
}
536+
},
537+
resources
538+
}),
539+
execModuleBundlerIfNeeded({
540+
options: {
541+
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
542+
bundleOptions: {
543+
optimize: false,
544+
ignoreMissingModules: true,
545+
skipIfEmpty: true
546+
}
547+
// Note: Although the bundle uses optimize=false, there is
548+
// no moduleNameMapping needed, as support files are excluded from minification.
549+
},
550+
resources
551+
})
552+
]);
553+
}
429554
const bundles = Array.prototype.concat.apply([], results).filter(Boolean);
430555
return Promise.all(bundles.map(({bundle, sourceMap} = {}) => {
431556
if (bundle) {

test/lib/lbt/bundle/AutoSplitter.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ function createMockPool(dependencies) {
3838
name: "x.view.xml"
3939
}, {
4040
name: "c.properties"
41-
}]
41+
}],
42+
getIgnoreMissingModules: () => false,
4243
};
4344
}
4445

@@ -165,7 +166,8 @@ test("integration: Extreme AutoSplitter with numberOfParts 50", async (t) => {
165166
});
166167
return {info};
167168
},
168-
resources: modules.map((res) => ({name: res}))
169+
resources: modules.map((res) => ({name: res})),
170+
getIgnoreMissingModules: () => false,
169171
};
170172
const autoSplitter = new AutoSplitter(pool, new BundleResolver(pool));
171173
const bundleDefinition = {
@@ -208,7 +210,8 @@ test("integration: AutoSplitter with bundleInfo", async (t) => {
208210
const info = new ModuleInfo(name);
209211
return {info};
210212
},
211-
resources: modules.map((res) => ({name: res}))
213+
resources: modules.map((res) => ({name: res})),
214+
getIgnoreMissingModules: () => false,
212215
};
213216
const autoSplitter = new AutoSplitter(pool, new BundleResolver(pool));
214217
const bundleDefinition = {

0 commit comments

Comments
 (0)