build-examples.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /**
  2. * build-examples.js
  3. * --------
  4. * Searches for each example's `js/app.es6` file.
  5. * Creates a new watchify instance for each `app.es6`.
  6. * Changes to Uppy's source will trigger rebundling.
  7. *
  8. * Run as:
  9. *
  10. * build-examples.js # to build all examples one-off
  11. * build-examples.js watch # to keep rebuilding examples with an internal watchify
  12. * build-examples.js <path> # to build just one example app.es6
  13. * build-examples.js <path> <path> # to build just one example app.es6 to a specific location
  14. *
  15. * Note:
  16. * Since each example is dependent on Uppy's source,
  17. * changing one source file causes the 'file changed'
  18. * notification to fire multiple times. To stop this,
  19. * files are added to a 'muted' array that is checked
  20. * before announcing a changed file. It's removed from
  21. * the array when it has been bundled.
  22. */
  23. var createStream = require('fs').createWriteStream;
  24. var glob = require('multi-glob').glob;
  25. var chalk = require('chalk');
  26. var path = require('path');
  27. var mkdirp = require('mkdirp');
  28. var notifier = require('node-notifier');
  29. var babelify = require('babelify');
  30. var browserify = require('browserify');
  31. var watchify = require('watchify');
  32. var webRoot = __dirname;
  33. var uppyRoot = path.dirname(webRoot);
  34. var srcPattern = webRoot + '/src/examples/**/js/app.es6';
  35. var dstPattern = webRoot + '/public/examples/**/js/app.js';
  36. var watchifyEnabled = process.argv[2] === 'watch';
  37. var browserifyPlugins = [];
  38. if (watchifyEnabled) {
  39. browserifyPlugins.push(watchify);
  40. }
  41. // Instead of 'watch', build-examples.js can also take a path as cli argument.
  42. // In this case we'll only bundle the specified path/pattern
  43. if (!watchifyEnabled && process.argv[2]) {
  44. srcPattern = process.argv[2];
  45. if (process.argv[3]) {
  46. dstPattern = process.argv[3];
  47. }
  48. }
  49. // Find each app.es6 file with glob.
  50. glob(srcPattern, function(err, files) {
  51. if (err) throw new Error(err);
  52. if (watchifyEnabled) {
  53. console.log('--> Watching examples..');
  54. }
  55. var muted = [];
  56. // Create a new watchify instance for each file.
  57. files.forEach(function(file) {
  58. var browseFy = browserify(file, {
  59. cache : {},
  60. packageCache: {},
  61. plugin : browserifyPlugins
  62. })
  63. // Aliasing for using `require('uppy')`, etc.
  64. browseFy
  65. .require(uppyRoot + '/src/index.js', { expose: 'uppy' })
  66. .require(uppyRoot + '/src/core/index.js', { expose: 'uppy/core' })
  67. .require(uppyRoot + '/src/plugins/index.js', { expose: 'uppy/plugins' })
  68. .transform(babelify);
  69. // Listeners for changes, errors, and completion.
  70. browseFy
  71. .on('update', bundle)
  72. .on('error', onError)
  73. .on('file', function(file, id, parent) {
  74. // When file completes, unmute it.
  75. muted = muted.filter(function(mutedId) {
  76. return id !== mutedId;
  77. });
  78. });
  79. // Call bundle() manually to start watch processes.
  80. bundle();
  81. /**
  82. * Creates bundle and writes it to static and public folders.
  83. * Changes to
  84. * @param {[type]} ids [description]
  85. * @return {[type]} [description]
  86. */
  87. function bundle(ids) {
  88. ids = ids || [];
  89. ids.forEach(function(id) {
  90. if (!isMuted(id, muted)) {
  91. console.info(chalk.cyan('change:'), id);
  92. muted.push(id);
  93. }
  94. });
  95. var exampleName = path.basename(path.dirname(path.dirname(file)));
  96. var output = dstPattern.replace('**', exampleName);
  97. var parentDir = path.dirname(output);
  98. mkdirp.sync(parentDir);
  99. console.info(chalk.green('✓ building:'), chalk.green(path.relative(process.cwd(), file)));
  100. var bundle = browseFy.bundle()
  101. .on('error', onError)
  102. bundle.pipe(createStream(output));
  103. }
  104. });
  105. });
  106. /**
  107. * Logs to console and shows desktop notification on error.
  108. * Calls `this.emit(end)` to stop bundling.
  109. * @param {object} err Error object
  110. */
  111. function onError(err) {
  112. console.error(chalk.red('✗ error:'), chalk.red(err.message));
  113. notifier.notify({
  114. 'title': 'Build failed:',
  115. 'message': err.message
  116. })
  117. this.emit('end');
  118. }
  119. /**
  120. * Checks if a file has been added to muted list.
  121. * This stops single changes from logging multiple times.
  122. * @param {string} id Name of changed file
  123. * @param {Array<string>} list Muted files array
  124. * @return {Boolean} True if file is muted
  125. */
  126. function isMuted(id, list) {
  127. return list.reduce(function(prev, curr) {
  128. return prev || (curr === id);
  129. }, false);
  130. }