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.

618 lines
17 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
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
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. // default settings
  49. base = defaults.base,
  50. clean = defaults.paths.clean,
  51. output = defaults.paths.output,
  52. source = defaults.paths.source,
  53. // derived
  54. config,
  55. package,
  56. assetPaths,
  57. componentGlob,
  58. // temporary
  59. folder
  60. ;
  61. /*******************************
  62. Read Settings
  63. *******************************/
  64. try {
  65. // try to load json
  66. var
  67. config = require('./semantic.json'),
  68. package = require('./package.json')
  69. ;
  70. }
  71. catch(error) {
  72. var config = false;
  73. }
  74. /*******************************
  75. Values Derived From Config
  76. *******************************/
  77. var
  78. getConfigValues = function() {
  79. // shorthand
  80. base = config.base;
  81. clean = config.paths.clean;
  82. output = config.paths.output;
  83. source = config.paths.source;
  84. // create glob for matching filenames from selected components
  85. componentGlob = (typeof config.components == 'object')
  86. ? (config.components.length > 1)
  87. ? '{' + config.components.join(',') + '}'
  88. : config.components[0]
  89. : ''
  90. ;
  91. // relative paths
  92. assetPaths = {
  93. uncompressed : path.relative(output.uncompressed, output.themes),
  94. compressed : path.relative(output.compressed, output.themes),
  95. packaged : path.relative(output.packaged, output.themes)
  96. };
  97. // add base to values
  98. for(var folder in source) {
  99. if(source.hasOwnProperty(folder)) {
  100. source[folder] = base + source[folder];
  101. }
  102. }
  103. for(folder in output) {
  104. if(output.hasOwnProperty(folder)) {
  105. output[folder] = base + output[folder];
  106. }
  107. }
  108. clean = base + clean;
  109. }
  110. ;
  111. getConfigValues();
  112. /*******************************
  113. Tasks
  114. *******************************/
  115. gulp.task('default', false, [
  116. 'check install'
  117. ]);
  118. gulp.task('watch', 'Watch for site/theme changes (Default Task)', function () {
  119. console.clear();
  120. console.log('Watching source files');
  121. // watching changes in style
  122. gulp
  123. .watch([
  124. source.config,
  125. source.definitions + '**/*.less',
  126. source.site + '**/*.{overrides,variables}',
  127. source.themes + '**/*.{overrides,variables}'
  128. ], function(file) {
  129. var
  130. srcPath,
  131. stream,
  132. compressedStream,
  133. uncompressedStream
  134. ;
  135. gulp.src(file.path)
  136. .pipe(print(log.modified))
  137. ;
  138. // recompile only definition file
  139. srcPath = util.replaceExtension(file.path, '.less');
  140. srcPath = srcPath.replace(source.themes, source.definitions);
  141. srcPath = srcPath.replace(source.site, source.definitions);
  142. // get relative asset path (path returns wrong path? hardcoded)
  143. // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
  144. assetPaths.source = '../../themes';
  145. if( fs.existsSync(srcPath) ) {
  146. // unified css stream
  147. stream = gulp.src(srcPath)
  148. .pipe(plumber())
  149. //.pipe(sourcemaps.init())
  150. .pipe(less(settings.less))
  151. .pipe(replace(comments.variables.in, comments.variables.out))
  152. .pipe(replace(comments.large.in, comments.large.out))
  153. .pipe(replace(comments.small.in, comments.small.out))
  154. .pipe(replace(comments.tiny.in, comments.tiny.out))
  155. .pipe(autoprefixer(settings.prefix))
  156. ;
  157. // use 2 concurrent streams from same source
  158. uncompressedStream = stream.pipe(clone());
  159. compressedStream = stream.pipe(clone());
  160. uncompressedStream
  161. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  162. //.pipe(sourcemaps.write('/', settings.sourcemap))
  163. .pipe(header(banner, settings.header))
  164. .pipe(gulp.dest(output.uncompressed))
  165. .pipe(print(log.created))
  166. .on('end', function() {
  167. gulp.start('package uncompressed css');
  168. })
  169. ;
  170. compressedStream = stream
  171. .pipe(clone())
  172. .pipe(replace(assetPaths.source, assetPaths.compressed))
  173. .pipe(minifyCSS(settings.minify))
  174. .pipe(rename(settings.rename.minCSS))
  175. //.pipe(sourcemaps.write('/', settings.sourcemap))
  176. .pipe(header(banner, settings.header))
  177. .pipe(gulp.dest(output.compressed))
  178. .pipe(print(log.created))
  179. .on('end', function() {
  180. gulp.start('package compressed css');
  181. })
  182. ;
  183. }
  184. else {
  185. console.error('Definition file not found', path);
  186. }
  187. })
  188. ;
  189. // watch changes in assets
  190. gulp
  191. .watch([
  192. source.themes + '**/assets/**'
  193. ], function(file) {
  194. // copy assets
  195. gulp.src(file.path, { base: source.themes })
  196. .pipe(gulp.dest(output.themes))
  197. .pipe(print(log.created))
  198. ;
  199. })
  200. ;
  201. // watch changes in js
  202. gulp
  203. .watch([
  204. source.definitions + '**/*.js'
  205. ], function(file) {
  206. gulp.src(file.path)
  207. .pipe(gulp.dest(output.uncompressed))
  208. .pipe(print(log.created))
  209. .pipe(sourcemaps.init())
  210. .pipe(uglify(settings.uglify))
  211. .pipe(rename(settings.rename.minJS))
  212. .pipe(gulp.dest(output.compressed))
  213. .pipe(print(log.created))
  214. .on('end', function() {
  215. gulp.start('package compressed js');
  216. gulp.start('package uncompressed js');
  217. })
  218. ;
  219. })
  220. ;
  221. });
  222. // Builds all files
  223. gulp.task('build', 'Builds all files from source', function(callback) {
  224. var
  225. stream,
  226. compressedStream,
  227. uncompressedStream
  228. ;
  229. console.info('Building Semantic');
  230. // get relative asset path (path returns wrong path?)
  231. // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
  232. assetPaths.source = '../../themes'; // hardcoded
  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 + '**/' + componentGlob + '!(*.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 + '**/' + componentGlob + '!(*.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 + '**/' + componentGlob + '!(*.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 + '**/' + componentGlob + '!(*.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 || !fs.existsSync('./src/theme.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. console.clear();
  355. gulp
  356. .src('gulpfile.js')
  357. .pipe(prompt.prompt(questions.setup, function(answers) {
  358. var
  359. siteVariable = /@siteFolder .*\'(.*)/mg,
  360. templates = {
  361. themeConfig : './src/theme.config.example',
  362. jsonConfig : './semantic.json.example',
  363. site : './src/_site'
  364. },
  365. siteDestination = answers.site || './src/site',
  366. themeDestination = './src/',
  367. pathToSite = path.relative(path.resolve('./src'), path.resolve('./' + siteDestination)),
  368. sitePathReplace = "@siteFolder : '" + pathToSite + "/';",
  369. configExists = fs.existsSync('./semantic.json'),
  370. themeConfigExists = fs.existsSync('./src/theme.config'),
  371. siteExists = fs.existsSync(siteDestination),
  372. jsonSource = (configExists)
  373. ? './semantic.json'
  374. : './semantic.json.example',
  375. json = {
  376. paths: {
  377. source: {},
  378. output: {}
  379. }
  380. }
  381. ;
  382. // exit if config exists and user specifies no overwrite
  383. if(answers.overwrite !== undefined && answers.overwrite == 'no') {
  384. return;
  385. }
  386. console.clear();
  387. console.log('Installing');
  388. console.log('------------------------------');
  389. // create site files
  390. if(siteExists) {
  391. console.info('Site folder exists, merging files (no overwrite)', siteDestination);
  392. }
  393. else {
  394. console.info('Creating site theme folder', siteDestination);
  395. }
  396. // copy recursively without overwrite
  397. wrench.copyDirSyncRecursive(templates.site, siteDestination, settings.wrench.recursive);
  398. // adjust less variable for site folder location
  399. console.info('Adjusting @siteFolder', defaults.paths.source.config, themeDestination);
  400. if(themeConfigExists) {
  401. gulp.src('./src/theme.config')
  402. .pipe(replace(siteVariable, sitePathReplace))
  403. .pipe(gulp.dest(themeDestination))
  404. ;
  405. }
  406. else {
  407. console.info('Creating src/theme.config (LESS config)');
  408. gulp.src(templates.themeConfig)
  409. .pipe(rename({ extname : '' }))
  410. .pipe(replace(siteVariable, sitePathReplace))
  411. .pipe(gulp.dest(themeDestination))
  412. ;
  413. }
  414. // determine semantic.json config
  415. if(answers.components) {
  416. json.components = answers.components;
  417. }
  418. if(answers.dist) {
  419. answers.dist = answers.dist;
  420. json.paths.output = {
  421. packaged : answers.dist + '/',
  422. uncompressed : answers.dist + '/components/',
  423. compressed : answers.dist + '/components/',
  424. themes : answers.dist + '/themes/'
  425. };
  426. }
  427. if(answers.site) {
  428. json.paths.source.site = answers.site + '/';
  429. }
  430. if(answers.packaged) {
  431. json.paths.output.packaged = answers.packaged + '/';
  432. }
  433. if(answers.compressed) {
  434. json.paths.output.compressed = answers.compressed + '/';
  435. }
  436. if(answers.uncompressed) {
  437. json.paths.output.uncompressed = answers.uncompressed + '/';
  438. }
  439. // write semantic.json
  440. if(configExists) {
  441. console.info('Extending semantic.json (Gulp config)');
  442. gulp.src(jsonSource)
  443. .pipe(plumber())
  444. .pipe(rename(settings.rename.json))
  445. .pipe(jeditor(json))
  446. .pipe(gulp.dest('./'))
  447. ;
  448. }
  449. else {
  450. console.info('Creating semantic.json (Gulp config)');
  451. gulp.src(jsonSource)
  452. .pipe(plumber())
  453. .pipe(rename({ extname : '' }))
  454. .pipe(jeditor(json))
  455. .pipe(gulp.dest('./'))
  456. ;
  457. }
  458. console.log('');
  459. console.log('');
  460. }))
  461. .pipe(prompt.prompt(questions.cleanup, function(answers) {
  462. if(answers.cleanup == 'yes') {
  463. del([
  464. './src/theme.config.example',
  465. './semantic.json.example',
  466. './src/_site'
  467. ]);
  468. }
  469. if(answers.build == 'yes') {
  470. config = require('./semantic.json');
  471. getConfigValues();
  472. gulp.start('build');
  473. }
  474. }))
  475. ;
  476. });
  477. /*--------------
  478. Maintainer
  479. ---------------*/
  480. /* Moves watched files to static site generator output */
  481. gulp.task('serve-docs', false, function () {
  482. config = require('./tasks/maintainer/docs-output.json');
  483. getConfigValues();
  484. // copy source files
  485. gulp
  486. .watch([
  487. 'src/**/*.*'
  488. ], function(file) {
  489. console.clear();
  490. return gulp.src(file.path, { base: 'src/' })
  491. .pipe(gulp.dest(output.less))
  492. .pipe(print(log.created))
  493. ;
  494. })
  495. ;
  496. gulp.start('watch');
  497. });
  498. /* Builds files to docs source */
  499. gulp.task('build-docs', false, function () {
  500. console.clear();
  501. // pushes to docpad files
  502. config = require('./tasks/maintainer/docs-output.json');
  503. getConfigValues();
  504. gulp.start('build');
  505. // copy source
  506. gulp.src('src/**/*.*')
  507. .pipe(gulp.dest(output.less))
  508. .pipe(print(log.created))
  509. ;
  510. });
  511. /* Bump Version */
  512. gulp.task('bump', false, function () {
  513. // bump package.json
  514. // bump composer.json
  515. });
  516. /* Release */
  517. gulp.task('release', false, function() {
  518. });
  519. gulp.task('release all', false, function () {
  520. // Create SCSS Version
  521. // Create RTL Release
  522. // Create Node Release
  523. // Create Bower Releases
  524. });