1. 'use strict';
    
  2. 
    
  3. // Do this as the first thing so that any code reading it knows the right env.
    
  4. process.env.BABEL_ENV = 'production';
    
  5. process.env.NODE_ENV = 'production';
    
  6. 
    
  7. // Makes the script crash on unhandled rejections instead of silently
    
  8. // ignoring them. In the future, promise rejections that are not handled will
    
  9. // terminate the Node.js process with a non-zero exit code.
    
  10. process.on('unhandledRejection', err => {
    
  11.   throw err;
    
  12. });
    
  13. 
    
  14. // Ensure environment variables are read.
    
  15. require('../config/env');
    
  16. 
    
  17. const path = require('path');
    
  18. const chalk = require('chalk');
    
  19. const fs = require('fs-extra');
    
  20. const webpack = require('webpack');
    
  21. const configFactory = require('../config/webpack.config');
    
  22. const paths = require('../config/paths');
    
  23. const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
    
  24. const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
    
  25. const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
    
  26. const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
    
  27. const printBuildError = require('react-dev-utils/printBuildError');
    
  28. 
    
  29. const measureFileSizesBeforeBuild =
    
  30.   FileSizeReporter.measureFileSizesBeforeBuild;
    
  31. const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
    
  32. const useYarn = fs.existsSync(paths.yarnLockFile);
    
  33. 
    
  34. // These sizes are pretty large. We'll warn for bundles exceeding them.
    
  35. const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
    
  36. const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
    
  37. 
    
  38. const isInteractive = process.stdout.isTTY;
    
  39. 
    
  40. // Warn and crash if required files are missing
    
  41. if (!checkRequiredFiles([paths.appIndexJs])) {
    
  42.   process.exit(1);
    
  43. }
    
  44. 
    
  45. const argv = process.argv.slice(2);
    
  46. const writeStatsJson = argv.indexOf('--stats') !== -1;
    
  47. 
    
  48. // Generate configuration
    
  49. const config = configFactory('production');
    
  50. 
    
  51. // We require that you explicitly set browsers and do not fall back to
    
  52. // browserslist defaults.
    
  53. const {checkBrowsers} = require('react-dev-utils/browsersHelper');
    
  54. checkBrowsers(paths.appPath, isInteractive)
    
  55.   .then(() => {
    
  56.     // First, read the current file sizes in build directory.
    
  57.     // This lets us display how much they changed later.
    
  58.     return measureFileSizesBeforeBuild(paths.appBuild);
    
  59.   })
    
  60.   .then(previousFileSizes => {
    
  61.     // Remove all content but keep the directory so that
    
  62.     // if you're in it, you don't end up in Trash
    
  63.     fs.emptyDirSync(paths.appBuild);
    
  64.     // Merge with the public folder
    
  65.     copyPublicFolder();
    
  66.     // Start the webpack build
    
  67.     return build(previousFileSizes);
    
  68.   })
    
  69.   .then(
    
  70.     ({stats, previousFileSizes, warnings}) => {
    
  71.       if (warnings.length) {
    
  72.         console.log(chalk.yellow('Compiled with warnings.\n'));
    
  73.         console.log(warnings.join('\n\n'));
    
  74.         console.log(
    
  75.           '\nSearch for the ' +
    
  76.             chalk.underline(chalk.yellow('keywords')) +
    
  77.             ' to learn more about each warning.'
    
  78.         );
    
  79.         console.log(
    
  80.           'To ignore, add ' +
    
  81.             chalk.cyan('// eslint-disable-next-line') +
    
  82.             ' to the line before.\n'
    
  83.         );
    
  84.       } else {
    
  85.         console.log(chalk.green('Compiled successfully.\n'));
    
  86.       }
    
  87. 
    
  88.       console.log('File sizes after gzip:\n');
    
  89.       printFileSizesAfterBuild(
    
  90.         stats,
    
  91.         previousFileSizes,
    
  92.         paths.appBuild,
    
  93.         WARN_AFTER_BUNDLE_GZIP_SIZE,
    
  94.         WARN_AFTER_CHUNK_GZIP_SIZE
    
  95.       );
    
  96.       console.log();
    
  97. 
    
  98.       const appPackage = require(paths.appPackageJson);
    
  99.       const publicUrl = paths.publicUrlOrPath;
    
  100.       const publicPath = config.output.publicPath;
    
  101.       const buildFolder = path.relative(process.cwd(), paths.appBuild);
    
  102.       printHostingInstructions(
    
  103.         appPackage,
    
  104.         publicUrl,
    
  105.         publicPath,
    
  106.         buildFolder,
    
  107.         useYarn
    
  108.       );
    
  109.     },
    
  110.     err => {
    
  111.       const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
    
  112.       if (tscCompileOnError) {
    
  113.         console.log(
    
  114.           chalk.yellow(
    
  115.             'Compiled with the following type errors (you may want to check these before deploying your app):\n'
    
  116.           )
    
  117.         );
    
  118.         printBuildError(err);
    
  119.       } else {
    
  120.         console.log(chalk.red('Failed to compile.\n'));
    
  121.         printBuildError(err);
    
  122.         process.exit(1);
    
  123.       }
    
  124.     }
    
  125.   )
    
  126.   .catch(err => {
    
  127.     if (err && err.message) {
    
  128.       console.log(err.message);
    
  129.     }
    
  130.     process.exit(1);
    
  131.   });
    
  132. 
    
  133. // Create the production build and print the deployment instructions.
    
  134. function build(previousFileSizes) {
    
  135.   console.log('Creating an optimized production build...');
    
  136. 
    
  137.   const compiler = webpack(config);
    
  138.   return new Promise((resolve, reject) => {
    
  139.     compiler.run((err, stats) => {
    
  140.       let messages;
    
  141.       if (err) {
    
  142.         if (!err.message) {
    
  143.           return reject(err);
    
  144.         }
    
  145. 
    
  146.         let errMessage = err.message;
    
  147. 
    
  148.         // Add additional information for postcss errors
    
  149.         if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
    
  150.           errMessage +=
    
  151.             '\nCompileError: Begins at CSS selector ' +
    
  152.             err['postcssNode'].selector;
    
  153.         }
    
  154. 
    
  155.         messages = formatWebpackMessages({
    
  156.           errors: [errMessage],
    
  157.           warnings: [],
    
  158.         });
    
  159.       } else {
    
  160.         messages = formatWebpackMessages(
    
  161.           stats.toJson({all: false, warnings: true, errors: true})
    
  162.         );
    
  163.       }
    
  164.       if (messages.errors.length) {
    
  165.         // Only keep the first error. Others are often indicative
    
  166.         // of the same problem, but confuse the reader with noise.
    
  167.         if (messages.errors.length > 1) {
    
  168.           messages.errors.length = 1;
    
  169.         }
    
  170.         return reject(new Error(messages.errors.join('\n\n')));
    
  171.       }
    
  172.       if (
    
  173.         process.env.CI &&
    
  174.         (typeof process.env.CI !== 'string' ||
    
  175.           process.env.CI.toLowerCase() !== 'false') &&
    
  176.         messages.warnings.length
    
  177.       ) {
    
  178.         // Ignore sourcemap warnings in CI builds. See #8227 for more info.
    
  179.         const filteredWarnings = messages.warnings.filter(
    
  180.           w => !/Failed to parse source map/.test(w)
    
  181.         );
    
  182.         if (filteredWarnings.length) {
    
  183.           console.log(
    
  184.             chalk.yellow(
    
  185.               '\nTreating warnings as errors because process.env.CI = true.\n' +
    
  186.                 'Most CI servers set it automatically.\n'
    
  187.             )
    
  188.           );
    
  189.           return reject(new Error(filteredWarnings.join('\n\n')));
    
  190.         }
    
  191.       }
    
  192. 
    
  193.       const resolveArgs = {
    
  194.         stats,
    
  195.         previousFileSizes,
    
  196.         warnings: messages.warnings,
    
  197.       };
    
  198. 
    
  199.       return resolve(resolveArgs);
    
  200.     });
    
  201.   });
    
  202. }
    
  203. 
    
  204. function copyPublicFolder() {
    
  205.   fs.copySync('public', 'build', {
    
  206.     dereference: true,
    
  207.   });
    
  208. }