Skip to content

Commit 86378ad

Browse files
codeworriortobiasso85matz3
authored
[ui5-builder][FEATURE] Add generateResourcesJson task (#390)
Introduces new task "generateResourcesJson" which creates the file resources.json for libraries, applications and themes. The task analyses the resources and collects meta information and stores them in a file called resources.json. This meta information includes module name, size, dependencies, includes, ... Co-authored-by: Tobias Sorn <[email protected]> Co-authored-by: Matthias Osswald <[email protected]>
1 parent 7c8c159 commit 86378ad

File tree

79 files changed

+2942
-88
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2942
-88
lines changed

packages/builder/lib/builder/builder.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ function composeTaskList({dev, selfContained, jsdoc, includedTasks, excludedTask
6060
selectedTasks.generateCachebusterInfo = false;
6161
selectedTasks.generateApiIndex = false;
6262

63+
// Disable generateResourcesJson due to performance.
64+
// When executed it analyzes each module's AST and therefore
65+
// takes up much time (~10% more)
66+
selectedTasks.generateResourcesJson = false;
67+
6368
if (selfContained) {
6469
// No preloads, bundle only
6570
selectedTasks.generateComponentPreload = false;

packages/builder/lib/lbt/analyzer/JSModuleAnalyzer.js

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ function getDocumentation(node) {
239239
* @private
240240
*/
241241
class JSModuleAnalyzer {
242+
/**
243+
* Analyzes the JS AST
244+
*
245+
* @param {object} ast js ast
246+
* @param {string} defaultName default name
247+
* @param {ModuleInfo} info module info
248+
*/
242249
analyze(ast, defaultName, info) {
243250
let mainModuleFound = false;
244251
/**
@@ -260,6 +267,20 @@ class JSModuleAnalyzer {
260267
*/
261268
let nModuleDeclarations = 0;
262269

270+
/**
271+
* Whether or not this is a UI5 module
272+
*
273+
* When in the non-conditional module execution there is a call to:
274+
* <ul>
275+
* <li>sap.ui.define call</li>
276+
* <li>jQuery.sap.declare call</li>
277+
* </ul>
278+
* this value is true
279+
*
280+
* @type {boolean}
281+
*/
282+
let bIsUi5Module = false;
283+
263284
// first analyze the whole AST...
264285
visit(ast, false);
265286

@@ -307,7 +328,7 @@ class JSModuleAnalyzer {
307328
info.addImplicitDependency(UI5ClientConstants.MODULE__UI5LOADER_AUTOCONFIG);
308329
}
309330

310-
if ( nModuleDeclarations === 0 && info.dependencies.length === 0 && info.subModules.length === 0 ) {
331+
if ( !bIsUi5Module ) {
311332
// when there are no indicators for module APIs, mark the module as 'raw' module
312333
info.rawModule = true;
313334
}
@@ -320,7 +341,6 @@ class JSModuleAnalyzer {
320341
// console.log(info.name, "exposed globals", info.exposedGlobals, "ignoredGlobals", info.ignoredGlobals);
321342
}
322343

323-
return;
324344

325345
// hoisted functions
326346
function setMainModuleInfo(name, description) {
@@ -353,6 +373,7 @@ class JSModuleAnalyzer {
353373
// recognized a call to jQuery.sap.declare()
354374
nModuleDeclarations++;
355375
info.setFormat(ModuleFormat.UI5_LEGACY);
376+
bIsUi5Module = true;
356377
onDeclare(node);
357378
} else if ( !conditional &&
358379
(isMethodCall(node, CALL_SAP_UI_DEFINE) || isMethodCall(node, CALL_AMD_DEFINE)) ) {
@@ -364,6 +385,7 @@ class JSModuleAnalyzer {
364385
} else {
365386
info.setFormat(ModuleFormat.AMD);
366387
}
388+
bIsUi5Module = true;
367389
onDefine(node);
368390

369391
const args = node.arguments;
@@ -380,8 +402,24 @@ class JSModuleAnalyzer {
380402
}
381403
} else if ( isMethodCall(node, CALL_REQUIRE_PREDEFINE) || isMethodCall(node, CALL_SAP_UI_PREDEFINE) ) {
382404
// recognized a call to require.predefine() or sap.ui.predefine()
405+
if (!conditional) {
406+
bIsUi5Module = true;
407+
}
383408
info.setFormat(ModuleFormat.UI5_DEFINE);
384-
onSapUiPredefine(node);
409+
onSapUiPredefine(node, conditional);
410+
411+
const args = node.arguments;
412+
let iArg = 0;
413+
if ( iArg < args.length && isString(args[iArg]) ) {
414+
iArg++;
415+
}
416+
if ( iArg < args.length && args[iArg].type == Syntax.ArrayExpression ) {
417+
iArg++;
418+
}
419+
if ( iArg < args.length && isCallableExpression(args[iArg]) ) {
420+
// unconditionally execute the factory function
421+
visit(args[iArg].body, conditional);
422+
}
385423
} else if ( isMethodCall(node, CALL_SAP_UI_REQUIRE) || isMethodCall(node, CALL_AMD_REQUIRE) ) {
386424
// recognized a call to require() or sap.ui.require()
387425
if ( isMethodCall(node, CALL_SAP_UI_REQUIRE) ) {
@@ -404,17 +442,24 @@ class JSModuleAnalyzer {
404442
} else if ( isMethodCall(node, CALL_REQUIRE_SYNC) || isMethodCall(node, CALL_SAP_UI_REQUIRE_SYNC) ) {
405443
// recognizes a call to sap.ui.requireSync
406444
info.setFormat(ModuleFormat.UI5_DEFINE);
445+
407446
onSapUiRequireSync(node, conditional);
408447
} else if ( isMethodCall(node, CALL_JQUERY_SAP_REQUIRE) ) {
409448
// recognizes a call to jQuery.sap.require
410449
info.setFormat(ModuleFormat.UI5_LEGACY);
411450
onJQuerySapRequire(node, conditional);
412451
} else if ( isMethodCall(node, CALL_JQUERY_SAP_REGISTER_PRELOADED_MODULES) ) {
413452
// recognizes a call to jQuery.sap.registerPreloadedModules
453+
if (!conditional) {
454+
bIsUi5Module = true;
455+
}
414456
info.setFormat(ModuleFormat.UI5_LEGACY);
415457
onRegisterPreloadedModules(node, /* evoSyntax= */ false);
416458
} else if ( isMethodCall(node, CALL_SAP_UI_REQUIRE_PRELOAD) ) {
417459
// recognizes a call to sap.ui.require.preload
460+
if (!conditional) {
461+
bIsUi5Module = true;
462+
}
418463
info.setFormat(ModuleFormat.UI5_DEFINE);
419464
onRegisterPreloadedModules(node, /* evoSyntax= */ true);
420465
} else if ( isCallableExpression(node.callee) ) {
@@ -560,6 +605,7 @@ class JSModuleAnalyzer {
560605

561606
if ( i < nArgs ) {
562607
if ( isString(args[i]) ) {
608+
// sap.ui.requireSync does not support relative dependencies
563609
const moduleName = ModuleName.fromRequireJSName( args[i].value );
564610
info.addDependency(moduleName, conditional);
565611
} else {
@@ -569,7 +615,7 @@ class JSModuleAnalyzer {
569615
}
570616
}
571617

572-
function onSapUiPredefine(predefineCall) {
618+
function onSapUiPredefine(predefineCall, conditional) {
573619
const args = predefineCall.arguments;
574620
const nArgs = args.length;
575621
let i = 0;
@@ -578,6 +624,16 @@ class JSModuleAnalyzer {
578624
if ( i < nArgs && isString(args[i]) ) {
579625
const moduleName = ModuleName.fromRequireJSName( args[i++].value );
580626
info.addSubModule(moduleName);
627+
628+
// add dependencies
629+
// to correctly identify dependencies e.g. of a library-preload
630+
const elementArg = args[i++];
631+
if (elementArg && elementArg.type === Syntax.ArrayExpression) {
632+
elementArg.elements.forEach((element) => {
633+
const dependencyName = ModuleName.resolveRelativeRequireJSName(moduleName, element.value);
634+
info.addDependency(dependencyName, conditional);
635+
});
636+
}
581637
} else {
582638
log.warn("sap.ui.predefine call is missing a module name (ignored)");
583639
}

packages/builder/lib/lbt/bundle/Builder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const {SectionType} = require("./BundleDefinition");
2020
const BundleWriter = require("./BundleWriter");
2121
const log = require("@ui5/logger").getLogger("lbt:bundle:Builder");
2222

23-
const copyrightCommentsPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9/i;
23+
const copyrightCommentsPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;
2424
const xmlHtmlPrePattern = /<(?:\w+:)?pre>/;
2525

2626
const strReplacements = {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const Resource = require("./Resource");
2+
3+
4+
function extractName(path) {
5+
return path.slice( "/resources/".length);
6+
}
7+
8+
9+
class LocatorResource extends Resource {
10+
constructor(pool, resource) {
11+
super(pool, extractName(resource.getPath()), null, resource.getStatInfo());
12+
this.resource = resource;
13+
}
14+
15+
buffer() {
16+
return this.resource.getBuffer();
17+
}
18+
19+
getProject() {
20+
return this.resource._project;
21+
}
22+
}
23+
24+
module.exports = LocatorResource;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const ResourcePool = require("./ResourcePool");
2+
const LocatorResource = require("./LocatorResource");
3+
4+
5+
class LocatorResourcePool extends ResourcePool {
6+
constructor() {
7+
super();
8+
}
9+
10+
prepare(resources) {
11+
resources = resources.filter( (res) => !res.getStatInfo().isDirectory() );
12+
return Promise.all(
13+
resources.map(
14+
(resource) => this.addResource( new LocatorResource(this, resource) )
15+
).filter(Boolean)
16+
);
17+
}
18+
}
19+
20+
module.exports = LocatorResourcePool;

packages/builder/lib/lbt/resources/ModuleInfo.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class ModuleInfo {
5858
/**
5959
* 'raw' modules are modules that don't use UI5's module system (require/declare)
6060
* TODO align with module format (ui5, amd, es6, raw)
61+
*
62+
* A raw module is a module which does not have in its non-conditional execution:
63+
* <ul>
64+
* <li>sap.ui.define call</li>
65+
* <li>jQuery.sap.declare call</li>
66+
* </ul>
6167
*/
6268
this.rawModule = false;
6369

0 commit comments

Comments
 (0)