index.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. var stripANSI = require('strip-ansi');
  2. var path = require('path');
  3. var os = require('os');
  4. var notifier = require('node-notifier');
  5. var DEFAULT_LOGO = path.join(__dirname, 'logo.png');
  6. function WebpackNotifierPlugin(options) {
  7. this.options = options || {};
  8. this.lastBuildSucceeded = false;
  9. this.isFirstBuild = true;
  10. }
  11. module.exports = WebpackNotifierPlugin;
  12. function findFirstDFS(compilation, key) {
  13. var match = compilation[key][0];
  14. if (match) {
  15. return match;
  16. }
  17. var children = compilation.children;
  18. for (var i = 0; i < children.length; i += 1) {
  19. match = findFirstDFS(children[i], key);
  20. if (match) {
  21. return match;
  22. }
  23. }
  24. }
  25. WebpackNotifierPlugin.prototype.compileEndOptions = function compileEndOptions(stats) {
  26. if (this.isFirstBuild) {
  27. this.isFirstBuild = false;
  28. if (this.options.skipFirstNotification) {
  29. return {};
  30. }
  31. }
  32. var imageFromOptions = ('contentImage' in this.options)
  33. ? this.options.contentImage
  34. : DEFAULT_LOGO;
  35. var successImage = '';
  36. var warningsImage = '';
  37. var errorsImage = '';
  38. if (typeof imageFromOptions === 'object') {
  39. successImage = imageFromOptions.success;
  40. warningsImage = imageFromOptions.warning;
  41. errorsImage = imageFromOptions.error;
  42. } else {
  43. successImage = imageFromOptions;
  44. warningsImage = imageFromOptions;
  45. errorsImage = imageFromOptions;
  46. }
  47. var hasEmoji = this.options.emoji;
  48. var error;
  49. var contentImage;
  50. var status;
  51. if (this.hasErrors(stats)) {
  52. error = findFirstDFS(stats.compilation, 'errors');
  53. contentImage = errorsImage;
  54. status = 'error';
  55. } else if (this.options.onlyOnError) {
  56. return {};
  57. } else if (this.hasWarnings(stats) && !this.options.excludeWarnings) {
  58. error = findFirstDFS(stats.compilation, 'warnings');
  59. contentImage = warningsImage;
  60. status = 'warning';
  61. } else if (!this.lastBuildSucceeded || this.options.alwaysNotify) {
  62. this.lastBuildSucceeded = true;
  63. return {
  64. message: (hasEmoji ? '✅ ' : '') + 'Build successful',
  65. contentImage: successImage,
  66. status: 'success'
  67. };
  68. } else {
  69. return {};
  70. }
  71. this.lastBuildSucceeded = false;
  72. var message = '';
  73. if (error.module && error.module.rawRequest) {
  74. message = error.module.rawRequest + '\n';
  75. }
  76. if (error.error) {
  77. message = (hasEmoji ? '❌ ' : '') + 'Error: ' + message + error.error.toString();
  78. } else if (error.warning) {
  79. message = (hasEmoji ? '⚠️ ' : '') + 'Warning: ' + message + error.warning.toString();
  80. } else if (error.message) {
  81. message = (hasEmoji ? '⚠️ ' : '') + 'Warning: ' + message + error.message.toString();
  82. }
  83. return {
  84. message: stripANSI(message),
  85. contentImage: contentImage,
  86. status: status
  87. };
  88. };
  89. WebpackNotifierPlugin.prototype.hasErrors = function hasErrors(stats) {
  90. return stats.hasErrors()
  91. || stats.compilation.children.some(child => child.getStats().hasErrors());
  92. };
  93. WebpackNotifierPlugin.prototype.hasWarnings = function hasWarnings(stats) {
  94. return stats.hasWarnings()
  95. || stats.compilation.children.some(child => child.getStats().hasWarnings());
  96. };
  97. WebpackNotifierPlugin.prototype.compilationDone = function compilationDone(stats) {
  98. var { message, contentImage, status } = this.compileEndOptions(stats);
  99. if (message) {
  100. var title = this.options.title ? this.options.title : 'Webpack';
  101. if (typeof title === 'function') {
  102. title = title({
  103. msg: message, // compatibility with v1.11.0
  104. message: message,
  105. status: status
  106. });
  107. }
  108. var icon = (os.platform() === 'win32' || os.platform() === 'linux')
  109. ? contentImage
  110. : undefined;
  111. notifier.notify(Object.assign(
  112. {},
  113. this.options,
  114. {
  115. title,
  116. message,
  117. contentImage,
  118. icon
  119. }
  120. ));
  121. }
  122. };
  123. WebpackNotifierPlugin.prototype.apply = function apply(compiler) {
  124. if (compiler.hooks) {
  125. var plugin = { name: 'Notifier' };
  126. compiler.hooks.done.tap(plugin, this.compilationDone.bind(this));
  127. } else {
  128. compiler.plugin('done', this.compilationDone.bind(this));
  129. }
  130. };