Skip to content

Commit 00ee973

Browse files
committed
[FEATURE] Build DepCache files (*-h2-preload.js) for HTTP/2 support
- implement a new bundle section type 'depcache' in the lbt builder - ignore pseudo-dependencies 'require', 'module' and 'exports' in the dependency analyzer (so that they don't appear in the dependency cache) - add configuration in the library and component preload bundlers to create bundles with the new section types in parallel to the existing preload bundles (using an '-h2-preload' suffix) - configure fixture applications g,h,i,j and fixture libraries e,h,i,j to use evo bundle format by adding a dependency to the sap.ui.core substitute fixture (sap.ui.core-evo) - add the newly introduced h2-preload bundles to the set of expected files in all fixtures that are used with one of the module bundling tasks
1 parent 53908c8 commit 00ee973

File tree

30 files changed

+365
-201
lines changed

30 files changed

+365
-201
lines changed

lib/lbt/bundle/Builder.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ const UI5BundleFormat = {
5252
outW.writeln(`}});`);
5353
},
5454

55+
beforeH2Preloads(outW) {
56+
outW.writeln(`"unsupported"; /* Bundle format 'h2' not supported (requires ui5loader)`);
57+
},
58+
59+
afterH2Preloads(outW) {
60+
outW.writeln(`*/`);
61+
},
62+
5563
requireSync(outW, moduleName) {
5664
outW.writeln(`sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");`);
5765
},
@@ -78,6 +86,14 @@ const EVOBundleFormat = {
7886
outW.writeln(`);`);
7987
},
8088

89+
beforeH2Preloads(outW) {
90+
outW.writeln(`sap.ui.loader.config({depCacheUI5:{`);
91+
},
92+
93+
afterH2Preloads(outW) {
94+
outW.writeln(`}});`);
95+
},
96+
8197
requireSync(outW, moduleName) {
8298
outW.writeln(`sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");`);
8399
},
@@ -206,6 +222,8 @@ class BundleBuilder {
206222
return this.writeRaw(section);
207223
case SectionType.Preload:
208224
return this.writePreloadFunction(section);
225+
case SectionType.DepCache:
226+
return this.writeDepCache(section);
209227
case SectionType.Require:
210228
return this.writeRequires(section);
211229
default:
@@ -449,6 +467,42 @@ class BundleBuilder {
449467
});
450468
}
451469

