@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.
Files changed (33) hide show
  1. package/index.js +4 -16
  2. package/jsdoc.json +0 -1
  3. package/lib/builder/BuildContext.js +17 -0
  4. package/lib/builder/ProjectBuildContext.js +9 -7
  5. package/lib/builder/builder.js +1 -2
  6. package/lib/lbt/analyzer/JSModuleAnalyzer.js +7 -0
  7. package/lib/lbt/bundle/AutoSplitter.js +10 -24
  8. package/lib/lbt/bundle/Builder.js +13 -41
  9. package/lib/lbt/resources/LocatorResource.js +0 -2
  10. package/lib/lbt/resources/Resource.js +7 -0
  11. package/lib/lbt/resources/ResourceCollector.js +33 -15
  12. package/lib/lbt/utils/parseUtils.js +1 -1
  13. package/lib/processors/bundlers/moduleBundler.js +11 -7
  14. package/lib/processors/minifier.js +84 -0
  15. package/lib/processors/resourceListCreator.js +2 -16
  16. package/lib/tasks/TaskUtil.js +9 -9
  17. package/lib/tasks/bundlers/generateBundle.js +30 -2
  18. package/lib/tasks/bundlers/generateComponentPreload.js +8 -1
  19. package/lib/tasks/bundlers/generateLibraryPreload.js +33 -4
  20. package/lib/tasks/bundlers/generateStandaloneAppBundle.js +13 -6
  21. package/lib/tasks/generateResourcesJson.js +14 -8
  22. package/lib/tasks/minify.js +31 -0
  23. package/lib/tasks/taskRepository.js +6 -2
  24. package/lib/types/application/ApplicationBuilder.js +22 -31
  25. package/lib/types/library/LibraryBuilder.js +21 -27
  26. package/lib/types/themeLibrary/ThemeLibraryBuilder.js +1 -0
  27. package/package.json +12 -12
  28. package/CHANGELOG.md +0 -726
  29. package/lib/processors/debugFileCreator.js +0 -52
  30. package/lib/processors/resourceCopier.js +0 -24
  31. package/lib/processors/uglifier.js +0 -45
  32. package/lib/tasks/createDebugFiles.js +0 -30
  33. 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/debugFileCreator')}
45
+ * @type {import('./lib/processors/minifier')}
46
46
  */
47
- debugFileCreator: "./lib/processors/debugFileCreator",
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/createDebugFiles')}
116
+ * @type {import('./lib/tasks/minify')}
125
117
  */
126
- createDebugFiles: "./lib/tasks/createDebugFiles",
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
@@ -12,7 +12,6 @@
12
12
  "./jsdoc-plugin"
13
13
  ],
14
14
  "opts": {
15
- "template": "node_modules/docdash/",
16
15
  "encoding": "utf8",
17
16
  "destination": "jsdocs/",
18
17
  "recurse": true,
@@ -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 = Object.freeze({
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
 
@@ -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.createDebugFiles = false;
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
- section.modules.forEach( (module) => {
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
- // console.log("determining compressed size for %s", module);
199
- let fileContent = await resource.buffer();
200
- if ( this.optimize ) {
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
- let fileContent = await resource.buffer();
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( fileContent );
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 code = await resource.buffer();
371
- code = rewriteDefine(this.targetBundleFormat, code, module);
372
- if ( code ) {
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
- const fileContent = await this.compressJS(code, resource);
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 compressedContent = await this.compressJS( await resource.buffer(), resource );
384
+ const moduleContent = await resource.string();
413
385
  outW.write(`function(){`);
414
- outW.write( compressedContent );
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 compressedContent = await this.compressJS( await resource.buffer(), resource );
422
- outW.write( makeStringLiteral( compressedContent ) );
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.buffer();
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.toString())) {
444
- fileContent = pd.xmlmin(fileContent.toString(), false);
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, debugBundles
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 nonBundledDebugResources = [];
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 ( (!info.isDebug || debugBundleFilter.matches(name)) ) {
235
- // Only analyze non-debug files and special debug bundles (like sap-ui-core-dbg.js)
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
- nonBundledDebugResources.push(info);
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
- for (let i = nonBundledDebugResources.length - 1; i >= 0; i--) {
283
- const dbgInfo = nonBundledDebugResources[i];
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
- this._resources.set(dbgInfo.name, newDbgInfo);
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() {
@@ -9,7 +9,7 @@ function parseJS(code, userOptions = {}) {
9
9
  // allowed options and their defaults
10
10
  const options = {
11
11
  comment: false,
12
- ecmaVersion: 2020,
12
+ ecmaVersion: 2021,
13
13
  range: false,
14
14
  sourceType: "script",
15
15
  };
@@ -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=false] If set to 'true' the module bundle gets minified
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
- // console.log("preloadBundler bundleDefinition:");
117
- // console.log(JSON.stringify(options.bundleDefinition, null, 4));
118
-
119
- // TODO 3.0: Fix defaulting behavior, align with JSDoc
120
- bundleOptions = bundleOptions || {optimize: true};
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