@ui5/builder 2.11.1 → 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 +11 -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 +19 -41
- package/lib/lbt/bundle/Resolver.js +1 -1
- 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/manifestCreator.js +1 -1
- package/lib/processors/minifier.js +84 -0
- package/lib/processors/resourceListCreator.js +2 -16
- package/lib/tasks/TaskUtil.js +11 -9
- package/lib/tasks/buildThemes.js +6 -2
- package/lib/tasks/bundlers/generateBundle.js +30 -2
- package/lib/tasks/bundlers/generateComponentPreload.js +8 -1
- package/lib/tasks/bundlers/generateLibraryPreload.js +78 -49
- 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/replaceVersion.js +1 -1
- package/lib/tasks/taskRepository.js +6 -2
- package/lib/types/application/ApplicationBuilder.js +22 -31
- package/lib/types/library/LibraryBuilder.js +22 -28
- package/lib/types/themeLibrary/ThemeLibraryBuilder.js +2 -1
- package/package.json +13 -13
- package/CHANGELOG.md +0 -711
- 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;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
const ResourceTagCollection = require("@ui5/fs").ResourceTagCollection;
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// Note: When adding standard tags, always update the public documentation in TaskUtil
|
|
4
|
+
// (Type "module:@ui5/builder.tasks.TaskUtil~StandardBuildTags")
|
|
5
|
+
const STANDARD_TAGS = {
|
|
4
6
|
OmitFromBuildResult: "ui5:OmitFromBuildResult",
|
|
5
|
-
IsBundle: "ui5:IsBundle"
|
|
6
|
-
}
|
|
7
|
+
IsBundle: "ui5:IsBundle",
|
|
8
|
+
};
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Build context of a single project. Always part of an overall
|
|
@@ -13,8 +15,8 @@ const STANDARD_TAGS = Object.freeze({
|
|
|
13
15
|
* @memberof module:@ui5/builder.builder
|
|
14
16
|
*/
|
|
15
17
|
class ProjectBuildContext {
|
|
16
|
-
constructor({buildContext, project, resources}) {
|
|
17
|
-
if (!buildContext || !project || !resources) {
|
|
18
|
+
constructor({buildContext, globalTags, project, resources}) {
|
|
19
|
+
if (!buildContext || !globalTags || !project || !resources) {
|
|
18
20
|
throw new Error(`One or more mandatory parameters are missing`);
|
|
19
21
|
}
|
|
20
22
|
this._buildContext = buildContext;
|
|
@@ -24,10 +26,12 @@ class ProjectBuildContext {
|
|
|
24
26
|
cleanup: []
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
this.STANDARD_TAGS = STANDARD_TAGS;
|
|
29
|
+
this.STANDARD_TAGS = Object.assign({}, STANDARD_TAGS, globalTags);
|
|
30
|
+
Object.freeze(this.STANDARD_TAGS);
|
|
28
31
|
|
|
29
32
|
this._resourceTagCollection = new ResourceTagCollection({
|
|
30
|
-
allowedTags: Object.values(this.STANDARD_TAGS)
|
|
33
|
+
allowedTags: Object.values(this.STANDARD_TAGS),
|
|
34
|
+
superCollection: this._buildContext.getResourceTagCollection()
|
|
31
35
|
});
|
|
32
36
|
}
|
|
33
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
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// for consistency of write calls, we generally allow template literals
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const path = require("path");
|
|
6
6
|
const {pd} = require("pretty-data");
|
|
7
7
|
const {parseJS, Syntax} = require("../utils/parseUtils");
|
|
8
8
|
// const MOZ_SourceMap = require("source-map");
|
|
@@ -18,7 +18,6 @@ const {SectionType} = require("./BundleDefinition");
|
|
|
18
18
|
const BundleWriter = require("./BundleWriter");
|
|
19
19
|
const log = require("@ui5/logger").getLogger("lbt:bundle:Builder");
|
|
20
20
|
|
|
21
|
-
const copyrightCommentsPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;
|
|
22
21
|
const xmlHtmlPrePattern = /<(?:\w+:)?pre\b/;
|
|
23
22
|
|
|
24
23
|
const strReplacements = {
|
|
@@ -281,12 +280,9 @@ class BundleBuilder {
|
|
|
281
280
|
}
|
|
282
281
|
|
|
283
282
|
async writeRawModule(module, resource) {
|
|
284
|
-
|
|
285
|
-
if ( /\.js$/.test(module) ) {
|
|
286
|
-
fileContent = await this.compressJS( fileContent, resource );
|
|
287
|
-
}
|
|
283
|
+
const fileContent = await resource.string();
|
|
288
284
|
this.outW.ensureNewLine();
|
|
289
|
-
this.outW.write(
|
|
285
|
+
this.outW.write(fileContent);
|
|
290
286
|
}
|
|
291
287
|
|
|
292
288
|
async writePreloadFunction(section) {
|
|
@@ -330,28 +326,6 @@ class BundleBuilder {
|
|
|
330
326
|
// this.afterWriteFunctionPreloadSection();
|
|
331
327
|
}
|
|
332
328
|
|
|
333
|
-
async compressJS(fileContent, resource) {
|
|
334
|
-
if ( this.optimize ) {
|
|
335
|
-
const result = await terser.minify({
|
|
336
|
-
[resource.name]: String(fileContent)
|
|
337
|
-
}, {
|
|
338
|
-
compress: false, // TODO configure?
|
|
339
|
-
output: {
|
|
340
|
-
comments: copyrightCommentsPattern,
|
|
341
|
-
wrap_func_args: false
|
|
342
|
-
}
|
|
343
|
-
// , outFileName: resource.name
|
|
344
|
-
// , outSourceMap: true
|
|
345
|
-
});
|
|
346
|
-
// console.log(result.map);
|
|
347
|
-
// const map = new MOZ_SourceMap.SourceMapConsumer(result.map);
|
|
348
|
-
// map.eachMapping(function (m) { console.log(m); }); // console.log(map);
|
|
349
|
-
fileContent = result.code;
|
|
350
|
-
// throw new Error();
|
|
351
|
-
}
|
|
352
|
-
return fileContent;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
329
|
beforeWriteFunctionPreloadSection(sequence) {
|
|
356
330
|
// simple version: just sort alphabetically
|
|
357
331
|
sequence.sort();
|
|
@@ -366,13 +340,12 @@ class BundleBuilder {
|
|
|
366
340
|
if ( /\.js$/.test(module) ) {
|
|
367
341
|
// console.log("Processing " + module);
|
|
368
342
|
const resource = await this.pool.findResourceWithInfo(module);
|
|
369
|
-
let
|
|
370
|
-
|
|
371
|
-
if (
|
|
343
|
+
let moduleContent = await resource.string();
|
|
344
|
+
moduleContent = rewriteDefine(this.targetBundleFormat, moduleContent, module);
|
|
345
|
+
if ( moduleContent ) {
|
|
372
346
|
outW.startSegment(module);
|
|
373
347
|
outW.ensureNewLine();
|
|
374
|
-
|
|
375
|
-
outW.write( fileContent );
|
|
348
|
+
outW.write(moduleContent);
|
|
376
349
|
outW.ensureNewLine();
|
|
377
350
|
const compressedSize = outW.endSegment();
|
|
378
351
|
log.verbose(" %s (%d,%d)", module,
|
|
@@ -408,17 +381,17 @@ class BundleBuilder {
|
|
|
408
381
|
const outW = this.outW;
|
|
409
382
|
|
|
410
383
|
if ( /\.js$/.test(module) && (info == null || !info.requiresTopLevelScope) ) {
|
|
411
|
-
const
|
|
384
|
+
const moduleContent = await resource.string();
|
|
412
385
|
outW.write(`function(){`);
|
|
413
|
-
outW.write(
|
|
386
|
+
outW.write(moduleContent);
|
|
414
387
|
this.exportGlobalNames(info);
|
|
415
388
|
outW.ensureNewLine();
|
|
416
389
|
outW.write(`}`);
|
|
417
390
|
} else if ( /\.js$/.test(module) /* implicitly: && info != null && info.requiresTopLevelScope */ ) {
|
|
418
391
|
log.warn("**** warning: module %s requires top level scope" +
|
|
419
392
|
" and can only be embedded as a string (requires 'eval')", module);
|
|
420
|
-
const
|
|
421
|
-
outW.write(
|
|
393
|
+
const moduleContent = await resource.buffer();
|
|
394
|
+
outW.write(makeStringLiteral(moduleContent));
|
|
422
395
|
} else if ( /\.html$/.test(module) ) {
|
|
423
396
|
const fileContent = await resource.buffer();
|
|
424
397
|
outW.write( makeStringLiteral( fileContent ) );
|
|
@@ -434,13 +407,13 @@ class BundleBuilder {
|
|
|
434
407
|
}
|
|
435
408
|
outW.write(makeStringLiteral(fileContent));
|
|
436
409
|
} else if ( /\.xml$/.test(module) ) {
|
|
437
|
-
let fileContent = await resource.
|
|
410
|
+
let fileContent = await resource.string();
|
|
438
411
|
if ( this.optimize ) {
|
|
439
412
|
// For XML we use the pretty data
|
|
440
413
|
// Do not minify if XML(View) contains an <*:pre> tag,
|
|
441
414
|
// because whitespace of HTML <pre> should be preserved (should only happen rarely)
|
|
442
|
-
if (!xmlHtmlPrePattern.test(fileContent
|
|
443
|
-
fileContent = pd.xmlmin(fileContent
|
|
415
|
+
if (!xmlHtmlPrePattern.test(fileContent)) {
|
|
416
|
+
fileContent = pd.xmlmin(fileContent, false);
|
|
444
417
|
}
|
|
445
418
|
}
|
|
446
419
|
outW.write( makeStringLiteral( fileContent ) );
|
|
@@ -486,6 +459,11 @@ class BundleBuilder {
|
|
|
486
459
|
if (!section.name) {
|
|
487
460
|
throw new Error(`A 'bundleInfo' section is missing the mandatory 'name' property.` );
|
|
488
461
|
}
|
|
462
|
+
if (!path.extname(section.name)) {
|
|
463
|
+
log.warn(`bundleInfo section name '${section.name}' is missing a file extension. ` +
|
|
464
|
+
`The info might not work as expected. ` +
|
|
465
|
+
`The name must match the bundle filename (incl. extension such as '.js')`);
|
|
466
|
+
}
|
|
489
467
|
this.outW.write(`"${section.name}":[${section.modules.map(makeStringLiteral).join(",")}]`);
|
|
490
468
|
});
|
|
491
469
|
this.outW.writeln();
|
|
@@ -289,7 +289,7 @@ class BundleResolver {
|
|
|
289
289
|
|
|
290
290
|
return collectModulesForSection(section).
|
|
291
291
|
then( (modules) => {
|
|
292
|
-
if ( section.mode == SectionType.Raw && section.sort ) {
|
|
292
|
+
if ( section.mode == SectionType.Raw && section.sort !== false ) {
|
|
293
293
|
// sort the modules in topological order
|
|
294
294
|
return topologicalSort(pool, modules).then( (modules) => {
|
|
295
295
|
log.verbose(" resolved modules (sorted): %s", modules);
|
|
@@ -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
|
|
@@ -237,7 +237,7 @@ async function createManifest(libraryResource, libBundle, descriptorVersion, _in
|
|
|
237
237
|
if ( library.getDocumentation() ) {
|
|
238
238
|
let desc = library.getDocumentation();
|
|
239
239
|
// remove all tags
|
|
240
|
-
desc = desc.replace(
|
|
240
|
+
desc = desc.replace(/\s+/g, " ").replace(/<\/?[a-zA-Z][a-zA-Z0-9_$.]*(\s[^>]*)>/g, "");
|
|
241
241
|
// extract summary (first sentence)
|
|
242
242
|
const m = /^([\w\W]+?[.;!?])[^a-zA-Z0-9_$]/.exec(desc);
|
|
243
243
|
return m ? m[1] : desc;
|
|
@@ -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
|
+
};
|