Skip to content

Commit e9c7528

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

File tree

3 files changed

+159
-40
lines changed

3 files changed

+159
-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: 151 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,63 @@ 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+
if (parsedVersion) {
130+
if (parsedVersion.major >= 2) {
131+
// Do not include manifest.json in UI5 2.x and higher to allow for loading it upfront for all libraries
132+
sections.unshift({
133+
mode: "provided",
134+
filters: [
135+
`${namespace}/manifest.json`,
136+
]
137+
});
138+
}
139+
}
140+
}
141+
142+
return {
143+
name: `${namespace}/library-preload.js`,
144+
sections,
145+
};
146+
}
147+
148+
function getContentBundleDefinition(namespace, excludes) {
149+
return {
150+
name: `${namespace}/library-content.js`,
151+
sections: [{
152+
mode: "provided",
153+
filters: [
154+
`${namespace}/library.js`,
155+
],
156+
resolve: true
157+
}, {
158+
mode: "preload",
159+
filters: getDefaultLibraryPreloadFilters(namespace, excludes),
160+
resolve: false,
161+
resolveConditional: false,
162+
renderer: true
163+
}]
164+
};
165+
}
166+
109167
function getDesigntimeBundleDefinition(namespace) {
110168
return {
111169
name: `${namespace}/designtime/library-preload.designtime.js`,
@@ -258,6 +316,7 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
258316
}
259317
const coreVersion = taskUtil?.getProject("sap.ui.core")?.getVersion();
260318
const allowStringBundling = taskUtil?.getProject().getSpecVersion().lt("4.0");
319+
const createBundleInfoPreload = !!process.env.UI5_CLI_EXPERIMENTAL_BUNDLE_INFO_PRELOAD;
261320
const execModuleBundlerIfNeeded = ({options, resources}) => {
262321
if (skipBundles.includes(options.bundleDefinition.name)) {
263322
log.verbose(`Skipping generation of bundle ${options.bundleDefinition.name}`);
@@ -390,42 +449,98 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
390449
const libraryNamespaceMatch = libraryIndicatorPath.match(libraryNamespacePattern);
391450
if (libraryNamespaceMatch && libraryNamespaceMatch[1]) {
392451
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-
]);
452+
let results;
453+
if (!createBundleInfoPreload) {
454+
// Regular bundling
455+
results = await Promise.all([
456+
execModuleBundlerIfNeeded({
457+
options: {
458+
bundleDefinition: getBundleDefinition(libraryNamespace, excludes),
459+
bundleOptions: {
460+
optimize: true,
461+
ignoreMissingModules: true
462+
}
463+
},
464+
resources
465+
}),
466+
execModuleBundlerIfNeeded({
467+
options: {
468+
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
469+
bundleOptions: {
470+
optimize: true,
471+
ignoreMissingModules: true,
472+
skipIfEmpty: true
473+
}
474+
},
475+
resources
476+
}),
477+
execModuleBundlerIfNeeded({
478+
options: {
479+
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
480+
bundleOptions: {
481+
optimize: false,
482+
ignoreMissingModules: true,
483+
skipIfEmpty: true
484+
}
485+
// Note: Although the bundle uses optimize=false, there is
486+
// no moduleNameMapping needed, as support files are excluded from minification.
487+
},
488+
resources
489+
})
490+
]);
491+
} else {
492+
log.info(
493+
`Using experimental bundling with bundle info preload ` +
494+
`for library ${libraryNamespace} in project ${projectName}.`);
495+
// Experimental bundling with bundle info preload
496+
results = await Promise.all([
497+
execModuleBundlerIfNeeded({
498+
options: {
499+
bundleDefinition:
500+
getBundleInfoPreloadDefinition(libraryNamespace, excludes, coreVersion),
501+
bundleOptions: {
502+
optimize: true,
503+
ignoreMissingModules: true
504+
}
505+
},
506+
resources
507+
}),
508+
execModuleBundlerIfNeeded({
509+
options: {
510+
bundleDefinition: getContentBundleDefinition(libraryNamespace, excludes),
511+
bundleOptions: {
512+
optimize: true,
513+
ignoreMissingModules: true
514+
}
515+
},
516+
resources
517+
}),
518+
execModuleBundlerIfNeeded({
519+
options: {
520+
bundleDefinition: getDesigntimeBundleDefinition(libraryNamespace),
521+
bundleOptions: {
522+
optimize: true,
523+
ignoreMissingModules: true,
524+
skipIfEmpty: true
525+
}
526+
},
527+
resources
528+
}),
529+
execModuleBundlerIfNeeded({
530+
options: {
531+
bundleDefinition: getSupportFilesBundleDefinition(libraryNamespace),
532+
bundleOptions: {
533+
optimize: false,
534+
ignoreMissingModules: true,
535+
skipIfEmpty: true
536+
}
537+
// Note: Although the bundle uses optimize=false, there is
538+
// no moduleNameMapping needed, as support files are excluded from minification.
539+
},
540+
resources
541+
})
542+
]);
543+
}
429544
const bundles = Array.prototype.concat.apply([], results).filter(Boolean);
430545
return Promise.all(bundles.map(({bundle, sourceMap} = {}) => {
431546
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)