css.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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(buildUncompressed, packUncompressed),
  126. gulp.series(buildCompressed, packCompressed)
  127. )(callback);
  128. }
  129. function rtlAndNormal(src, callback) {
  130. if (callback === undefined) {
  131. callback = src;
  132. src = config.paths.source.definitions + '/**/' + config.globs.components + '.less';
  133. }
  134. const rtl = (callback) => buildCSS(src, 'rtl', config, {}, callback);
  135. rtl.displayName = "CSS Right-To-Left";
  136. const css = (callback) => buildCSS(src, 'default', config, {}, callback);
  137. css.displayName = "CSS";
  138. if (config.rtl === true || config.rtl === 'Yes') {
  139. rtl(callback);
  140. } else if (config.rtl === 'both') {
  141. gulp.series(rtl, css)(callback);
  142. } else {
  143. css(callback);
  144. }
  145. }
  146. function docs(src, callback) {
  147. if (callback === undefined) {
  148. callback = src;
  149. src = config.paths.source.definitions + '/**/' + config.globs.components + '.less';
  150. }
  151. const func = (callback) => buildCSS(src, 'docs', config, {}, callback);
  152. func.displayName = "CSS Docs";
  153. func(callback);
  154. }
  155. // Default tasks
  156. module.exports = rtlAndNormal;
  157. // We keep the changed files in an array to call build with all of them at the same time
  158. let timeout, files = [];
  159. /**
  160. * Watch changes in CSS files and call the correct build pipe
  161. * @param type
  162. * @param config
  163. */
  164. module.exports.watch = function (type, config) {
  165. const method = type === 'docs' ? docs : rtlAndNormal;
  166. // Watch theme.config file
  167. gulp.watch([
  168. normalize(config.paths.source.config),
  169. normalize(config.paths.source.site + '/**/site.variables'),
  170. normalize(config.paths.source.themes + '/**/site.variables')
  171. ])
  172. .on('all', function () {
  173. // Clear timeout and reset files
  174. timeout && clearTimeout(timeout);
  175. files = [];
  176. return gulp.series(method)();
  177. });
  178. // Watch any less / overrides / variables files
  179. gulp.watch([
  180. normalize(config.paths.source.definitions + '/**/*.less'),
  181. normalize(config.paths.source.site + '/**/*.{overrides,variables}'),
  182. normalize(config.paths.source.themes + '/**/*.{overrides,variables}')
  183. ])
  184. .on('all', function (event, path) {
  185. // We don't handle deleted files yet
  186. if (event === 'unlink' || event === 'unlinkDir') {
  187. return;
  188. }
  189. // Clear timeout
  190. timeout && clearTimeout(timeout);
  191. // Determine which LESS file has to be recompiled
  192. let lessPath;
  193. if(path.indexOf('site.variables') !== -1) {
  194. return;
  195. } else if (path.indexOf(config.paths.source.themes) !== -1) {
  196. console.log('Change detected in packaged theme');
  197. lessPath = replaceExt(path, '.less');
  198. lessPath = lessPath.replace(tasks.regExp.theme, config.paths.source.definitions);
  199. } else if (path.indexOf(config.paths.source.site) !== -1) {
  200. console.log('Change detected in site theme');
  201. lessPath = replaceExt(path, '.less');
  202. lessPath = lessPath.replace(config.paths.source.site, config.paths.source.definitions);
  203. } else {
  204. console.log('Change detected in definition');
  205. lessPath = path;
  206. }
  207. // Add file to internal changed files array
  208. if (!files.includes(lessPath)) {
  209. files.push(lessPath);
  210. }
  211. // Update timeout
  212. timeout = setTimeout(() => {
  213. // Copy files to build in another array
  214. const buildFiles = [...files];
  215. // Call method
  216. gulp.series((callback) => method(buildFiles, callback))();
  217. // Reset internal changed files array
  218. files = [];
  219. }, 1000);
  220. });
  221. };
  222. // Expose build css method
  223. module.exports.buildCSS = buildCSS;