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