470+
async writeDepCache(section) {
471+
const outW = this.outW;
472+
473+
outW.ensureNewLine();
474+
475+
const sequence = section.modules.slice().sort();
476+
477+
if ( sequence.length > 0 ) {
478+
this.targetBundleFormat.beforeH2Preloads(outW, section);
479+
let i = 0;
480+
for (const module of sequence) {
481+
const resource = await this.pool.findResourceWithInfo(module);
482+
if ( resource != null ) {
483+
const deps = resource.info.dependencies.filter( (dep) =>
484+
!resource.info.isConditionalDependency(dep) && !resource.info.isImplicitDependency(dep) );
485+
if ( deps.length > 0 ) {
486+
if ( i > 0 ) {
487+
outW.writeln(",");
488+
}
489+
outW.write(`"${module}": [${deps.map((dep) => "\"" + dep + "\"").join(",")}]`);
490+
i++;
491+
} else {
492+
log.verbose(" skipped %s, no dependencies", module);
493+
}
494+
} else {
495+
log.error(" couldn't find %s", module);
496+
}
497+
}
498+
499+
if ( i > 0 ) {
500+
outW.writeln();
501+
}
502+
this.targetBundleFormat.afterH2Preloads(outW, section);
503+
}
504+
}
505+
452506
writeRequires(section) {
453507
this.outW.ensureNewLine();
454508
section.modules.forEach( (module) => {

lib/lbt/bundle/BundleDefinition.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ const SectionType = {
1717
*/
1818
Preload: "preload",
1919

20+
/**
21+
* Only the dependencies of the modules are stored as 'depCache' configuration.
22+
* Requires UI5 Evolution runtime.
23+
*/
24+
DepCache: "depcache",
25+
2026
/**
2127
* For each module, a jQuery.sap.require call will be created.
2228
* Usually used as the last section in a merged module to enforce loading and

lib/tasks/bundlers/generateComponentPreload.js

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,59 @@ module.exports = function({workspace, dependencies, options}) {
5959
}
6060
});
6161

62-
return moduleBundler({
63-
resources,
64-
options: {
65-
bundleDefinition: {
66-
name: `${namespace}/Component-preload.js`,
67-
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
68-
sections: [
69-
{
70-
mode: "preload",
71-
filters: filters,
72-
resolve: false,
73-
resolveConditional: false,
74-
renderer: false
75-
}
76-
]
62+
return Promise.all([
63+
moduleBundler({
64+
resources,
65+
options: {
66+
bundleDefinition: {
67+
name: `${namespace}/Component-preload.js`,
68+
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
69+
sections: [
70+
{
71+
mode: "preload",
72+
filters: filters,
73+
resolve: false,
74+
resolveConditional: false,
75+
renderer: false
76+
}
77+
]
78+
}
7779
}
78-
}
79-
});
80+
}),
81+
moduleBundler({
82+
resources,
83+
options: {
84+
bundleDefinition: {
85+
name: `${namespace}/Component-h2-preload.js`,
86+
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
87+
sections: [
88+
{
89+
mode: "preload",
90+
filters: [
91+
`${namespace}/library.js`,
92+
`${namespace}/manifest.json`
93+
],
94+
resolve: false,
95+
resolveConditional: false,
96+
renderer: false
97+
},
98+
{
99+
mode: "depcache",
100+
filters: filters,
101+
resolve: false,
102+
resolveConditional: false,
103+
renderer: false
104+
}
105+
]
106+
}
107+
}
108+
})
109+
]);
80110
}));
81111
})
82112
.then((processedResources) => {
113+
return Array.prototype.concat.apply([], processedResources);
114+
}).then((processedResources) => {
83115
return Promise.all(processedResources.map((resource) => {
84116
return workspace.write(resource[0]);
85117
}));

lib/tasks/bundlers/generateLibraryPreload.js

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ const log = require("@ui5/logger").getLogger("builder:tasks:bundlers:generateLib
22
const moduleBundler = require("../../processors/bundlers/moduleBundler");
33
const ReaderCollectionPrioritized = require("@ui5/fs").ReaderCollectionPrioritized;
44

5-
function getBundleDefinition(namespace) {
5+
function getBundleDefinition(namespace, h2) {
6+
const h2infix = h2 ? "h2-" : "";
7+
let bundleDef;
68
// TODO: move to config of actual core project
79
if (namespace === "sap/ui/core") {
8-
return {
9-
name: `${namespace}/library-preload.js`,
10+
bundleDef = {
11+
name: `${namespace}/library-${h2infix}preload.js`,
1012
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
1113
sections: [
1214
{
@@ -19,7 +21,7 @@ function getBundleDefinition(namespace) {
1921
resolve: true
2022
},
2123
{
22-
mode: "preload",
24+
mode: h2 ? "depcache" : "preload",
2325
filters: [
2426
`${namespace}/`,
2527
`!${namespace}/.library`,
@@ -62,28 +64,40 @@ function getBundleDefinition(namespace) {
6264
}
6365
]
6466
};
67+
} else {
68+
bundleDef = {
69+
name: `${namespace}/library-${h2infix}preload.js`,
70+
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
71+
sections: [
72+
{
73+
mode: h2 ? "depcache" : "preload",
74+
filters: [
75+
`${namespace}/`,
76+
`!${namespace}/.library`,
77+
`!${namespace}/themes/`,
78+
`!${namespace}/messagebundle*`
79+
],
80+
resolve: false,
81+
resolveConditional: false,
82+
renderer: true
83+
}
84+
]
85+
};
6586
}
66-
return {
67-
name: `${namespace}/library-preload.js`,
68-
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
69-
sections: [
70-
{
71-
mode: "preload",
72-
filters: [
73-
`${namespace}/`,
74-
`!${namespace}/.library`,
75-
`!${namespace}/designtime/`,
76-
`!${namespace}/**/*.designtime.js`,
77-
`!${namespace}/**/*.support.js`,
78-
`!${namespace}/themes/`,
79-
`!${namespace}/messagebundle*`
80-
],
81-
resolve: false,
82-
resolveConditional: false,
83-
renderer: true
84-
}
85-
]
86-
};
87+
88+
if ( h2 ) {
89+
bundleDef.sections.unshift({
90+
mode: "preload",
91+
filters: [
92+
`${namespace}/library.js`,
93+
`${namespace}/manifest.json`
94+
],
95+
resolve: false,
96+
resolveConditional: false,
97+
renderer: false
98+
});
99+
}
100+
return bundleDef;
87101
}
88102

89103
function getModuleBundlerOptions(config) {
@@ -249,21 +263,38 @@ module.exports = function({workspace, dependencies, options}) {
249263
const libraryNamespaceMatch = libraryIndicatorPath.match(libraryNamespacePattern);
250264
if (libraryNamespaceMatch && libraryNamespaceMatch[1]) {
251265
const libraryNamespace = libraryNamespaceMatch[1];
252-
return moduleBundler({
253-
options: {
254-
bundleDefinition: getBundleDefinition(libraryNamespace),
255-
bundleOptions: {
256-
optimize: true,
257-
usePredefineCalls: true
266+
return Promise.all([
267+
moduleBundler({
268+
options: {
269+
bundleDefinition: getBundleDefinition(libraryNamespace),
270+
bundleOptions: {
271+
optimize: true,
272+
usePredefineCalls: true
273+
}
274+
},
275+
resources
276+
}).then(([bundle]) => {
277+
if (bundle) {
278+
// console.log(`${libraryNamespace}/library-preload.js bundle created`);
279+
return workspace.write(bundle);
280+
}
281+
}),
282+
moduleBundler({
283+
options: {
284+
bundleDefinition: getBundleDefinition(libraryNamespace, /* h2 */ true),
285+
bundleOptions: {
286+
optimize: true,
287+
usePredefineCalls: true
288+
}
289+
},
290+
resources
291+
}).then(([bundle]) => {
292+
if (bundle) {
293+
// console.log(`${libraryNamespace}/library-h2-preload.js bundle created`);
294+
return workspace.write(bundle);
258295
}
259-
},
260-
resources
261-
}).then(([bundle]) => {
262-
if (bundle) {
263-
// console.log(`${libraryNamespace}/library-preload.js bundle created`);
264-
return workspace.write(bundle);
265-
}
266-
});
296+
})
297+
]);
267298
} else {
268299
log.verbose(`Could not determine library namespace from file "${libraryIndicatorPath}" for project ${options.projectName}. Skipping library preload bundling.`);
269300
return Promise.resolve();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ui5-bundle application/g/Component-h2-preload.js
2+
sap.ui.require.preload({
3+
"application/g/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g","type":"application","applicationVersion":{"version":"1.0.0"},"embeds":["embedded"],"title":"{{title}}"},"customCopyrightString":"Some fancy copyright"}'
4+
});
5+
sap.ui.loader.config({depCacheUI5:{
6+
"application/g/Component.js": ["sap/ui/core/UIComponent.js"],
7+
"application/g/subcomponentA/Component.js": ["sap/ui/core/UIComponent.js"],
8+
"application/g/subcomponentB/Component.js": ["sap/ui/core/UIComponent.js"]
9+
}});
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//@ui5-bundle application/g/Component-preload.js
2-
jQuery.sap.registerPreloadedModules({
3-
"version":"2.0",
4-
"modules":{
2+
sap.ui.require.preload({
53
"application/g/Component.js":function(){sap.ui.define(["sap/ui/core/UIComponent"],function(n){"use strict";return n.extend("application.g.Component",{metadata:{manifest:"json"}})});
64
},
75
"application/g/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g","type":"application","applicationVersion":{"version":"1.0.0"},"embeds":["embedded"],"title":"{{title}}"},"customCopyrightString":"Some fancy copyright"}',
@@ -11,4 +9,4 @@ jQuery.sap.registerPreloadedModules({
119
"application/g/subcomponentB/Component.js":function(){sap.ui.define(["sap/ui/core/UIComponent"],function(n){"use strict";return n.extend("application.g.subcomponentB.Component",{metadata:{manifest:"json"}})});
1210
},
1311
"application/g/subcomponentB/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g.subcomponentB","type":"application","applicationVersion":{"version":"1.2.2"},"embeds":["embedded"],"title":"{{title}}"}}'
14-
}});
12+
});

test/expected/build/application.g/cachebuster/sap-ui-cachebuster-info.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"subcomponentB/Component.js": 1540570258000,
66
"subcomponentA/Component.js": 1540570258000,
77
"Component.js": 1540570258000,
8+
"Component-h2-preload.js": 1554823987259,
89
"Component-preload.js": 1554823987259,
910
"subcomponentB/Component-dbg.js": 1540570258000,
1011
"subcomponentA/Component-dbg.js": 1540570258000,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//@ui5-bundle application/g/Component-h2-preload.js
2+
sap.ui.require.preload({
3+
"application/g/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g","type":"application","applicationVersion":{"version":"1.0.0"},"embeds":["embedded"],"title":"{{title}}"},"customCopyrightString":"Some fancy copyright"}'
4+
});
5+
sap.ui.loader.config({depCacheUI5:{
6+
"application/g/Component.js": ["sap/ui/core/UIComponent.js"]
7+
}});
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
//@ui5-bundle application/g/Component-preload.js
2-
jQuery.sap.registerPreloadedModules({
3-
"version":"2.0",
4-
"modules":{
2+
sap.ui.require.preload({
53
"application/g/Component.js":function(){sap.ui.define(["sap/ui/core/UIComponent"],function(n){"use strict";return n.extend("application.g.Component",{metadata:{manifest:"json"}})});
64
},
75
"application/g/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g","type":"application","applicationVersion":{"version":"1.0.0"},"embeds":["embedded"],"title":"{{title}}"},"customCopyrightString":"Some fancy copyright"}'
8-
}});
6+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//@ui5-bundle application/g/subcomponentA/Component-h2-preload.js
2+
sap.ui.require.preload({
3+
"application/g/subcomponentA/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g.subcomponentA","type":"application","applicationVersion":{"version":"1.2.2"},"embeds":["embedded"],"title":"{{title}}"}}'
4+
});
5+
sap.ui.loader.config({depCacheUI5:{
6+
"application/g/subcomponentA/Component.js": ["sap/ui/core/UIComponent.js"]
7+
}});

0 commit comments

Comments
 (0)