You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
8.3 KiB

  1. /*******************************
  2. * Build Task
  3. *******************************/
  4. const
  5. gulp = require('gulp'),
  6. // node dependencies
  7. console = require('better-console'),
  8. // gulp dependencies
  9. autoprefixer = require('gulp-autoprefixer'),
  10. chmod = require('gulp-chmod'),
  11. concatCSS = require('gulp-concat-css'),
  12. dedupe = require('gulp-dedupe'),
  13. flatten = require('gulp-flatten'),
  14. gulpif = require('gulp-if'),
  15. header = require('gulp-header'),
  16. less = require('gulp-less'),
  17. minifyCSS = require('gulp-clean-css'),
  18. normalize = require('normalize-path'),
  19. plumber = require('gulp-plumber'),
  20. print = require('gulp-print').default,
  21. rename = require('gulp-rename'),
  22. replace = require('gulp-replace'),
  23. replaceExt = require('replace-ext'),
  24. rtlcss = require('gulp-rtlcss'),
  25. // config
  26. config = require('./../config/user'),
  27. docsConfig = require('./../config/docs'),
  28. tasks = require('../config/tasks'),
  29. install = require('../config/project/install'),
  30. // shorthand
  31. globs = config.globs,
  32. assets = config.paths.assets,
  33. banner = tasks.banner,
  34. filenames = tasks.filenames,
  35. comments = tasks.regExp.comments,
  36. log = tasks.log,
  37. settings = tasks.settings
  38. ;
  39. /**
  40. * Builds the css
  41. * @param src
  42. * @param type
  43. * @param compress
  44. * @param config
  45. * @param opts
  46. * @return {*}
  47. */
  48. function build(src, type, compress, config, opts) {
  49. let fileExtension;
  50. if (type === 'rtl' && compress) {
  51. fileExtension = settings.rename.rtlMinCSS;
  52. } else if (type === 'rtl') {
  53. fileExtension = settings.rename.rtlCSS;
  54. } else if (compress) {
  55. fileExtension = settings.rename.minCSS;
  56. }
  57. return gulp.src(src, opts)
  58. .pipe(plumber(settings.plumber.less))
  59. .pipe(less(settings.less))
  60. .pipe(autoprefixer(settings.prefix))
  61. .pipe(gulpif(type === 'rtl', rtlcss()))
  62. .pipe(replace(comments.variables.in, comments.variables.out))
  63. .pipe(replace(comments.license.in, comments.license.out))
  64. .pipe(replace(comments.large.in, comments.large.out))
  65. .pipe(replace(comments.small.in, comments.small.out))
  66. .pipe(replace(comments.tiny.in, comments.tiny.out))
  67. .pipe(flatten())
  68. .pipe(replace(config.paths.assets.source,
  69. compress ? config.paths.assets.compressed : config.paths.assets.uncompressed))
  70. .pipe(gulpif(compress, minifyCSS(settings.minify)))
  71. .pipe(gulpif(fileExtension, rename(fileExtension)))
  72. .pipe(gulpif(config.hasPermissions, chmod(config.parsedPermissions)))
  73. .pipe(gulp.dest(compress ? config.paths.output.compressed : config.paths.output.uncompressed))
  74. .pipe(print(log.created))
  75. ;
  76. }
  77. /**
  78. * Packages the css files in dist
  79. * @param {string} type - type of the css processing (none, rtl, docs)
  80. * @param {boolean} compress - should the output be compressed
  81. */
  82. function pack(type, compress) {
  83. const output = type === 'docs' ? docsConfig.paths.output : config.paths.output;
  84. const ignoredGlobs = type === 'rtl' ? globs.ignoredRTL + '.rtl.css' : globs.ignored + '.css';
  85. let concatenatedCSS;
  86. if (type === 'rtl') {
  87. concatenatedCSS = compress ? filenames.concatenatedMinifiedRTLCSS : filenames.concatenatedRTLCSS;
  88. } else {
  89. concatenatedCSS = compress ? filenames.concatenatedMinifiedCSS : filenames.concatenatedCSS;
  90. }
  91. return gulp.src(output.uncompressed + '/**/' + globs.components + ignoredGlobs)
  92. .pipe(plumber())
  93. .pipe(dedupe())
  94. .pipe(replace(assets.uncompressed, assets.packaged))
  95. .pipe(concatCSS(concatenatedCSS, settings.concatCSS))
  96. .pipe(gulpif(config.hasPermissions, chmod(config.parsedPermissions)))
  97. .pipe(gulpif(compress, minifyCSS(settings.concatMinify)))
  98. .pipe(header(banner, settings.header))
  99. .pipe(gulp.dest(output.packaged))
  100. .pipe(print(log.created))
  101. ;
  102. }
  103. function buildCSS(src, type, config, opts, callback) {
  104. if (!install.isSetup()) {
  105. console.error('Cannot build CSS files. Run "gulp install" to set-up Semantic');
  106. callback();
  107. return;
  108. }
  109. if (callback === undefined) {
  110. callback = opts;
  111. opts = config;
  112. config = type;
  113. type = src;
  114. src = config.paths.source.definitions + '/**/' + config.globs.components + '.less';
  115. }
  116. const buildUncompressed = () => build(src, type, false, config, opts);
  117. buildUncompressed.displayName = 'Building uncompressed CSS';
  118. const buildCompressed = () => build(src, type, true, config, opts);
  119. buildCompressed.displayName = 'Building compressed CSS';
  120. const packUncompressed = () => pack(type, false);
  121. packUncompressed.displayName = 'Packing uncompressed CSS';
  122. const packCompressed = () => pack(type, true);
  123. packCompressed.displayName = 'Packing compressed CSS';
  124. gulp.parallel(
  125. gulp.series(
  126. buildUncompressed,
  127. gulp.parallel(packUncompressed, packCompressed)
  128. ),
  129. gulp.series(buildCompressed)
  130. )(callback);
  131. }
  132. function rtlAndNormal(src, callback) {
  133. if (callback === undefined) {
  134. callback = src;
  135. src = config.paths.source.definitions + '/**/' + config.globs.components + '.less';
  136. }
  137. const rtl = (callback) => buildCSS(src, 'rtl', config, {}, callback);
  138. rtl.displayName = "CSS Right-To-Left";
  139. const css = (callback) => buildCSS(src, 'default', config, {}, callback);
  140. css.displayName = "CSS";
  141. if (config.rtl === true || config.rtl === 'Yes') {
  142. rtl(callback);
  143. } else if (config.rtl === 'both') {
  144. gulp.series(rtl, css)(callback);
  145. } else {
  146. css(callback);
  147. }
  148. }
  149. function docs(src, callback) {
  150. if (callback === undefined) {
  151. callback = src;
  152. src = config.paths.source.definitions + '/**/' + config.globs.components + '.less';
  153. }
  154. const func = (callback) => buildCSS(src, 'docs', config, {}, callback);
  155. func.displayName = "CSS Docs";
  156. func(callback);
  157. }
  158. // Default tasks
  159. module.exports = rtlAndNormal;
  160. // We keep the changed files in an array to call build with all of them at the same time
  161. let timeout, files = [];
  162. /**
  163. * Watch changes in CSS files and call the correct build pipe
  164. * @param type
  165. * @param config
  166. */
  167. module.exports.watch = function (type, config) {
  168. const method = type === 'docs' ? docs : rtlAndNormal;
  169. // Watch theme.config file
  170. gulp.watch([
  171. normalize(config.paths.source.config),
  172. normalize(config.paths.source.site + '/**/site.variables'),
  173. normalize(config.paths.source.themes + '/**/site.variables')
  174. ])
  175. .on('all', function () {
  176. // Clear timeout and reset files
  177. timeout && clearTimeout(timeout);
  178. files = [];
  179. return gulp.series(method)();
  180. });
  181. // Watch any less / overrides / variables files
  182. gulp.watch([
  183. normalize(config.paths.source.definitions + '/**/*.less'),
  184. normalize(config.paths.source.site + '/**/*.{overrides,variables}'),
  185. normalize(config.paths.source.themes + '/**/*.{overrides,variables}')
  186. ])
  187. .on('all', function (event, path) {
  188. // We don't handle deleted files yet
  189. if (event === 'unlink' || event === 'unlinkDir') {
  190. return;
  191. }
  192. // Clear timeout
  193. timeout && clearTimeout(timeout);
  194. // Determine which LESS file has to be recompiled
  195. let lessPath;
  196. if(path.indexOf('site.variables') !== -1) {
  197. return;
  198. } else if (path.indexOf(config.paths.source.themes) !== -1) {
  199. console.log('Change detected in packaged theme');
  200. lessPath = replaceExt(path, '.less');
  201. lessPath = lessPath.replace(tasks.regExp.theme, config.paths.source.definitions);
  202. } else if (path.indexOf(config.paths.source.site) !== -1) {
  203. console.log('Change detected in site theme');
  204. lessPath = replaceExt(path, '.less');
  205. lessPath = lessPath.replace(config.paths.source.site, config.paths.source.definitions);
  206. } else {
  207. console.log('Change detected in definition');
  208. lessPath = path;
  209. }
  210. // Add file to internal changed files array
  211. if (!files.includes(lessPath)) {
  212. files.push(lessPath);
  213. }
  214. // Update timeout
  215. timeout = setTimeout(() => {
  216. // Copy files to build in another array
  217. const buildFiles = [...files];
  218. // Call method
  219. gulp.series((callback) => method(buildFiles, callback))();
  220. // Reset internal changed files array
  221. files = [];
  222. }, 1000);
  223. });
  224. };
  225. // Expose build css method
  226. module.exports.buildCSS = buildCSS;