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.

571 lines
15 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*
  2. All configurable options are defined inside build.config
  3. Please adjust this to your site's settings
  4. */
  5. /*******************************
  6. Set-up
  7. *******************************/
  8. var
  9. gulp = require('gulp-help')(require('gulp')),
  10. // node components & oddballs
  11. del = require('del'),
  12. fs = require('fs'),
  13. path = require('path'),
  14. console = require('better-console'),
  15. wrench = require('wrench'),
  16. // gulp dependencies
  17. autoprefixer = require('gulp-autoprefixer'),
  18. clone = require('gulp-clone'),
  19. concat = require('gulp-concat'),
  20. concatCSS = require('gulp-concat-css'),
  21. copy = require('gulp-copy'),
  22. debug = require('gulp-debug'),
  23. flatten = require('gulp-flatten'),
  24. header = require('gulp-header'),
  25. jeditor = require('gulp-json-editor'),
  26. karma = require('gulp-karma'),
  27. less = require('gulp-less'),
  28. minifyCSS = require('gulp-minify-css'),
  29. notify = require('gulp-notify'),
  30. plumber = require('gulp-plumber'),
  31. print = require('gulp-print'),
  32. prompt = require('gulp-prompt'),
  33. rename = require('gulp-rename'),
  34. replace = require('gulp-replace'),
  35. sourcemaps = require('gulp-sourcemaps'),
  36. uglify = require('gulp-uglify'),
  37. util = require('gulp-util'),
  38. watch = require('gulp-watch'),
  39. // config
  40. banner = require('./tasks/banner'),
  41. comments = require('./tasks/comments'),
  42. defaults = require('./tasks/defaults'),
  43. log = require('./tasks/log'),
  44. questions = require('./tasks/questions'),
  45. settings = require('./tasks/gulp-settings'),
  46. // local
  47. overwrite = true,
  48. // derived
  49. config,
  50. package,
  51. compiledFilter,
  52. assetPaths,
  53. // temporary
  54. folder
  55. ;
  56. /*******************************
  57. Read Settings
  58. *******************************/
  59. try {
  60. // settings
  61. var
  62. config = require('./semantic.json'),
  63. package = require('./package.json')
  64. ;
  65. }
  66. catch(error) {
  67. var config = false;
  68. }
  69. /*******************************
  70. Values Derived From Config
  71. *******************************/
  72. if(config) {
  73. var
  74. // shorthand
  75. base = config.base,
  76. clean = config.paths.clean,
  77. output = config.paths.output,
  78. source = config.paths.source
  79. ;
  80. // create glob for matching filenames from selected components
  81. compiledFilter = (typeof config.components == 'object')
  82. ? (config.components.length > 1)
  83. ? '{' + config.components.join(',') + '}'
  84. : config.components[0]
  85. : ''
  86. ;
  87. // relative paths
  88. assetPaths = {
  89. uncompressed : path.relative(output.uncompressed, output.themes),
  90. compressed : path.relative(output.compressed, output.themes),
  91. packaged : path.relative(output.packaged, output.themes)
  92. };
  93. // paths with base
  94. for(folder in source) {
  95. if(source.hasOwnProperty(folder)) {
  96. source[folder] = base + source[folder];
  97. }
  98. }
  99. for(folder in output) {
  100. if(output.hasOwnProperty(folder)) {
  101. output[folder] = base + output[folder];
  102. }
  103. }
  104. clean = base + clean;
  105. }
  106. else {
  107. // use default values
  108. var
  109. base = defaults.base,
  110. clean = defaults.paths.clean,
  111. output = defaults.paths.output,
  112. source = defaults.paths.source
  113. ;
  114. }
  115. /*******************************
  116. Tasks
  117. *******************************/
  118. gulp.task('default', false, [
  119. 'check install'
  120. ]);
  121. gulp.task('watch', 'Watch for site/theme changes (Default Task)', function () {
  122. console.clear();
  123. console.log('Watching source files');
  124. // watching changes in style
  125. gulp
  126. .watch([
  127. source.config,
  128. source.definitions + '**/*.less',
  129. source.site + '**/*.{overrides,variables}',
  130. source.themes + '**/*.{overrides,variables}'
  131. ], function(file) {
  132. var
  133. srcPath,
  134. stream,
  135. compressedStream,
  136. uncompressedStream
  137. ;
  138. gulp.src(file.path)
  139. .pipe(print(log.modified))
  140. ;
  141. // recompile only definition file
  142. srcPath = util.replaceExtension(file.path, '.less');
  143. srcPath = srcPath.replace(source.themes, source.definitions);
  144. srcPath = srcPath.replace(source.site, source.definitions);
  145. // get relative asset path (path returns wrong path? hardcoded)
  146. //assetPaths.source = path.relative(srcPath, source.themes);
  147. assetPaths.source = '../../themes';
  148. if( fs.existsSync(srcPath) ) {
  149. // unified css stream
  150. stream = gulp.src(srcPath)
  151. .pipe(plumber())
  152. //.pipe(sourcemaps.init())
  153. .pipe(less(settings.less))
  154. .pipe(replace(comments.variables.in, comments.variables.out))
  155. .pipe(replace(comments.large.in, comments.large.out))
  156. .pipe(replace(comments.small.in, comments.small.out))
  157. .pipe(replace(comments.tiny.in, comments.tiny.out))
  158. .pipe(autoprefixer(settings.prefix))
  159. ;
  160. // use 2 concurrent streams from same source
  161. uncompressedStream = stream.pipe(clone());
  162. compressedStream = stream.pipe(clone());
  163. uncompressedStream
  164. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  165. //.pipe(sourcemaps.write('/', settings.sourcemap))
  166. .pipe(header(banner, settings.header))
  167. .pipe(gulp.dest(output.uncompressed))
  168. .pipe(print(log.created))
  169. .on('end', function() {
  170. gulp.start('package uncompressed css');
  171. })
  172. ;
  173. compressedStream = stream
  174. .pipe(clone())
  175. .pipe(replace(assetPaths.source, assetPaths.compressed))
  176. .pipe(minifyCSS(settings.minify))
  177. .pipe(rename(settings.rename.minCSS))
  178. //.pipe(sourcemaps.write('/', settings.sourcemap))
  179. .pipe(header(banner, settings.header))
  180. .pipe(gulp.dest(output.compressed))
  181. .pipe(print(log.created))
  182. .on('end', function() {
  183. gulp.start('package compressed css');
  184. })
  185. ;
  186. }
  187. else {
  188. console.error('Definition file not found', path);
  189. }
  190. })
  191. ;
  192. // watch changes in assets
  193. gulp
  194. .watch([
  195. source.themes + '**/assets/**'
  196. ], function(file) {
  197. // copy assets
  198. gulp.src(file.path, { base: source.themes })
  199. .pipe(gulp.dest(output.themes))
  200. .pipe(print(log.created))
  201. ;
  202. })
  203. ;
  204. // watch changes in js
  205. gulp
  206. .watch([
  207. source.definitions + '**/*.js'
  208. ], function(file) {
  209. gulp.src(file.path)
  210. .pipe(gulp.dest(output.uncompressed))
  211. .pipe(print(log.created))
  212. .pipe(sourcemaps.init())
  213. .pipe(uglify(settings.uglify))
  214. .pipe(rename(settings.rename.minJS))
  215. .pipe(gulp.dest(output.compressed))
  216. .pipe(print(log.created))
  217. .on('end', function() {
  218. gulp.start('package compressed js');
  219. gulp.start('package uncompressed js');
  220. })
  221. ;
  222. })
  223. ;
  224. });
  225. // Builds all files
  226. gulp.task('build', 'Builds all files from source', function(callback) {
  227. var
  228. stream,
  229. compressedStream,
  230. uncompressedStream
  231. ;
  232. console.info('Building Semantic');
  233. // copy assets
  234. gulp.src(source.themes + '**/assets/**')
  235. .pipe(gulp.dest(output.themes))
  236. ;
  237. // javascript stream
  238. gulp.src(source.definitions + '**/*.js')
  239. .pipe(flatten())
  240. .pipe(gulp.dest(output.uncompressed))
  241. .pipe(print(log.created))
  242. // .pipe(sourcemaps.init())
  243. .pipe(uglify(settings.uglify))
  244. .pipe(rename(settings.rename.minJS))
  245. .pipe(header(banner, settings.header))
  246. .pipe(gulp.dest(output.compressed))
  247. .pipe(print(log.created))
  248. .on('end', function() {
  249. gulp.start('package compressed js');
  250. gulp.start('package uncompressed js');
  251. })
  252. ;
  253. // unified css stream
  254. stream = gulp.src(source.definitions + '**/*.less')
  255. .pipe(plumber())
  256. //.pipe(sourcemaps.init())
  257. .pipe(less(settings.less))
  258. .pipe(flatten())
  259. .pipe(replace(comments.variables.in, comments.variables.out))
  260. .pipe(replace(comments.large.in, comments.large.out))
  261. .pipe(replace(comments.small.in, comments.small.out))
  262. .pipe(replace(comments.tiny.in, comments.tiny.out))
  263. .pipe(autoprefixer(settings.prefix))
  264. ;
  265. // use 2 concurrent streams from same source
  266. uncompressedStream = stream.pipe(clone());
  267. compressedStream = stream.pipe(clone());
  268. uncompressedStream
  269. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  270. //.pipe(sourcemaps.write('/', settings.sourcemap))
  271. .pipe(header(banner, settings.header))
  272. .pipe(gulp.dest(output.uncompressed))
  273. .pipe(print(log.created))
  274. .on('end', function() {
  275. gulp.start('package uncompressed css');
  276. })
  277. ;
  278. compressedStream = stream
  279. .pipe(clone())
  280. .pipe(replace(assetPaths.source, assetPaths.compressed))
  281. .pipe(minifyCSS(settings.minify))
  282. .pipe(rename(settings.rename.minCSS))
  283. //.pipe(sourcemaps.write('/', settings.sourcemap))
  284. .pipe(header(banner, settings.header))
  285. .pipe(gulp.dest(output.compressed))
  286. .pipe(print(log.created))
  287. .on('end', function() {
  288. gulp.start('package compressed css');
  289. })
  290. ;
  291. });
  292. // cleans distribution files
  293. gulp.task('clean', 'Clean dist folder', function(callback) {
  294. return del([clean], settings.del, callback);
  295. });
  296. gulp.task('version', 'Displays current version of Semantic', function(callback) {
  297. console.log('Semantic UI ' + package.version);
  298. });
  299. /*--------------
  300. Internal
  301. ---------------*/
  302. gulp.task('package uncompressed css', false, function() {
  303. return gulp.src(output.uncompressed + '**/' + compiledFilter + '!(*.min|*.map).css')
  304. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  305. .pipe(concatCSS('semantic.css'))
  306. .pipe(gulp.dest(output.packaged))
  307. .pipe(print(log.created))
  308. ;
  309. });
  310. gulp.task('package compressed css', false, function() {
  311. return gulp.src(output.uncompressed + '**/' + compiledFilter + '!(*.min|*.map).css')
  312. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  313. .pipe(concatCSS('semantic.min.css'))
  314. .pipe(minifyCSS(settings.minify))
  315. .pipe(header(banner, settings.header))
  316. .pipe(gulp.dest(output.packaged))
  317. .pipe(print(log.created))
  318. ;
  319. });
  320. gulp.task('package uncompressed js', false, function() {
  321. return gulp.src(output.uncompressed + '**/' + compiledFilter + '!(*.min|*.map).js')
  322. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  323. .pipe(concat('semantic.js'))
  324. .pipe(header(banner, settings.header))
  325. .pipe(gulp.dest(output.packaged))
  326. .pipe(print(log.created))
  327. ;
  328. });
  329. gulp.task('package compressed js', false, function() {
  330. return gulp.src(output.uncompressed + '**/' + compiledFilter + '!(*.min|*.map).js')
  331. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  332. .pipe(concat('semantic.min.js'))
  333. .pipe(uglify(settings.uglify))
  334. .pipe(header(banner, settings.header))
  335. .pipe(gulp.dest(output.packaged))
  336. .pipe(print(log.created))
  337. ;
  338. });
  339. /*--------------
  340. Config
  341. ---------------*/
  342. gulp.task('check install', false, function () {
  343. setTimeout(function() {
  344. if( !config ) {
  345. console.log('No semantic.json file found. Starting install...');
  346. gulp.start('install');
  347. }
  348. else {
  349. gulp.start('watch');
  350. }
  351. }, 50);
  352. });
  353. gulp.task('install', 'Set-up project for first time', function () {
  354. gulp
  355. .src(defaults.paths.source.config)
  356. .pipe(prompt.prompt(questions.setup, function(answers) {
  357. var
  358. siteVariable = /@siteFolder .*\'(.*)\'/mg,
  359. templates = {
  360. theme : './src/theme.config.example',
  361. json : './semantic.json.example',
  362. site : './src/_site'
  363. },
  364. siteDestination = answers.site || './src/site',
  365. themeDestination = './src/theme.config',
  366. pathToSite = path.relative(path.resolve('./src'), path.resolve(siteDestination)),
  367. configExists = fs.existsSync('./semantic.json'),
  368. themeConfigExists = fs.existsSync('./src/theme.config'),
  369. siteExists = fs.existsSync(siteDestination),
  370. jsonSource = (configExists)
  371. ? './semantic.json'
  372. : './semantic.json.example',
  373. json = {
  374. paths: {
  375. source: {},
  376. output: {}
  377. }
  378. }
  379. ;
  380. // exit if config exists and user specifies no overwrite
  381. if(answers.overwrite !== undefined && answers.overwrite == 'no') {
  382. return;
  383. }
  384. console.clear();
  385. console.log('Installing');
  386. console.log('------------------------------');
  387. // create site files
  388. if(siteExists) {
  389. console.info('Site folder exists, merging files (no overwrite)', siteDestination);
  390. }
  391. else {
  392. console.info('Creating site theme folder', siteDestination);
  393. }
  394. // copy recursively without overwrite
  395. wrench.copyDirSyncRecursive(templates.site, siteDestination, settings.wrench.recursive);
  396. if(themeConfigExists) {
  397. console.error('./src/theme.config already exists, skipping');
  398. }
  399. else {
  400. console.info('Creating src/theme.config (LESS config)');
  401. gulp.src(templates.theme)
  402. .pipe(gulp.dest(themeDestination))
  403. ;
  404. }
  405. // adjust less variable for site folder location
  406. console.info('Adjusting @siteFolder', pathToSite);
  407. gulp.src(themeDestination)
  408. .pipe(replace(siteVariable, pathToSite))
  409. .pipe(gulp.dest(themeDestination))
  410. ;
  411. // determine semantic.json config
  412. if(answers.components) {
  413. json.components = answers.components;
  414. }
  415. if(answers.dist) {
  416. answers.dist = answers.dist;
  417. json.paths.output = {
  418. packaged : answers.dist + '/',
  419. uncompressed : answers.dist + '/components/',
  420. compressed : answers.dist + '/components/',
  421. themes : answers.dist + '/themes/'
  422. };
  423. }
  424. if(answers.site) {
  425. json.paths.source.site = answers.site + '/';
  426. }
  427. if(answers.packaged) {
  428. json.paths.output.packaged = answers.packaged + '/';
  429. }
  430. if(answers.compressed) {
  431. json.paths.output.compressed = answers.compressed + '/';
  432. }
  433. if(answers.uncompressed) {
  434. json.paths.output.uncompressed = answers.uncompressed + '/';
  435. }
  436. // write semantic.json
  437. if(configExists) {
  438. console.info('Extending semantic.json (Gulp config)');
  439. gulp.src(jsonSource)
  440. .pipe(plumber())
  441. .pipe(rename(settings.rename.json))
  442. .pipe(jeditor(json))
  443. .pipe(gulp.dest('./'))
  444. ;
  445. }
  446. else {
  447. console.info('Creating semantic.json (Gulp config)');
  448. gulp.src(jsonSource)
  449. .pipe(plumber())
  450. .pipe(rename({ extname : '' }))
  451. .pipe(jeditor(json))
  452. .pipe(gulp.dest('./'))
  453. ;
  454. }
  455. console.log('');
  456. console.log('');
  457. }))
  458. .pipe(prompt.prompt(questions.cleanup, function(answers) {
  459. if(answers.cleanup == 'yes') {
  460. del([
  461. './src/theme.config.example',
  462. './semantic.json.example',
  463. './src/_site'
  464. ]);
  465. }
  466. if(answers.build == 'yes') {
  467. gulp.start('build');
  468. }
  469. }))
  470. ;
  471. });
  472. /*--------------
  473. Maintainer
  474. ---------------*/
  475. /* Bump Version */
  476. gulp.task('bump', false, function () {
  477. // Create RTL Release
  478. // Create Node Release
  479. });
  480. /* Release */
  481. gulp.task('release', false, function () {
  482. // Create SCSS Version
  483. // Create RTL Release
  484. // Create Node Release
  485. // Create Bower Releases
  486. });