Skip to content

Commit

Permalink
[FEATURE] Build DepCache files (*-h2-preload.js) for HTTP/2 support
Browse files Browse the repository at this point in the history
- 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)
  • Loading branch information
codeworrior committed Jul 5, 2018
1 parent 05d4127 commit a2b9599
Show file tree
Hide file tree
Showing 31 changed files with 436 additions and 171 deletions.
6 changes: 6 additions & 0 deletions lib/lbt/analyzer/JSModuleAnalyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ const CALL_JQUERY_SAP_IS_DECLARED = [["jQuery", "$"], "sap", "isDeclared"];
const CALL_JQUERY_SAP_REQUIRE = [["jQuery", "$"], "sap", "require"];
const CALL_JQUERY_SAP_REGISTER_PRELOADED_MODULES = [["jQuery", "$"], "sap", "registerPreloadedModules"];

const SPECIAL_AMD_DEPENDENCIES = ["require", "exports", "module"];

function isCallableExpression(node) {
return node.type == Syntax.FunctionExpression || node.type == Syntax.ArrowFunctionExpression;
}
Expand Down Expand Up @@ -534,6 +536,10 @@ class JSModuleAnalyzer {
// console.log(array);
array.forEach( (item) => {
if ( isString(item) ) {
// ignore special AMD dependencies (require, exports, module)
if ( SPECIAL_AMD_DEPENDENCIES.indexOf(item.value) >= 0 ) {
return;
}
let requiredModule;
if (name == null) {
requiredModule = ModuleName.fromRequireJSName( item.value );
Expand Down
54 changes: 54 additions & 0 deletions lib/lbt/bundle/Builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ const UI5BundleFormat = {
outW.writeln(`}});`);
},

beforeH2Preloads(outW) {
outW.writeln(`"unsupported"; /* Bundle format 'h2' not supported (requires ui5loader)`);
},

afterH2Preloads(outW) {
outW.writeln(`*/`);
},

requireSync(outW, moduleName) {
outW.writeln(`sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");`);
},
Expand All @@ -76,6 +84,14 @@ const EVOBundleFormat = {
outW.writeln(`);`);
},

beforeH2Preloads(outW) {
outW.writeln(`sap.ui.loader.config({depCacheUI5:{`);
},

afterH2Preloads(outW) {
outW.writeln(`}});`);
},

requireSync(outW, moduleName) {
outW.writeln(`sap.ui.requireSync("${ModuleName.toRequireJSName(moduleName)}");`);
},
Expand Down Expand Up @@ -205,6 +221,8 @@ class BundleBuilder {
return this.writeRaw(section);
case SectionType.Preload:
return this.writePreloadFunction(section);
case SectionType.DepCache:
return this.writeDepCache(section);
case SectionType.Require:
return this.writeRequires(section);
default:
Expand Down Expand Up @@ -481,6 +499,42 @@ class BundleBuilder {
});
}

async writeDepCache(section) {
const outW = this.outW;

outW.ensureNewLine();

const sequence = section.modules.slice();

if ( sequence.length > 0 ) {
this.targetBundleFormat.beforeH2Preloads(outW, section);
let i = 0;
for (let module of sequence) {
let resource = await this.pool.findResourceWithInfo(module);
if ( resource != null ) {
let deps = resource.info.dependencies.filter( (dep) =>
!resource.info.isConditionalDependency(dep) && !resource.info.isImplicitDependency(dep) );
if ( deps.length > 0 ) {
if ( i > 0 ) {
outW.writeln(",");
}
outW.write(`"${module}": [${deps.map((dep) => "\"" + dep + "\"").join(",")}]`);
i++;
} else {
log.verbose(" skipped %s, no dependencies", module);
}
} else {
log.error(" couldn't find %s", module);
}
}

if ( i > 0 ) {
outW.writeln();
}
this.targetBundleFormat.afterH2Preloads(outW, section);
}
}

writeRequires(section) {
this.outW.ensureNewLine();
section.modules.forEach( (module) => {
Expand Down
6 changes: 6 additions & 0 deletions lib/lbt/bundle/BundleDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ const SectionType = {
*/
Preload: "preload",

/**
* Only the dependencies of the modules are stored as 'depCache' configuration.
* Requires UI5 Evolution runtime.
*/
DepCache: "depcache",

/**
* For each module, a jQuery.sap.require call will be created.
* Usually used as the last section in a merged module to enforce loading and
Expand Down
66 changes: 49 additions & 17 deletions lib/tasks/bundlers/generateComponentPreload.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,59 @@ module.exports = function({workspace, dependencies, options}) {
}
});

return moduleBundler({
resources,
options: {
bundleDefinition: {
name: `${namespace}/Component-preload.js`,
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
sections: [
{
mode: "preload",
filters: filters,
resolve: false,
resolveConditional: false,
renderer: false
}
]
return Promise.all([
moduleBundler({
resources,
options: {
bundleDefinition: {
name: `${namespace}/Component-preload.js`,
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
sections: [
{
mode: "preload",
filters: filters,
resolve: false,
resolveConditional: false,
renderer: false
}
]
}
}
}
});
}),
moduleBundler({
resources,
options: {
bundleDefinition: {
name: `${namespace}/Component-h2-preload.js`,
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
sections: [
{
mode: "preload",
filters: [
`${namespace}/library.js`,
`${namespace}/manifest.json`
],
resolve: false,
resolveConditional: false,
renderer: false
},
{
mode: "depcache",
filters: filters,
resolve: false,
resolveConditional: false,
renderer: false
}
]
}
}
})
]);
}));
})
.then((processedResources) => {
return Array.prototype.concat.apply([], processedResources);
}).then((processedResources) => {
return Promise.all(processedResources.map((resource) => {
return workspace.write(resource[0]);
}));
Expand Down
96 changes: 63 additions & 33 deletions lib/tasks/bundlers/generateLibraryPreload.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ const log = require("@ui5/logger").getLogger("builder:tasks:bundlers:generateLib
const moduleBundler = require("../../processors/bundlers/moduleBundler");
const ReaderCollectionPrioritized = require("@ui5/fs").ReaderCollectionPrioritized;

function getBundleDefinition(namespace) {
function getBundleDefinition(namespace, h2) {
let h2infix = h2 ? "h2-" : "";
let bundleDef;
// TODO: move to config of actual core project
if (namespace === "sap/ui/core") {
return {
name: `${namespace}/library-preload.js`,
bundleDef = {
name: `${namespace}/library-${h2infix}preload.js`,
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
sections: [
{
mode: "preload",
mode: h2 ? "depcache" : "preload",
filters: [
`${namespace}/`,
`!${namespace}/.library`,
Expand Down Expand Up @@ -41,27 +43,42 @@ function getBundleDefinition(namespace) {
}
]
};
} else {
bundleDef = {
name: `${namespace}/library-${h2infix}preload.js`,
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
sections: [
{
mode: h2 ? "depcache" : "preload",
filters: [
`${namespace}/`,
`!${namespace}/.library`,
`!${namespace}/themes/`,
`!${namespace}/messagebundle*`
],
resolve: false,
resolveConditional: false,
renderer: true
}
]
};
}
return {
name: `${namespace}/library-preload.js`,
defaultFileTypes: [".js", ".fragment.xml", ".view.xml", ".properties", ".json"],
sections: [
{
mode: "preload",
filters: [
`${namespace}/`,
`!${namespace}/.library`,
`!${namespace}/themes/`,
`!${namespace}/messagebundle*`
],
resolve: false,
resolveConditional: false,
renderer: true
}
]
};
if ( h2 ) {
bundleDef.sections.unshift({
mode: "preload",
filters: [
`${namespace}/library.js`,
`${namespace}/manifest.json`
],
resolve: false,
resolveConditional: false,
renderer: false
});
}
return bundleDef;
}


/**
* Task for library bundling.
*
Expand Down Expand Up @@ -168,17 +185,30 @@ module.exports = function({workspace, dependencies, options}) {
const libraryNamespaceMatch = libraryIndicatorPath.match(libraryNamespacePattern);
if (libraryNamespaceMatch && libraryNamespaceMatch[1]) {
const libraryNamespace = libraryNamespaceMatch[1];
return moduleBundler({
options: {
bundleDefinition: getBundleDefinition(libraryNamespace)
},
resources
}).then(([bundle]) => {
if (bundle) {
// console.log(`${libraryNamespace}/library-preload.js bundle created`);
return workspace.write(bundle);
}
});
return Promise.all([
moduleBundler({
options: {
bundleDefinition: getBundleDefinition(libraryNamespace)
},
resources
}).then(([bundle]) => {
if (bundle) {
// console.log(`${libraryNamespace}/library-preload.js bundle created`);
return workspace.write(bundle);
}
}),
moduleBundler({
options: {
bundleDefinition: getBundleDefinition(libraryNamespace, /* h2 */ true)
},
resources
}).then(([bundle]) => {
if (bundle) {
// console.log(`${libraryNamespace}/library-h2-preload.js bundle created`);
return workspace.write(bundle);
}
})
]);
} else {
log.verbose(`Could not determine library namespace from file "${libraryIndicatorPath}" for project ${options.projectName}. Skipping library preload bundling.`);
return Promise.resolve();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sap.ui.require.preload({
"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}}"}}'
});
sap.ui.loader.config({depCacheUI5:{
"application/g/Component.js": ["sap/ui/core/UIComponent.js"]
}});
6 changes: 2 additions & 4 deletions test/expected/build/application.g/dest/Component-preload.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
jQuery.sap.registerPreloadedModules({
"version":"2.0",
"modules":{
sap.ui.require.preload({
"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"}})});
},
"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}}"}}'
}});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sap.ui.require.preload({
"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}}"}}'
});
sap.ui.loader.config({depCacheUI5:{
"application/g/subcomponentA/Component.js": ["sap/ui/core/UIComponent.js"]
}});
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
jQuery.sap.registerPreloadedModules({
"version":"2.0",
"modules":{
sap.ui.require.preload({
"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"}})});
},
"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}}"}}'
}});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sap.ui.require.preload({
"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}}"}}'
});
sap.ui.loader.config({depCacheUI5:{
"application/g/subcomponentB/Component.js": ["sap/ui/core/UIComponent.js"]
}});
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
jQuery.sap.registerPreloadedModules({
"version":"2.0",
"modules":{
sap.ui.require.preload({
"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"}})});
},
"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}}"}}'
}});
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
jQuery.sap.registerPreloadedModules({
"version":"2.0",
"modules":{
sap.ui.require.preload({
"application/h/sectionsA/section1.js":function(){sap.ui.define(["sap/m/Button"],function(n){console.log("Section 1 included")});
},
"application/h/sectionsA/section3.js":function(){sap.ui.define(["sap/m/Button"],function(n){console.log("Section 3 included")});
}
}});
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
jQuery.sap.registerPreloadedModules({
"version":"2.0",
"modules":{
sap.ui.require.preload({
"application/h/sectionsB/section1.js":function(){sap.ui.define(["sap/m/Button"],function(n){console.log("Section 1 included")});
},
"application/h/sectionsB/section2.js":function(){sap.ui.define(["sap/m/Button"],function(n){console.log("Section 2 included")});
},
"application/h/sectionsB/section3.js":function(){sap.ui.define(["sap/m/Button"],function(n){console.log("Section 3 included")});
}
}});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sap.ui.loader.config({depCacheUI5:{
"library/h/components/Component.js": ["sap/ui/core/UIComponent.js"]
}});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sap.ui.loader.config({depCacheUI5:{
"library/h/components/subcomponent1/Component.js": ["sap/ui/core/UIComponent.js"]
}});
Loading

0 comments on commit a2b9599

Please sign in to comment.