builder/lib/tasks/bundlers/generateStandaloneAppBundle.js

  1. import {getLogger} from "@ui5/logger";
  2. const log = getLogger("builder:tasks:bundlers:generateStandaloneAppBundle");
  3. import ReaderCollectionPrioritized from "@ui5/fs/ReaderCollectionPrioritized";
  4. import moduleBundler from "../../processors/bundlers/moduleBundler.js";
  5. import createModuleNameMapping from "./utils/createModuleNameMapping.js";
  6. function getBundleDefinition(config) {
  7. const bundleDefinition = {
  8. name: config.name,
  9. defaultFileTypes: [
  10. ".js",
  11. ".control.xml",
  12. ".fragment.html",
  13. ".fragment.json",
  14. ".fragment.xml",
  15. ".view.html",
  16. ".view.json",
  17. ".view.xml",
  18. ".properties"
  19. ],
  20. sections: []
  21. };
  22. // add raw section
  23. bundleDefinition.sections.push({
  24. // include all 'raw' modules that are needed for the UI5 loader
  25. mode: "raw",
  26. filters: config.filters,
  27. resolve: true, // dependencies for raw modules are taken from shims in .library files
  28. sort: true, // topological sort on raw modules is mandatory
  29. declareModules: false
  30. });
  31. // preload section is only relevant for sap-ui-custom.js
  32. if (config.preloadSection) {
  33. bundleDefinition.sections.push({
  34. mode: "preload",
  35. filters: [
  36. `${config.namespace || ""}/`,
  37. `${config.namespace || ""}/**/manifest.json`,
  38. `${config.namespace || ""}/changes/changes-bundle.json`,
  39. `${config.namespace || ""}/changes/flexibility-bundle.json`,
  40. `!${config.namespace || ""}/test/`,
  41. "sap/ui/core/Core.js"
  42. ],
  43. resolve: true,
  44. resolveConditional: true,
  45. renderer: true
  46. });
  47. }
  48. bundleDefinition.sections.push({
  49. mode: "require",
  50. filters: [
  51. "sap/ui/core/Core.js"
  52. ]
  53. });
  54. return bundleDefinition;
  55. }
  56. /**
  57. * @public
  58. * @module @ui5/builder/tasks/bundlers/generateStandaloneAppBundle
  59. */
  60. /* eslint "jsdoc/check-param-names": ["error", {"disableExtraPropertyReporting":true}] */
  61. /**
  62. * Task for bundling standalone applications.
  63. *
  64. * @public
  65. * @function default
  66. * @static
  67. *
  68. * @param {object} parameters Parameters
  69. * @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
  70. * @param {@ui5/fs/AbstractReader} parameters.dependencies Reader or Collection to read dependency files
  71. * @param {@ui5/project/build/helpers/TaskUtil|object} [parameters.taskUtil] TaskUtil
  72. * @param {object} parameters.options Options
  73. * @param {string} parameters.options.projectName Project name
  74. * @param {string} [parameters.options.projectNamespace] Project namespace
  75. * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
  76. */
  77. export default async function({workspace, dependencies, taskUtil, options}) {
  78. const {projectName} = options;
  79. // Backward compatibility: "namespace" option got renamed to "projectNamespace"
  80. const namespace = options.projectNamespace || options.namespace;
  81. if (!namespace) {
  82. log.warn(`Namespace of project ${projectName} is not known. Self contained bundling is currently ` +
  83. `unable to generate complete bundles for such projects.`);
  84. }
  85. const combo = new ReaderCollectionPrioritized({
  86. name: `generateStandaloneAppBundle - prioritize workspace over dependencies: ${projectName}`,
  87. readers: [workspace, dependencies]
  88. });
  89. let resourceReader = combo;
  90. if (taskUtil) {
  91. // Omit -dbg files
  92. resourceReader = await taskUtil.resourceFactory.createFilterReader({
  93. reader: combo,
  94. callback: function(resource) {
  95. return !taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant);
  96. }
  97. });
  98. }
  99. const resources = await resourceReader.byGlob("/resources/**/*.{js,json,xml,html,properties,library,js.map}");
  100. const isEvo = resources.find((resource) => {
  101. return resource.getPath() === "/resources/ui5loader.js";
  102. });
  103. let filters;
  104. if (isEvo) {
  105. filters = ["ui5loader-autoconfig.js"];
  106. } else {
  107. filters = ["jquery.sap.global.js"];
  108. }
  109. let unoptimizedModuleNameMapping;
  110. let unoptimizedResources = resources;
  111. if (taskUtil) {
  112. const unoptimizedResourceReader = await taskUtil.resourceFactory.createFilterReader({
  113. reader: combo,
  114. callback: function(resource) {
  115. // Remove any non-debug variants
  116. return !taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.HasDebugVariant);
  117. }
  118. });
  119. unoptimizedResources = await unoptimizedResourceReader
  120. .byGlob("/resources/**/*.{js,json,xml,html,properties,library,js.map}");
  121. unoptimizedModuleNameMapping = createModuleNameMapping({
  122. resources: unoptimizedResources,
  123. taskUtil
  124. });
  125. }
  126. await Promise.all([
  127. moduleBundler({
  128. resources,
  129. options: {
  130. bundleDefinition: getBundleDefinition({
  131. name: "sap-ui-custom.js",
  132. filters,
  133. namespace,
  134. preloadSection: true
  135. })
  136. }
  137. }),
  138. moduleBundler({
  139. resources: unoptimizedResources,
  140. options: {
  141. bundleDefinition: getBundleDefinition({
  142. name: "sap-ui-custom-dbg.js",
  143. filters,
  144. namespace
  145. }),
  146. bundleOptions: {
  147. optimize: false
  148. },
  149. moduleNameMapping: unoptimizedModuleNameMapping
  150. }
  151. })
  152. ]).then((results) => {
  153. const bundles = Array.prototype.concat.apply([], results);
  154. return Promise.all(bundles.map(({bundle, sourceMap}) => {
  155. if (taskUtil) {
  156. taskUtil.setTag(bundle, taskUtil.STANDARD_TAGS.IsBundle);
  157. if (sourceMap) {
  158. // Clear tag that might have been set by the minify task, in cases where
  159. // the bundle name is identical to a source file
  160. taskUtil.clearTag(sourceMap, taskUtil.STANDARD_TAGS.OmitFromBuildResult);
  161. }
  162. }
  163. const writes = [workspace.write(bundle)];
  164. if (sourceMap) {
  165. writes.push(workspace.write(sourceMap));
  166. }
  167. return Promise.all(writes);
  168. }));
  169. });
  170. }