Skip to content

Commit 7102405

Browse files
committed
[FEATURE] Build DepCache info files (*-h2-preload.js) for better 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) - switch application.g, application.h and library.h fixtures to use evo bundle format by adding a dependency to the sap.ui.core substitute fixture - add the newly created h2-preload bundles to the set of expected files - add a test scenario 'library.j' that runs the library bundle generation (in order to improve code coverage)
1 parent 712dcff commit 7102405

File tree

31 files changed

+436
-171
lines changed

31 files changed

+436
-171
lines changed

lib/lbt/analyzer/JSModuleAnalyzer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ const CALL_JQUERY_SAP_IS_DECLARED = [["jQuery", "$"], "sap", "isDeclared"];
151151
const CALL_JQUERY_SAP_REQUIRE = [["jQuery", "$"], "sap", "require"];
152152
const CALL_JQUERY_SAP_REGISTER_PRELOADED_MODULES = [["jQuery", "$"], "sap", "registerPreloadedModules"];
153153

154+
const SPECIAL_AMD_DEPENDENCIES = ["require", "exports", "module"];
155+
154156

155157
/**
156158
* Analyzes an already parsed JSDocument to collect information about the contained module(s).
@@ -470,6 +472,10 @@ class JSModuleAnalyzer {
470472
// console.log(array);
471473
array.forEach( (item) => {
472474
if ( isString(item) ) {
475+
// ignore special AMD dependencies (require, exports, module)
476+
if ( SPECIAL_AMD_DEPENDENCIES.indexOf(item.value) >= 0 ) {
477+
return;
478+
}
473479
let requiredModule;
474480
if (name == null) {
475481
requiredModule = ModuleName.fromRequireJSName( item.value );

lib/lbt/bundle/Builder.js

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

53+
beforeH2Preloads(outW) {
54+
outW.writeln(`"unsupported"; /* Bundle format 'h2' not supported (requires ui5loader)`);
55+
},
56+
57+
afterH2Preloads(outW) {
58+
outW.writeln(`*/`);
59+
},
60+
5361
requireSync(outW, moduleName) {
5462
outW.writeln(`sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");`);
5563
},
@@ -76,6 +84,14 @@ const EVOBundleFormat = {
7684
outW.writeln(`);`);
7785
},
7886

87+
beforeH2Preloads(outW) {
88+
outW.writeln(`sap.ui.loader.config({depCacheUI5:{`);
89+
},
90+
91+
afterH2Preloads(outW) {
92+
outW.writeln(`}});`);
93+
},
94+
7995
requireSync(outW, moduleName) {
8096
outW.writeln(`sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");`);
8197
},
@@ -205,6 +221,8 @@ class BundleBuilder {
205221
return this.writeRaw(section);
206222
case SectionType.Preload:
207223
return this.writePreloadFunction(section);
224+
case SectionType.DepCache:
225+
return this.writeDepCache(section);
208226
case SectionType.Require:
209227
return this.writeRequires(section);
210228
default:
@@ -481,6 +499,42 @@ class BundleBuilder {
481499
});
482500
}
483501

502+
async writeDepCache(section) {
503+
const outW = this.outW;
504+
505+
outW.ensureNewLine();
506+
507+
const sequence = section.modules.slice();
508+
509+
if ( sequence.length > 0 ) {
510+
this.targetBundleFormat.beforeH2Preloads(outW, section);
511+
let i = 0;
512+
for (let module of sequence) {
513+
let resource = await this.pool.findResourceWithInfo(module);
514+
if ( resource != null ) {
515+
let deps = resource.info.dependencies.filter( (dep) =>
516+
!resource.info.isConditionalDependency(dep) && !resource.info.isImplicitDependency(dep) );
517+
if ( deps.length > 0 ) {
518+
if ( i > 0 ) {
519+
outW.writeln(",");
520+
}
521+
outW.write(`"${module}": [${deps.map((dep) => "\"" + dep + "\"").join(",")}]`);
522+
i++;
523+
} else {
524+
log.verbose(" skipped %s, no dependencies", module);
525+
}
526+
} else {
527+
log.error(" couldn't find %s", module);
528+
}
529+
}
530+
531+
if ( i > 0 ) {
532+
outW.writeln();
533+
}
534+
this.targetBundleFormat.afterH2Preloads(outW, section);
535+
}
536+
}
537+
484538
writeRequires(section) {
485539
this.outW.ensureNewLine();
486540
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
@@ -56,27 +56,59 @@ module.exports = function({workspace, dependencies, options}) {
5656
}
5757
});
5858

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

