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.

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