@ui5/builder 3.0.0-alpha.0 → 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +4 -16
- package/jsdoc.json +0 -1
- package/lib/builder/BuildContext.js +17 -0
- package/lib/builder/ProjectBuildContext.js +9 -7
- package/lib/builder/builder.js +1 -2
- package/lib/lbt/analyzer/JSModuleAnalyzer.js +7 -0
- package/lib/lbt/bundle/AutoSplitter.js +10 -24
- package/lib/lbt/bundle/Builder.js +13 -41
- package/lib/lbt/resources/LocatorResource.js +0 -2
- package/lib/lbt/resources/Resource.js +7 -0
- package/lib/lbt/resources/ResourceCollector.js +33 -15
- package/lib/lbt/utils/parseUtils.js +1 -1
- package/lib/processors/bundlers/moduleBundler.js +11 -7
- package/lib/processors/minifier.js +84 -0
- package/lib/processors/resourceListCreator.js +2 -16
- package/lib/tasks/TaskUtil.js +9 -9
- package/lib/tasks/bundlers/generateBundle.js +30 -2
- package/lib/tasks/bundlers/generateComponentPreload.js +8 -1
- package/lib/tasks/bundlers/generateLibraryPreload.js +33 -4
- package/lib/tasks/bundlers/generateStandaloneAppBundle.js +13 -6
- package/lib/tasks/generateResourcesJson.js +14 -8
- package/lib/tasks/minify.js +31 -0
- package/lib/tasks/taskRepository.js +6 -2
- package/lib/types/application/ApplicationBuilder.js +22 -31
- package/lib/types/library/LibraryBuilder.js +21 -27
- package/lib/types/themeLibrary/ThemeLibraryBuilder.js +1 -0
- package/package.json +12 -12
- package/CHANGELOG.md +0 -726
- package/lib/processors/debugFileCreator.js +0 -52
- package/lib/processors/resourceCopier.js +0 -24
- package/lib/processors/uglifier.js +0 -45
- package/lib/tasks/createDebugFiles.js +0 -30
- package/lib/tasks/uglify.js +0 -33
package/index.js
CHANGED
|
@@ -42,9 +42,9 @@ module.exports = {
|
|
|
42
42
|
*/
|
|
43
43
|
bootstrapHtmlTransformer: "./lib/processors/bootstrapHtmlTransformer",
|
|
44
44
|
/**
|
|
45
|
-
* @type {import('./lib/processors/
|
|
45
|
+
* @type {import('./lib/processors/minifier')}
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
minifier: "./lib/processors/minifier",
|
|
48
48
|
/**
|
|
49
49
|
* @type {import('./lib/processors/libraryLessGenerator')}
|
|
50
50
|
*/
|
|
@@ -53,10 +53,6 @@ module.exports = {
|
|
|
53
53
|
* @type {import('./lib/processors/manifestCreator')}
|
|
54
54
|
*/
|
|
55
55
|
manifestCreator: "./lib/processors/manifestCreator",
|
|
56
|
-
/**
|
|
57
|
-
* @type {import('./lib/processors/resourceCopier')}
|
|
58
|
-
*/
|
|
59
|
-
resourceCopier: "./lib/processors/resourceCopier",
|
|
60
56
|
/**
|
|
61
57
|
* @type {import('./lib/processors/nonAsciiEscaper')}
|
|
62
58
|
*/
|
|
@@ -69,10 +65,6 @@ module.exports = {
|
|
|
69
65
|
* @type {import('./lib/processors/themeBuilder')}
|
|
70
66
|
*/
|
|
71
67
|
themeBuilder: "./lib/processors/themeBuilder",
|
|
72
|
-
/**
|
|
73
|
-
* @type {import('./lib/processors/uglifier')}
|
|
74
|
-
*/
|
|
75
|
-
uglifier: "./lib/processors/uglifier",
|
|
76
68
|
/**
|
|
77
69
|
* @type {import('./lib/processors/versionInfoGenerator')}
|
|
78
70
|
*/
|
|
@@ -121,9 +113,9 @@ module.exports = {
|
|
|
121
113
|
*/
|
|
122
114
|
buildThemes: "./lib/tasks/buildThemes",
|
|
123
115
|
/**
|
|
124
|
-
* @type {import('./lib/tasks/
|
|
116
|
+
* @type {import('./lib/tasks/minify')}
|
|
125
117
|
*/
|
|
126
|
-
|
|
118
|
+
minify: "./lib/tasks/minify",
|
|
127
119
|
/**
|
|
128
120
|
* @type {import('./lib/tasks/jsdoc/executeJsdocSdkTransformation')}
|
|
129
121
|
*/
|
|
@@ -160,10 +152,6 @@ module.exports = {
|
|
|
160
152
|
* @type {import('./lib/tasks/transformBootstrapHtml')}
|
|
161
153
|
*/
|
|
162
154
|
transformBootstrapHtml: "./lib/tasks/transformBootstrapHtml",
|
|
163
|
-
/**
|
|
164
|
-
* @type {import('./lib/tasks/uglify')}
|
|
165
|
-
*/
|
|
166
|
-
uglify: "./lib/tasks/uglify",
|
|
167
155
|
/**
|
|
168
156
|
* @type {import('./lib/tasks/taskRepository')}
|
|
169
157
|
*/
|
package/jsdoc.json
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
const ResourceTagCollection = require("@ui5/fs").ResourceTagCollection;
|
|
1
2
|
const ProjectBuildContext = require("./ProjectBuildContext");
|
|
2
3
|
|
|
4
|
+
// Note: When adding standard tags, always update the public documentation in TaskUtil
|
|
5
|
+
// (Type "module:@ui5/builder.tasks.TaskUtil~StandardBuildTags")
|
|
6
|
+
const GLOBAL_TAGS = Object.freeze({
|
|
7
|
+
IsDebugVariant: "ui5:IsDebugVariant",
|
|
8
|
+
HasDebugVariant: "ui5:HasDebugVariant",
|
|
9
|
+
});
|
|
10
|
+
|
|
3
11
|
/**
|
|
4
12
|
* Context of a build process
|
|
5
13
|
*
|
|
@@ -13,6 +21,10 @@ class BuildContext {
|
|
|
13
21
|
}
|
|
14
22
|
this.rootProject = rootProject;
|
|
15
23
|
this.projectBuildContexts = [];
|
|
24
|
+
|
|
25
|
+
this._resourceTagCollection = new ResourceTagCollection({
|
|
26
|
+
allowedTags: Object.values(GLOBAL_TAGS)
|
|
27
|
+
});
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
getRootProject() {
|
|
@@ -22,6 +34,7 @@ class BuildContext {
|
|
|
22
34
|
createProjectContext({project, resources}) {
|
|
23
35
|
const projectBuildContext = new ProjectBuildContext({
|
|
24
36
|
buildContext: this,
|
|
37
|
+
globalTags: GLOBAL_TAGS,
|
|
25
38
|
project,
|
|
26
39
|
resources
|
|
27
40
|
});
|
|
@@ -34,6 +47,10 @@ class BuildContext {
|
|
|
34
47
|
return ctx.executeCleanupTasks();
|
|
35
48
|
}));
|
|
36
49
|
}
|
|
50
|
+
|
|
51
|
+
getResourceTagCollection() {
|
|
52
|
+
return this._resourceTagCollection;
|
|
53
|
+
}
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
module.exports = BuildContext;
|
|
@@ -2,10 +2,10 @@ const ResourceTagCollection = require("@ui5/fs").ResourceTagCollection;
|
|
|
2
2
|
|
|
3
3
|
// Note: When adding standard tags, always update the public documentation in TaskUtil
|
|
4
4
|
// (Type "module:@ui5/builder.tasks.TaskUtil~StandardBuildTags")
|
|
5
|
-
const STANDARD_TAGS =
|
|
5
|
+
const STANDARD_TAGS = {
|
|
6
6
|
OmitFromBuildResult: "ui5:OmitFromBuildResult",
|
|
7
|
-
IsBundle: "ui5:IsBundle"
|
|
8
|
-
}
|
|
7
|
+
IsBundle: "ui5:IsBundle",
|
|
8
|
+
};
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Build context of a single project. Always part of an overall
|
|
@@ -15,8 +15,8 @@ const STANDARD_TAGS = Object.freeze({
|
|
|
15
15
|
* @memberof module:@ui5/builder.builder
|
|
16
16
|
*/
|
|
17
17
|
class ProjectBuildContext {
|
|
18
|
-
constructor({buildContext, project, resources}) {
|
|
19
|
-
if (!buildContext || !project || !resources) {
|
|
18
|
+
constructor({buildContext, globalTags, project, resources}) {
|
|
19
|
+
if (!buildContext || !globalTags || !project || !resources) {
|
|
20
20
|
throw new Error(`One or more mandatory parameters are missing`);
|
|
21
21
|
}
|
|
22
22
|
this._buildContext = buildContext;
|
|
@@ -26,10 +26,12 @@ class ProjectBuildContext {
|
|
|
26
26
|
cleanup: []
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
this.STANDARD_TAGS = STANDARD_TAGS;
|
|
29
|
+
this.STANDARD_TAGS = Object.assign({}, STANDARD_TAGS, globalTags);
|
|
30
|
+
Object.freeze(this.STANDARD_TAGS);
|
|
30
31
|
|
|
31
32
|
this._resourceTagCollection = new ResourceTagCollection({
|
|
32
|
-
allowedTags: Object.values(this.STANDARD_TAGS)
|
|
33
|
+
allowedTags: Object.values(this.STANDARD_TAGS),
|
|
34
|
+
superCollection: this._buildContext.getResourceTagCollection()
|
|
33
35
|
});
|
|
34
36
|
}
|
|
35
37
|
|
package/lib/builder/builder.js
CHANGED
|
@@ -94,8 +94,7 @@ function composeTaskList({dev, selfContained, jsdoc, includedTasks, excludedTask
|
|
|
94
94
|
selectedTasks.generateComponentPreload = false;
|
|
95
95
|
selectedTasks.generateLibraryPreload = false;
|
|
96
96
|
selectedTasks.generateLibraryManifest = false;
|
|
97
|
-
selectedTasks.
|
|
98
|
-
selectedTasks.uglify = false;
|
|
97
|
+
selectedTasks.minify = false;
|
|
99
98
|
selectedTasks.generateFlexChangesBundle = false;
|
|
100
99
|
selectedTasks.generateManifestBundle = false;
|
|
101
100
|
}
|
|
@@ -64,6 +64,7 @@ const EnrichedVisitorKeys = (function() {
|
|
|
64
64
|
BreakStatement: [],
|
|
65
65
|
CallExpression: [], // special handling
|
|
66
66
|
CatchClause: ["param", "body"],
|
|
67
|
+
ChainExpression: [],
|
|
67
68
|
ClassBody: [],
|
|
68
69
|
ClassDeclaration: [],
|
|
69
70
|
ClassExpression: [],
|
|
@@ -125,8 +126,10 @@ const EnrichedVisitorKeys = (function() {
|
|
|
125
126
|
* All properties in an object pattern are executed.
|
|
126
127
|
*/
|
|
127
128
|
ObjectPattern: [], // properties
|
|
129
|
+
// PrivateIdentifier: [], // will come with ES2022
|
|
128
130
|
Program: [],
|
|
129
131
|
Property: [],
|
|
132
|
+
// PropertyDefinition: [], // will come with ES2022
|
|
130
133
|
/*
|
|
131
134
|
* argument of the rest element is always executed under the same condition as the rest element itself
|
|
132
135
|
*/
|
|
@@ -134,6 +137,7 @@ const EnrichedVisitorKeys = (function() {
|
|
|
134
137
|
ReturnStatement: [],
|
|
135
138
|
SequenceExpression: [],
|
|
136
139
|
SpreadElement: [], // the argument of the spread operator always needs to be evaluated - argument
|
|
140
|
+
// StaticBlock: [], // will come with ES2022
|
|
137
141
|
Super: [],
|
|
138
142
|
SwitchStatement: [],
|
|
139
143
|
SwitchCase: ["test", "consequent"], // test and consequent are executed only conditionally
|
|
@@ -174,6 +178,9 @@ const EnrichedVisitorKeys = (function() {
|
|
|
174
178
|
// Check if the visitor-key exists in the available Syntax because
|
|
175
179
|
// the list of visitor-keys does not match the available Syntax.
|
|
176
180
|
if (!Syntax[type]) {
|
|
181
|
+
// Deprecated / removed:
|
|
182
|
+
// ExperimentalRestProperty
|
|
183
|
+
// ExperimentalSpreadProperty
|
|
177
184
|
return;
|
|
178
185
|
}
|
|
179
186
|
// Ignore JSX visitor-keys because they aren't used.
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const terser = require("terser");
|
|
4
3
|
const {pd} = require("pretty-data");
|
|
5
4
|
|
|
6
5
|
const ModuleName = require("../utils/ModuleName");
|
|
@@ -8,7 +7,6 @@ const {SectionType} = require("./BundleDefinition");
|
|
|
8
7
|
const escapePropertiesFile = require("../utils/escapePropertiesFile");
|
|
9
8
|
const log = require("@ui5/logger").getLogger("lbt:bundle:AutoSplitter");
|
|
10
9
|
|
|
11
|
-
const copyrightCommentsPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9/i;
|
|
12
10
|
const xmlHtmlPrePattern = /<(?:\w+:)?pre\b/;
|
|
13
11
|
|
|
14
12
|
/**
|
|
@@ -112,6 +110,7 @@ class AutoSplitter {
|
|
|
112
110
|
|
|
113
111
|
resolvedModule.sections.forEach( (section) => {
|
|
114
112
|
let currentSection;
|
|
113
|
+
let sequence;
|
|
115
114
|
switch ( section.mode ) {
|
|
116
115
|
case SectionType.Provided:
|
|
117
116
|
// 'provided' sections are no longer needed in a fully resolved module
|
|
@@ -131,16 +130,20 @@ class AutoSplitter {
|
|
|
131
130
|
});
|
|
132
131
|
break;
|
|
133
132
|
case SectionType.Preload:
|
|
133
|
+
sequence = section.modules.slice();
|
|
134
|
+
// simple version: just sort alphabetically
|
|
135
|
+
sequence.sort();
|
|
136
|
+
|
|
134
137
|
// NODE_TODO: sort by copyright:
|
|
135
|
-
// sequence = section.modules.slice();
|
|
136
138
|
// jsBuilder.beforeWriteFunctionPreloadSection((List<ModuleName>) sequence);
|
|
139
|
+
|
|
137
140
|
currentSection = {
|
|
138
141
|
mode: SectionType.Preload,
|
|
139
142
|
filters: []
|
|
140
143
|
};
|
|
141
144
|
currentSection.name = section.name;
|
|
142
145
|
currentModule.sections.push( currentSection );
|
|
143
|
-
|
|
146
|
+
sequence.forEach( (module) => {
|
|
144
147
|
const moduleSize = moduleSizes[module];
|
|
145
148
|
if ( part + 1 < numberOfParts && totalSize + moduleSize / 2 > partSize ) {
|
|
146
149
|
part++;
|
|
@@ -195,26 +198,9 @@ class AutoSplitter {
|
|
|
195
198
|
}
|
|
196
199
|
|
|
197
200
|
if ( /\.js$/.test(module) ) {
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// console.log("uglify %s start", module);
|
|
202
|
-
const result = await terser.minify({
|
|
203
|
-
[resource.name]: String(fileContent)
|
|
204
|
-
}, {
|
|
205
|
-
warnings: false, // TODO configure?
|
|
206
|
-
compress: false, // TODO configure?
|
|
207
|
-
output: {
|
|
208
|
-
comments: copyrightCommentsPattern,
|
|
209
|
-
wrap_func_args: false
|
|
210
|
-
}
|
|
211
|
-
// , outFileName: resource.name
|
|
212
|
-
// , outSourceMap: true
|
|
213
|
-
});
|
|
214
|
-
// console.log("uglify %s end", module);
|
|
215
|
-
fileContent = result.code;
|
|
216
|
-
}
|
|
217
|
-
// trace.debug("analyzed %s:%d%n", module, mw.getTargetLength());
|
|
201
|
+
// No optimize / minify step here as the input should be
|
|
202
|
+
// either already optimized or not, based on the bundle options
|
|
203
|
+
const fileContent = await resource.buffer();
|
|
218
204
|
return fileContent.length;
|
|
219
205
|
} else if ( /\.properties$/.test(module) ) {
|
|
220
206
|
/* NODE-TODO minimize *.properties
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
5
|
const path = require("path");
|
|
6
|
-
const terser = require("terser");
|
|
7
6
|
const {pd} = require("pretty-data");
|
|
8
7
|
const {parseJS, Syntax} = require("../utils/parseUtils");
|
|
9
8
|
// const MOZ_SourceMap = require("source-map");
|
|
@@ -19,7 +18,6 @@ const {SectionType} = require("./BundleDefinition");
|
|
|
19
18
|
const BundleWriter = require("./BundleWriter");
|
|
20
19
|
const log = require("@ui5/logger").getLogger("lbt:bundle:Builder");
|
|
21
20
|
|
|
22
|
-
const copyrightCommentsPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;
|
|
23
21
|
const xmlHtmlPrePattern = /<(?:\w+:)?pre\b/;
|
|
24
22
|
|
|
25
23
|
const strReplacements = {
|
|
@@ -282,12 +280,9 @@ class BundleBuilder {
|
|
|
282
280
|
}
|
|
283
281
|
|
|
284
282
|
async writeRawModule(module, resource) {
|
|
285
|
-
|
|
286
|
-
if ( /\.js$/.test(module) ) {
|
|
287
|
-
fileContent = await this.compressJS( fileContent, resource );
|
|
288
|
-
}
|
|
283
|
+
const fileContent = await resource.string();
|
|
289
284
|
this.outW.ensureNewLine();
|
|
290
|
-
this.outW.write(
|
|
285
|
+
this.outW.write(fileContent);
|
|
291
286
|
}
|
|
292
287
|
|
|
293
288
|
async writePreloadFunction(section) {
|
|
@@ -331,28 +326,6 @@ class BundleBuilder {
|
|
|
331
326
|
// this.afterWriteFunctionPreloadSection();
|
|
332
327
|
}
|
|
333
328
|
|
|
334
|
-
async compressJS(fileContent, resource) {
|
|
335
|
-
if ( this.optimize ) {
|
|
336
|
-
const result = await terser.minify({
|
|
337
|
-
[resource.name]: String(fileContent)
|
|
338
|
-
}, {
|
|
339
|
-
compress: false, // TODO configure?
|
|
340
|
-
output: {
|
|
341
|
-
comments: copyrightCommentsPattern,
|
|
342
|
-
wrap_func_args: false
|
|
343
|
-
}
|
|
344
|
-
// , outFileName: resource.name
|
|
345
|
-
// , outSourceMap: true
|
|
346
|
-
});
|
|
347
|
-
// console.log(result.map);
|
|
348
|
-
// const map = new MOZ_SourceMap.SourceMapConsumer(result.map);
|
|
349
|
-
// map.eachMapping(function (m) { console.log(m); }); // console.log(map);
|
|
350
|
-
fileContent = result.code;
|
|
351
|
-
// throw new Error();
|
|
352
|
-
}
|
|
353
|
-
return fileContent;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
329
|
beforeWriteFunctionPreloadSection(sequence) {
|
|
357
330
|
// simple version: just sort alphabetically
|
|
358
331
|
sequence.sort();
|
|
@@ -367,13 +340,12 @@ class BundleBuilder {
|
|
|
367
340
|
if ( /\.js$/.test(module) ) {
|
|
368
341
|
// console.log("Processing " + module);
|
|
369
342
|
const resource = await this.pool.findResourceWithInfo(module);
|
|
370
|
-
let
|
|
371
|
-
|
|
372
|
-
if (
|
|
343
|
+
let moduleContent = await resource.string();
|
|
344
|
+
moduleContent = rewriteDefine(this.targetBundleFormat, moduleContent, module);
|
|
345
|
+
if ( moduleContent ) {
|
|
373
346
|
outW.startSegment(module);
|
|
374
347
|
outW.ensureNewLine();
|
|
375
|
-
|
|
376
|
-
outW.write( fileContent );
|
|
348
|
+
outW.write(moduleContent);
|
|
377
349
|
outW.ensureNewLine();
|
|
378
350
|
const compressedSize = outW.endSegment();
|
|
379
351
|
log.verbose(" %s (%d,%d)", module,
|
|
@@ -409,17 +381,17 @@ class BundleBuilder {
|
|
|
409
381
|
const outW = this.outW;
|
|
410
382
|
|
|
411
383
|
if ( /\.js$/.test(module) && (info == null || !info.requiresTopLevelScope) ) {
|
|
412
|
-
const
|
|
384
|
+
const moduleContent = await resource.string();
|
|
413
385
|
outW.write(`function(){`);
|
|
414
|
-
outW.write(
|
|
386
|
+
outW.write(moduleContent);
|
|
415
387
|
this.exportGlobalNames(info);
|
|
416
388
|
outW.ensureNewLine();
|
|
417
389
|
outW.write(`}`);
|
|
418
390
|
} else if ( /\.js$/.test(module) /* implicitly: && info != null && info.requiresTopLevelScope */ ) {
|
|
419
391
|
log.warn("**** warning: module %s requires top level scope" +
|
|
420
392
|
" and can only be embedded as a string (requires 'eval')", module);
|
|
421
|
-
const
|
|
422
|
-
outW.write(
|
|
393
|
+
const moduleContent = await resource.buffer();
|
|
394
|
+
outW.write(makeStringLiteral(moduleContent));
|
|
423
395
|
} else if ( /\.html$/.test(module) ) {
|
|
424
396
|
const fileContent = await resource.buffer();
|
|
425
397
|
outW.write( makeStringLiteral( fileContent ) );
|
|
@@ -435,13 +407,13 @@ class BundleBuilder {
|
|
|
435
407
|
}
|
|
436
408
|
outW.write(makeStringLiteral(fileContent));
|
|
437
409
|
} else if ( /\.xml$/.test(module) ) {
|
|
438
|
-
let fileContent = await resource.
|
|
410
|
+
let fileContent = await resource.string();
|
|
439
411
|
if ( this.optimize ) {
|
|
440
412
|
// For XML we use the pretty data
|
|
441
413
|
// Do not minify if XML(View) contains an <*:pre> tag,
|
|
442
414
|
// because whitespace of HTML <pre> should be preserved (should only happen rarely)
|
|
443
|
-
if (!xmlHtmlPrePattern.test(fileContent
|
|
444
|
-
fileContent = pd.xmlmin(fileContent
|
|
415
|
+
if (!xmlHtmlPrePattern.test(fileContent)) {
|
|
416
|
+
fileContent = pd.xmlmin(fileContent, false);
|
|
445
417
|
}
|
|
446
418
|
}
|
|
447
419
|
outW.write( makeStringLiteral( fileContent ) );
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
const Resource = require("./Resource");
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
function extractName(path) {
|
|
5
4
|
return path.slice( "/resources/".length);
|
|
6
5
|
}
|
|
7
6
|
|
|
8
|
-
|
|
9
7
|
class LocatorResource extends Resource {
|
|
10
8
|
constructor(pool, resource) {
|
|
11
9
|
super(pool, extractName(resource.getPath()), null, resource.getStatInfo());
|
|
@@ -18,6 +18,13 @@ class Resource {
|
|
|
18
18
|
async buffer() {
|
|
19
19
|
return readFile(this.file);
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @returns {Promise<string>} String of the file content
|
|
24
|
+
*/
|
|
25
|
+
async string() {
|
|
26
|
+
return (await this.buffer()).toString();
|
|
27
|
+
}
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
module.exports = Resource;
|
|
@@ -193,17 +193,16 @@ class ResourceCollector {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
async determineResourceDetails({
|
|
196
|
-
debugResources, mergedResources, designtimeResources, supportResources
|
|
196
|
+
debugResources, mergedResources, designtimeResources, supportResources
|
|
197
197
|
}) {
|
|
198
198
|
const baseNames = new Set();
|
|
199
199
|
const debugFilter = new ResourceFilterList(debugResources);
|
|
200
200
|
const mergeFilter = new ResourceFilterList(mergedResources);
|
|
201
201
|
const designtimeFilter = new ResourceFilterList(designtimeResources);
|
|
202
202
|
const supportFilter = new ResourceFilterList(supportResources);
|
|
203
|
-
const debugBundleFilter = new ResourceFilterList(debugBundles);
|
|
204
203
|
|
|
205
204
|
const promises = [];
|
|
206
|
-
const
|
|
205
|
+
const debugResourcesInfo = [];
|
|
207
206
|
|
|
208
207
|
for (const [name, info] of this._resources.entries()) {
|
|
209
208
|
if ( debugFilter.matches(name) ) {
|
|
@@ -231,13 +230,14 @@ class ResourceCollector {
|
|
|
231
230
|
}
|
|
232
231
|
|
|
233
232
|
if ( /(?:\.js|\.view\.xml|\.control\.xml|\.fragment\.xml)$/.test(name) ) {
|
|
234
|
-
if (
|
|
235
|
-
// Only analyze non-
|
|
233
|
+
if ( !info.isDebug ) {
|
|
234
|
+
// Only analyze non-dbg files in first run
|
|
236
235
|
promises.push(
|
|
237
236
|
this.enrichWithDependencyInfo(info)
|
|
238
237
|
);
|
|
239
238
|
} else {
|
|
240
|
-
|
|
239
|
+
// Collect dbg files to be handled in a second step (see below)
|
|
240
|
+
debugResourcesInfo.push(info);
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
|
|
@@ -279,19 +279,37 @@ class ResourceCollector {
|
|
|
279
279
|
|
|
280
280
|
await Promise.all(promises);
|
|
281
281
|
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
const debugBundlePromises = [];
|
|
283
|
+
|
|
284
|
+
for (let i = debugResourcesInfo.length - 1; i >= 0; i--) {
|
|
285
|
+
const dbgInfo = debugResourcesInfo[i];
|
|
284
286
|
const nonDebugName = ResourceInfoList.getNonDebugName(dbgInfo.name);
|
|
285
287
|
const nonDbgInfo = this._resources.get(nonDebugName);
|
|
286
|
-
const newDbgInfo = new ResourceInfo(dbgInfo.name);
|
|
287
|
-
|
|
288
|
-
// First copy info of analysis from non-dbg file (included, required, condRequired, ...)
|
|
289
|
-
newDbgInfo.copyFrom(null, nonDbgInfo);
|
|
290
|
-
// Then copy over info from dbg file to properly set name, isDebug, etc.
|
|
291
|
-
newDbgInfo.copyFrom(null, dbgInfo);
|
|
292
288
|
|
|
293
|
-
|
|
289
|
+
// FIXME: "merged" property is only calculated in ResourceInfo#copyFrom
|
|
290
|
+
// Therefore using the same logic here to compute it.
|
|
291
|
+
if (!nonDbgInfo || (nonDbgInfo.included != null && nonDbgInfo.included.size > 0)) {
|
|
292
|
+
// We need to analyze the dbg resource if there is no non-dbg variant or
|
|
293
|
+
// it is a bundle because we will (usually) have different content.
|
|
294
|
+
debugBundlePromises.push(
|
|
295
|
+
this.enrichWithDependencyInfo(dbgInfo)
|
|
296
|
+
);
|
|
297
|
+
} else {
|
|
298
|
+
// If the non-dbg resource is not a bundle, we can just copy over the info and skip
|
|
299
|
+
// analyzing the dbg variant as both should have the same info.
|
|
300
|
+
|
|
301
|
+
const newDbgInfo = new ResourceInfo(dbgInfo.name);
|
|
302
|
+
|
|
303
|
+
// First copy info of analysis from non-dbg file (included, required, condRequired, ...)
|
|
304
|
+
newDbgInfo.copyFrom(null, nonDbgInfo);
|
|
305
|
+
// Then copy over info from dbg file to properly set name, isDebug, etc.
|
|
306
|
+
newDbgInfo.copyFrom(null, dbgInfo);
|
|
307
|
+
|
|
308
|
+
this._resources.set(dbgInfo.name, newDbgInfo);
|
|
309
|
+
}
|
|
294
310
|
}
|
|
311
|
+
|
|
312
|
+
await Promise.all(debugBundlePromises);
|
|
295
313
|
}
|
|
296
314
|
|
|
297
315
|
createOrphanFilters() {
|
|
@@ -89,7 +89,7 @@ const log = require("@ui5/logger").getLogger("builder:processors:bundlers:module
|
|
|
89
89
|
*
|
|
90
90
|
* @public
|
|
91
91
|
* @typedef {object} ModuleBundleOptions
|
|
92
|
-
* @property {boolean} [optimize=
|
|
92
|
+
* @property {boolean} [optimize=true] Whether the module bundle gets minified
|
|
93
93
|
* @property {boolean} [decorateBootstrapModule=false] If set to 'false', the module won't be decorated
|
|
94
94
|
* with an optimization marker
|
|
95
95
|
* @property {boolean} [addTryCatchRestartWrapper=false] Whether to wrap bootable module bundles with
|
|
@@ -109,15 +109,19 @@ const log = require("@ui5/logger").getLogger("builder:processors:bundlers:module
|
|
|
109
109
|
* @param {module:@ui5/fs.Resource[]} parameters.resources Resources
|
|
110
110
|
* @param {object} parameters.options Options
|
|
111
111
|
* @param {ModuleBundleDefinition} parameters.options.bundleDefinition Module bundle definition
|
|
112
|
-
* @param {ModuleBundleOptions} parameters.options.bundleOptions Module bundle options
|
|
112
|
+
* @param {ModuleBundleOptions} [parameters.options.bundleOptions] Module bundle options
|
|
113
113
|
* @returns {Promise<module:@ui5/fs.Resource[]>} Promise resolving with module bundle resources
|
|
114
114
|
*/
|
|
115
115
|
module.exports = function({resources, options: {bundleDefinition, bundleOptions}}) {
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
// Apply defaults without modifying the passed object
|
|
117
|
+
bundleOptions = Object.assign({}, {
|
|
118
|
+
optimize: true,
|
|
119
|
+
decorateBootstrapModule: false,
|
|
120
|
+
addTryCatchRestartWrapper: false,
|
|
121
|
+
usePredefineCalls: false,
|
|
122
|
+
numberOfParts: 1,
|
|
123
|
+
ignoreMissingModules: false
|
|
124
|
+
}, bundleOptions);
|
|
121
125
|
|
|
122
126
|
const pool = new LocatorResourcePool({
|
|
123
127
|
ignoreMissingModules: bundleOptions.ignoreMissingModules
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const terser = require("terser");
|
|
3
|
+
const Resource = require("@ui5/fs").Resource;
|
|
4
|
+
/**
|
|
5
|
+
* Preserve comments which contain:
|
|
6
|
+
* <ul>
|
|
7
|
+
* <li>copyright notice</li>
|
|
8
|
+
* <li>license terms</li>
|
|
9
|
+
* <li>"@ui5-bundle"</li>
|
|
10
|
+
* <li>"@ui5-bundle-raw-include"</li>
|
|
11
|
+
* </ul>
|
|
12
|
+
*
|
|
13
|
+
* @type {RegExp}
|
|
14
|
+
*/
|
|
15
|
+
const copyrightCommentsAndBundleCommentPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;
|
|
16
|
+
const debugFileRegex = /((?:\.view|\.fragment|\.controller|\.designtime|\.support)?\.js)$/;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Result set
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
* @typedef {object} MinifierResult
|
|
24
|
+
* @property {module:@ui5/fs.Resource} resource Minified resource
|
|
25
|
+
* @property {module:@ui5/fs.Resource} dbgResource Debug (non-minified) variant
|
|
26
|
+
* @property {module:@ui5/fs.Resource} sourceMap Source Map
|
|
27
|
+
* @memberof module:@ui5/builder.processors
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Minifies the supplied resources.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
* @alias module:@ui5/builder.processors.minifier
|
|
35
|
+
* @param {object} parameters Parameters
|
|
36
|
+
* @param {module:@ui5/fs.Resource[]} parameters.resources List of resources to be processed
|
|
37
|
+
* @returns {Promise<module:@ui5/builder.processors.MinifierResult[]>}
|
|
38
|
+
* Promise resolving with object of resource, dbgResource and sourceMap
|
|
39
|
+
*/
|
|
40
|
+
module.exports = async function({resources}) {
|
|
41
|
+
return Promise.all(resources.map(async (resource) => {
|
|
42
|
+
const dbgPath = resource.getPath().replace(debugFileRegex, "-dbg$1");
|
|
43
|
+
const dbgResource = await resource.clone();
|
|
44
|
+
dbgResource.setPath(dbgPath);
|
|
45
|
+
|
|
46
|
+
const filename = path.posix.basename(resource.getPath());
|
|
47
|
+
const code = await resource.getString();
|
|
48
|
+
try {
|
|
49
|
+
const dbgFilename = path.posix.basename(dbgPath);
|
|
50
|
+
const result = await terser.minify({
|
|
51
|
+
// Use debug-name since this will be referenced in the source map "sources"
|
|
52
|
+
[dbgFilename]: code
|
|
53
|
+
}, {
|
|
54
|
+
output: {
|
|
55
|
+
comments: copyrightCommentsAndBundleCommentPattern,
|
|
56
|
+
wrap_func_args: false
|
|
57
|
+
},
|
|
58
|
+
compress: false,
|
|
59
|
+
mangle: {
|
|
60
|
+
reserved: [
|
|
61
|
+
"jQuery",
|
|
62
|
+
"jquery",
|
|
63
|
+
"sap",
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
sourceMap: {
|
|
67
|
+
filename,
|
|
68
|
+
url: filename + ".map"
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
resource.setString(result.code);
|
|
72
|
+
const sourceMapResource = new Resource({
|
|
73
|
+
path: resource.getPath() + ".map",
|
|
74
|
+
string: result.map
|
|
75
|
+
});
|
|
76
|
+
return {resource, dbgResource, sourceMapResource};
|
|
77
|
+
} catch (err) {
|
|
78
|
+
// Note: err.filename contains the debug-name
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Minification failed with error: ${err.message} in file ${filename} ` +
|
|
81
|
+
`(line ${err.line}, col ${err.col}, pos ${err.pos})`);
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
};
|
|
@@ -66,17 +66,6 @@ const DEFAULT_SUPPORT_RESOURCES_FILTER = [
|
|
|
66
66
|
"**/*.support.js"
|
|
67
67
|
];
|
|
68
68
|
|
|
69
|
-
/**
|
|
70
|
-
* Hard coded debug bundle, to trigger separate analysis for this filename
|
|
71
|
-
* because sap-ui-core.js and sap-ui-core-dbg.js have different includes
|
|
72
|
-
*
|
|
73
|
-
* @type {string[]}
|
|
74
|
-
*/
|
|
75
|
-
const DEBUG_BUNDLES = [
|
|
76
|
-
"sap-ui-core-dbg.js",
|
|
77
|
-
"sap-ui-core-nojQuery-dbg.js"
|
|
78
|
-
];
|
|
79
|
-
|
|
80
69
|
/**
|
|
81
70
|
* Creates and adds resources.json entry (itself) to the list.
|
|
82
71
|
*
|
|
@@ -138,8 +127,7 @@ module.exports = async function({resources, dependencyResources = [], options})
|
|
|
138
127
|
debugResources: DEFAULT_DEBUG_RESOURCES_FILTER,
|
|
139
128
|
mergedResources: DEFAULT_BUNDLE_RESOURCES_FILTER,
|
|
140
129
|
designtimeResources: DEFAULT_DESIGNTIME_RESOURCES_FILTER,
|
|
141
|
-
supportResources: DEFAULT_SUPPORT_RESOURCES_FILTER
|
|
142
|
-
debugBundles: DEBUG_BUNDLES
|
|
130
|
+
supportResources: DEFAULT_SUPPORT_RESOURCES_FILTER
|
|
143
131
|
}, options);
|
|
144
132
|
|
|
145
133
|
const pool = new LocatorResourcePool();
|
|
@@ -158,12 +146,10 @@ module.exports = async function({resources, dependencyResources = [], options})
|
|
|
158
146
|
}
|
|
159
147
|
|
|
160
148
|
await collector.determineResourceDetails({
|
|
161
|
-
pool,
|
|
162
149
|
debugResources: options.debugResources,
|
|
163
150
|
mergedResources: options.mergedResources,
|
|
164
151
|
designtimeResources: options.designtimeResources,
|
|
165
|
-
supportResources: options.supportResources
|
|
166
|
-
debugBundles: options.debugBundles
|
|
152
|
+
supportResources: options.supportResources
|
|
167
153
|
});
|
|
168
154
|
|
|
169
155
|
// group resources by components and create ResourceInfoLists
|