lib/tasks/bundlers/generateLibraryPreload.js

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ 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+
let 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
{
13-
mode: "preload",
15+
mode: h2 ? "depcache" : "preload",
1416
filters: [
1517
`${namespace}/`,
1618
`!${namespace}/.library`,
@@ -41,27 +43,42 @@ function getBundleDefinition(namespace) {
4143
}
4244
]
4345
};
46+
} else {
47+
bundleDef = {
48+
name: `${namespace}/library-${h2infix}preload.js`,
49+
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
50+
sections: [
51+
{
52+
mode: h2 ? "depcache" : "preload",
53+
filters: [
54+
`${namespace}/`,
55+
`!${namespace}/.library`,
56+
`!${namespace}/themes/`,
57+
`!${namespace}/messagebundle*`
58+
],
59+
resolve: false,
60+
resolveConditional: false,
61+
renderer: true
62+
}
63+
]
64+
};
4465
}
45-
return {
46-
name: `${namespace}/library-preload.js`,
47-
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
48-
sections: [
49-
{
50-
mode: "preload",
51-
filters: [
52-
`${namespace}/`,
53-
`!${namespace}/.library`,
54-
`!${namespace}/themes/`,
55-
`!${namespace}/messagebundle*`
56-
],
57-
resolve: false,
58-
resolveConditional: false,
59-
renderer: true
60-
}
61-
]
62-
};
66+
if ( h2 ) {
67+
bundleDef.sections.unshift({
68+
mode: "preload",
69+
filters: [
70+
`${namespace}/library.js`,
71+
`${namespace}/manifest.json`
72+
],
73+
resolve: false,
74+
resolveConditional: false,
75+
renderer: false
76+
});
77+
}
78+
return bundleDef;
6379
}
6480

81+
6582
/**
6683
* Task for library bundling.
6784
*
@@ -168,17 +185,30 @@ module.exports = function({workspace, dependencies, options}) {
168185
const libraryNamespaceMatch = libraryIndicatorPath.match(libraryNamespacePattern);
169186
if (libraryNamespaceMatch && libraryNamespaceMatch[1]) {
170187
const libraryNamespace = libraryNamespaceMatch[1];
171-
return moduleBundler({
172-
options: {
173-
bundleDefinition: getBundleDefinition(libraryNamespace)
174-
},
175-
resources
176-
}).then(([bundle]) => {
177-
if (bundle) {
178-
// console.log(`${libraryNamespace}/library-preload.js bundle created`);
179-
return workspace.write(bundle);
180-
}
181-
});
188+
return Promise.all([
189+
moduleBundler({
190+
options: {
191+
bundleDefinition: getBundleDefinition(libraryNamespace)
192+
},
193+
resources
194+
}).then(([bundle]) => {
195+
if (bundle) {
196+
// console.log(`${libraryNamespace}/library-preload.js bundle created`);
197+
return workspace.write(bundle);
198+
}
199+
}),
200+
moduleBundler({
201+
options: {
202+
bundleDefinition: getBundleDefinition(libraryNamespace, /* h2 */ true)
203+
},
204+
resources
205+
}).then(([bundle]) => {
206+
if (bundle) {
207+
// console.log(`${libraryNamespace}/library-h2-preload.js bundle created`);
208+
return workspace.write(bundle);
209+
}
210+
})
211+
]);
182212
} else {
183213
log.verbose(`Could not determine library namespace from file "${libraryIndicatorPath}" for project ${options.projectName}. Skipping library preload bundling.`);
184214
return Promise.resolve();
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
sap.ui.require.preload({
2+
"application/g/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g","type":"application","applicationVersion":{"version":"1.2.2"},"embeds":["embedded"],"title":"{{title}}"}}'
3+
});
4+
sap.ui.loader.config({depCacheUI5:{
5+
"application/g/Component.js": ["sap/ui/core/UIComponent.js"]
6+
}});
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
jQuery.sap.registerPreloadedModules({
2-
"version":"2.0",
3-
"modules":{
1+
sap.ui.require.preload({
42
"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"}})});
53
},
64
"application/g/manifest.json":'{"_version":"1.1.0","sap.app":{"_version":"1.1.0","id":"application.g","type":"application","applicationVersion":{"version":"1.2.2"},"embeds":["embedded"],"title":"{{title}}"}}'
7-
}});
5+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
sap.ui.require.preload({
2+
"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}}"}}'
3+
});
4+
sap.ui.loader.config({depCacheUI5:{
5+
"application/g/subcomponentA/Component.js": ["sap/ui/core/UIComponent.js"]
6+
}});
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
jQuery.sap.registerPreloadedModules({
2-
"version":"2.0",
3-
"modules":{
1+
sap.ui.require.preload({
42
"application/g/subcomponentA/Component.js":function(){sap.ui.define(["sap/ui/core/UIComponent"],function(n){"use strict";return n.extend("application.g.subcomponentA.Component",{metadata:{manifest:"json"}})});
53
},
64
"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}}"}}'
7-
}});
5+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
sap.ui.require.preload({
2+
"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}}"}}'
3+
});
4+
sap.ui.loader.config({depCacheUI5:{
5+
"application/g/subcomponentB/Component.js": ["sap/ui/core/UIComponent.js"]
6+
}});

0 commit comments

Comments
 (0)