@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.
Files changed (37) 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 +11 -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 +19 -41
  9. package/lib/lbt/bundle/Resolver.js +1 -1
  10. package/lib/lbt/resources/LocatorResource.js +0 -2
  11. package/lib/lbt/resources/Resource.js +7 -0
  12. package/lib/lbt/resources/ResourceCollector.js +33 -15
  13. package/lib/lbt/utils/parseUtils.js +1 -1
  14. package/lib/processors/bundlers/moduleBundler.js +11 -7
  15. package/lib/processors/manifestCreator.js +1 -1
  16. package/lib/processors/minifier.js +84 -0
  17. package/lib/processors/resourceListCreator.js +2 -16
  18. package/lib/tasks/TaskUtil.js +11 -9
  19. package/lib/tasks/buildThemes.js +6 -2
  20. package/lib/tasks/bundlers/generateBundle.js +30 -2
  21. package/lib/tasks/bundlers/generateComponentPreload.js +8 -1
  22. package/lib/tasks/bundlers/generateLibraryPreload.js +78 -49
  23. package/lib/tasks/bundlers/generateStandaloneAppBundle.js +13 -6
  24. package/lib/tasks/generateResourcesJson.js +14 -8
  25. package/lib/tasks/minify.js +31 -0
  26. package/lib/tasks/replaceVersion.js +1 -1
  27. package/lib/tasks/taskRepository.js +6 -2
  28. package/lib/types/application/ApplicationBuilder.js +22 -31
  29. package/lib/types/library/LibraryBuilder.js +22 -28
  30. package/lib/types/themeLibrary/ThemeLibraryBuilder.js +2 -1
  31. package/package.json +13 -13
  32. package/CHANGELOG.md +0 -711
  33. package/lib/processors/debugFileCreator.js +0 -52
  34. package/lib/processors/resourceCopier.js +0 -24
  35. package/lib/processors/uglifier.js +0 -45
  36. package/lib/tasks/createDebugFiles.js +0 -30
  37. 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;
@@ -1,9 +1,11 @@
1
1
  const ResourceTagCollection = require("@ui5/fs").ResourceTagCollection;
2
2
 
3
- const STANDARD_TAGS = Object.freeze({
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
 
@@ -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
@@ -2,7 +2,7 @@
2
2
  // for consistency of write calls, we generally allow template literals
3
3
  "use strict";
4
4
 
5
- const terser = require("terser");
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
- let fileContent = await resource.buffer();
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( fileContent );
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 code = await resource.buffer();
370
- code = rewriteDefine(this.targetBundleFormat, code, module);
371
- if ( code ) {
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
- const fileContent = await this.compressJS(code, resource);
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 compressedContent = await this.compressJS( await resource.buffer(), resource );
384
+ const moduleContent = await resource.string();
412
385
  outW.write(`function(){`);
413
- outW.write( compressedContent );
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 compressedContent = await this.compressJS( await resource.buffer(), resource );
421
- outW.write( makeStringLiteral( compressedContent ) );
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.buffer();
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.toString())) {
443
- fileContent = pd.xmlmin(fileContent.toString(), false);
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, 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
@@ -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(/\\s+/g, " ").replace(/<\/?[a-zA-Z][a-zA-Z0-9_$.]*(\s[^>]*)>/g, "");
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
+ };