build-examples.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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' Set that is checked
  20. * before announcing a changed file. It's removed from
  21. * the Set when it has been bundled.
  22. */
  23. const { glob } = require('multi-glob')
  24. const chalk = require('chalk')
  25. const path = require('path')
  26. const notifier = require('node-notifier')
  27. const esbuild = require('esbuild')
  28. const alias = require('esbuild-plugin-alias')
  29. const babelImport = import('esbuild-plugin-babel')
  30. const webRoot = __dirname
  31. let srcPattern = `${webRoot}/src/examples/**/app.es6`
  32. let dstPattern = `${webRoot}/public/examples/**/app.js`
  33. const watchifyEnabled = process.argv[2] === 'watch'
  34. // Instead of 'watch', build-examples.js can also take a path as cli argument.
  35. // In this case we'll only bundle the specified path/pattern
  36. if (!watchifyEnabled && process.argv.length > 2) {
  37. [, , srcPattern, dstPattern] = process.argv
  38. }
  39. // Find each app.es6 file with glob.
  40. glob(srcPattern, (err, files) => {
  41. if (err) throw new Error(err)
  42. if (watchifyEnabled) {
  43. console.log('--> Watching examples..')
  44. }
  45. files.forEach((file) => {
  46. const exampleName = path.basename(path.dirname(file))
  47. const outfile = dstPattern.replace('**', exampleName)
  48. babelImport.then(({ default: babel }) => esbuild.build({
  49. bundle: true,
  50. sourcemap: true,
  51. watch: watchifyEnabled,
  52. entryPoints: [file],
  53. outfile,
  54. banner: {
  55. js: '"use strict";',
  56. },
  57. loader: {
  58. '.es6': 'js',
  59. },
  60. plugins: [
  61. alias({
  62. '@uppy': path.resolve(__dirname, `../packages/@uppy`),
  63. }),
  64. babel({
  65. filter: /\.(es6|js)$/,
  66. config: { root: path.join(__dirname, '..') },
  67. }),
  68. ],
  69. })).catch(onError) // eslint-disable-line no-use-before-define
  70. })
  71. })
  72. /**
  73. * Logs to console and shows desktop notification on error.
  74. * Calls `this.emit(end)` to stop bundling.
  75. *
  76. * @param {object} err Error object
  77. */
  78. function onError (err) {
  79. console.error(chalk.red('✗ error:'), chalk.red(err.message))
  80. notifier.notify({
  81. title: 'Build failed:',
  82. message: err.message,
  83. })
  84. this?.emit?.('end')
  85. // When running without watch, process.exit(1) on error
  86. if (!watchifyEnabled) {
  87. process.exit(1)
  88. }
  89. }