build-examples.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. // consider enabling this
  30. // var rollupify = require('rollupify')
  31. var babelify = require('babelify')
  32. var browserify = require('browserify')
  33. var watchify = require('watchify')
  34. var webRoot = __dirname
  35. var uppyRoot = path.dirname(webRoot)
  36. var srcPattern = webRoot + '/src/examples/**/app.es6'
  37. var dstPattern = webRoot + '/public/examples/**/app.js'
  38. var watchifyEnabled = process.argv[2] === 'watch'
  39. var browserifyPlugins = []
  40. if (watchifyEnabled) {
  41. browserifyPlugins.push(watchify)
  42. }
  43. // Instead of 'watch', build-examples.js can also take a path as cli argument.
  44. // In this case we'll only bundle the specified path/pattern
  45. if (!watchifyEnabled && process.argv[2]) {
  46. srcPattern = process.argv[2]
  47. if (process.argv[3]) {
  48. dstPattern = process.argv[3]
  49. }
  50. }
  51. // Find each app.es6 file with glob.
  52. glob(srcPattern, function (err, files) {
  53. if (err) throw new Error(err)
  54. if (watchifyEnabled) {
  55. console.log('--> Watching examples..')
  56. }
  57. var muted = []
  58. // Create a new watchify instance for each file.
  59. files.forEach(function (file) {
  60. var browseFy = browserify(file, {
  61. cache: {},
  62. packageCache: {},
  63. debug: true,
  64. plugin: browserifyPlugins
  65. })
  66. // Aliasing for using `require('uppy')`, etc.
  67. browseFy
  68. .require(uppyRoot + '/src/index.js', { expose: 'uppy' })
  69. .require(uppyRoot + '/src/core/index.js', { expose: 'uppy/core' })
  70. .require(uppyRoot + '/src/plugins/index.js', { expose: 'uppy/plugins' })
  71. .require(uppyRoot + '/src/locales/index.js', { expose: 'uppy/locales' })
  72. // .transform(rollupify)
  73. .transform(babelify)
  74. // Listeners for changes, errors, and completion.
  75. browseFy
  76. .on('update', bundle)
  77. .on('error', onError)
  78. .on('file', function (file, id, parent) {
  79. // When file completes, unmute it.
  80. muted = muted.filter(function (mutedId) {
  81. return id !== mutedId
  82. })
  83. })
  84. // Call bundle() manually to start watch processes.
  85. bundle()
  86. /**
  87. * Creates bundle and writes it to static and public folders.
  88. * Changes to
  89. * @param {[type]} ids [description]
  90. * @return {[type]} [description]
  91. */
  92. function bundle (ids) {
  93. ids = ids || []
  94. ids.forEach(function (id) {
  95. if (!isMuted(id, muted)) {
  96. console.info(chalk.cyan('change:'), id)
  97. muted.push(id)
  98. }
  99. })
  100. var exampleName = path.basename(path.dirname(file))
  101. var output = dstPattern.replace('**', exampleName)
  102. var parentDir = path.dirname(output)
  103. mkdirp.sync(parentDir)
  104. console.info(chalk.green('✓ building:'), chalk.green(path.relative(process.cwd(), file)))
  105. browseFy
  106. .bundle()
  107. .on('error', onError)
  108. .pipe(createStream(output))
  109. }
  110. })
  111. })
  112. /**
  113. * Logs to console and shows desktop notification on error.
  114. * Calls `this.emit(end)` to stop bundling.
  115. * @param {object} err Error object
  116. */
  117. function onError (err) {
  118. console.error(chalk.red('✗ error:'), chalk.red(err.message))
  119. notifier.notify({
  120. 'title': 'Build failed:',
  121. 'message': err.message
  122. })
  123. this.emit('end')
  124. // When running without watch, process.exit(1) on error
  125. if (!watchifyEnabled) {
  126. process.exit(1)
  127. }
  128. }
  129. /**
  130. * Checks if a file has been added to muted list.
  131. * This stops single changes from logging multiple times.
  132. * @param {string} id Name of changed file
  133. * @param {Array<string>} list Muted files array
  134. * @return {Boolean} True if file is muted
  135. */
  136. function isMuted (id, list) {
  137. return list.reduce(function (prev, curr) {
  138. return prev || (curr === id)
  139. }, false)
  140. }