build.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*eslint-disable no-console */
  2. process.env.BABEL_ENV = 'production';
  3. process.env.NODE_ENV = 'production';
  4. process.on('unhandledRejection', err => {
  5. throw err;
  6. });
  7. require('../config/env');
  8. const path = require('path');
  9. const chalk = require('chalk');
  10. const fs = require('fs-extra');
  11. const webpack = require('webpack');
  12. const config = require('../config/webpack.config.prod');
  13. const paths = require('../config/paths');
  14. const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
  15. const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
  16. const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
  17. const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
  18. const printBuildError = require('react-dev-utils/printBuildError');
  19. const measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild;
  20. const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
  21. const useYarn = fs.existsSync(paths.yarnLockFile);
  22. // These sizes are pretty large. We'll warn for bundles exceeding them.
  23. const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
  24. const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
  25. // Warn and crash if required files are missing
  26. if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
  27. process.exit(1);
  28. }
  29. // First, read the current file sizes in build directory.
  30. // This lets us display how much they changed later.
  31. measureFileSizesBeforeBuild(paths.appBuild)
  32. .then(previousFileSizes => {
  33. // Remove all content but keep the directory so that
  34. // if you're in it, you don't end up in Trash
  35. fs.emptyDirSync(paths.appBuild);
  36. // Merge with the public folder
  37. copyPublicFolder();
  38. // Start the webpack build
  39. return build(previousFileSizes);
  40. })
  41. .then(
  42. ({ stats, previousFileSizes, warnings }) => {
  43. if (warnings.length) {
  44. console.log(chalk.yellow('Compiled with warnings.\n'));
  45. console.log(warnings.join('\n\n'));
  46. console.log(`\nSearch for the ${chalk.underline(chalk.yellow('keywords'))} to learn more about each warning.`);
  47. console.log(`To ignore, add ${chalk.cyan('// eslint-disable-next-line')} to the line before.\n`);
  48. } else {
  49. console.log(chalk.green('Compiled successfully.\n'));
  50. }
  51. console.log('File sizes after gzip:\n');
  52. printFileSizesAfterBuild(
  53. stats,
  54. previousFileSizes,
  55. paths.appBuild,
  56. WARN_AFTER_BUNDLE_GZIP_SIZE,
  57. WARN_AFTER_CHUNK_GZIP_SIZE
  58. );
  59. console.log();
  60. const appPackage = require(paths.appPackageJson);
  61. const publicUrl = paths.publicUrl;
  62. const publicPath = config.output.publicPath;
  63. const buildFolder = path.relative(process.cwd(), paths.appBuild);
  64. printHostingInstructions(appPackage, publicUrl, publicPath, buildFolder, useYarn);
  65. },
  66. err => {
  67. throw err;
  68. console.log(chalk.red('Failed to compile.\n'));
  69. printBuildError(err);
  70. process.exit(1);
  71. }
  72. );
  73. // Create the production build and print the deployment instructions.
  74. function build(previousFileSizes) {
  75. console.log('Creating an optimized production build...');
  76. const compiler = webpack(config);
  77. return new Promise((resolve, reject) => {
  78. compiler.run((err, stats) => {
  79. if (err) {
  80. return reject(err);
  81. }
  82. const messages = formatWebpackMessages(stats.toJson({}, true));
  83. if (messages.errors.length) {
  84. // Only keep the first error. Others are often indicative
  85. // of the same problem, but confuse the reader with noise.
  86. if (messages.errors.length > 1) {
  87. messages.errors.length = 1;
  88. }
  89. return reject(new Error(messages.errors.join('\n\n')));
  90. }
  91. if (
  92. process.env.CI &&
  93. (typeof process.env.CI !== 'string' || process.env.CI.toLowerCase() !== 'false') &&
  94. messages.warnings.length
  95. ) {
  96. console.log(
  97. chalk.yellow(
  98. '\nTreating warnings as errors because process.env.CI = true.\n' + 'Most CI servers set it automatically.\n'
  99. )
  100. );
  101. return reject(new Error(messages.warnings.join('\n\n')));
  102. }
  103. return resolve({
  104. stats,
  105. previousFileSizes,
  106. warnings: messages.warnings,
  107. });
  108. });
  109. });
  110. }
  111. function copyPublicFolder() {
  112. fs.copySync(paths.appPublic, paths.appBuild, {
  113. dereference: true,
  114. filter: file => file !== paths.appHtml,
  115. });
  116. }