builder/lib/processors/themeBuilder.js

  1. const log = require("@ui5/logger").getLogger("builder:processors:themeBuilder");
  2. const path = require("path");
  3. const less = require("less-openui5");
  4. const Resource = require("@ui5/fs").Resource;
  5. const libraryMatchPattern = /^\/resources\/(.*)\/themes\/[^/]*\/library\.source\.less$/i;
  6. /**
  7. * Builds a library theme
  8. *
  9. * @public
  10. * @memberof module:@ui5/builder.processors
  11. */
  12. class ThemeBuilder {
  13. /**
  14. * Constructor
  15. *
  16. * @public
  17. * @param {fs|module:@ui5/fs.fsInterface} fs Node fs or custom
  18. * [fs interface]{@link module:resources/module:@ui5/fs.fsInterface}
  19. */
  20. constructor({fs}) {
  21. this.builder = new less.Builder({fs});
  22. }
  23. /**
  24. * Starts the theme build
  25. *
  26. * @public
  27. * @param {module:@ui5/fs.Resource[]} resources Library files
  28. * @param {object} [options] Build options
  29. * @param {boolean} [options.compress=false] Compress build output (CSS / JSON)
  30. * @param {boolean} [options.cssVariables=false] Generates the CSS variables
  31. * (css-variables.css, css-variables.source.less) and the skeleton for a theme
  32. * (library-skeleton.css, [library-skeleton-RTL.css])
  33. * @returns {Promise<module:@ui5/fs.Resource[]>} Resolving with array of created files
  34. */
  35. build(resources, {compress = false, cssVariables = false} = {}) {
  36. const files = [];
  37. const compile = (resource) => {
  38. log.verbose("Compiling %s", resource.getPath());
  39. let libraryName;
  40. const libraryMatch = libraryMatchPattern.exec(resource.getPath());
  41. if (libraryMatch) {
  42. libraryName = libraryMatch[1].replace(/\//g, ".");
  43. }
  44. return this.builder.build({
  45. lessInputPath: resource.getPath(),
  46. library: {
  47. name: libraryName
  48. },
  49. compiler: {
  50. compress
  51. },
  52. cssVariables
  53. }).then((result) => {
  54. const themeDir = path.dirname(resource.getPath());
  55. const libCss = new Resource({
  56. path: themeDir + "/library.css",
  57. string: result.css
  58. });
  59. const libCssRtl = new Resource({
  60. path: themeDir + "/library-RTL.css",
  61. string: result.cssRtl
  62. });
  63. const libParams = new Resource({
  64. path: themeDir + "/library-parameters.json",
  65. string: JSON.stringify(result.variables, null, compress ? null : "\t")
  66. });
  67. files.push(libCss, libCssRtl, libParams);
  68. if (cssVariables) {
  69. const libCssVarsSource = new Resource({
  70. path: themeDir + "/css_variables.source.less",
  71. string: result.cssVariablesSource
  72. });
  73. const libCssVars = new Resource({
  74. path: themeDir + "/css_variables.css",
  75. string: result.cssVariables
  76. });
  77. const libCssSkel = new Resource({
  78. path: themeDir + "/library_skeleton.css",
  79. string: result.cssSkeleton
  80. });
  81. const libCssSkelRtl = new Resource({
  82. path: themeDir + "/library_skeleton-RTL.css",
  83. string: result.cssSkeletonRtl
  84. });
  85. files.push(libCssVarsSource, libCssVars, libCssSkel, libCssSkelRtl);
  86. }
  87. }, (err) => {
  88. log.error(`Error while compiling ${resource.getPath()}: ${err.message}`);
  89. throw err;
  90. });
  91. };
  92. return Promise.all(resources.map(compile)).then(() => {
  93. return files;
  94. });
  95. }
  96. /**
  97. * Clears all cached build results
  98. *
  99. * @public
  100. * Use this method to prevent high memory consumption when building many themes within the same process.
  101. */
  102. clearCache() {
  103. this.builder.clearCache();
  104. }
  105. }
  106. /**
  107. *
  108. * @public
  109. * @typedef {object} ThemeBuilderOptions
  110. * @property {boolean} [compress=false] Compress build output (CSS / JSON)
  111. * @property {boolean} [cssVariables=false] Generates the CSS variables
  112. * (css-variables.css, css-variables.source.less) and the skeleton for a theme
  113. * (library-skeleton.css, [library-skeleton-RTL.css])
  114. */
  115. /**
  116. * Builds a library theme.
  117. *
  118. * @public
  119. * @alias module:@ui5/builder.processors.themeBuilder
  120. * @param {object} parameters Parameters
  121. * @param {module:@ui5/fs.Resource[]} parameters.resources List of <code>library.source.less</code>
  122. * resources to be processed
  123. * @param {fs|module:@ui5/fs.fsInterface} parameters.fs Node fs or custom
  124. * [fs interface]{@link module:resources/module:@ui5/fs.fsInterface}
  125. * @param {ThemeBuilderOptions} [parameters.options] Options
  126. * @returns {Promise<module:@ui5/fs.Resource[]>} Promise resolving with theme resources
  127. */
  128. module.exports = async function({
  129. resources,
  130. fs,
  131. options = {}
  132. }) {
  133. const {compress, cssVariables} = /** @type {ThemeBuilderOptions} */ (options);
  134. const themeBuilder = new ThemeBuilder({fs});
  135. return themeBuilder.build(resources, {
  136. compress,
  137. cssVariables
  138. }).then((files) => {
  139. themeBuilder.clearCache();
  140. return files;
  141. });
  142. };
  143. module.exports.ThemeBuilder = ThemeBuilder;