UNPKG

5.31 kBJavaScriptView Raw
1// @remove-on-eject-begin
2/**
3 * Copyright (c) 2015-present, Facebook, Inc.
4 * All rights reserved.
5 *
6 * This source code is licensed under the BSD-style license found in the
7 * LICENSE file in the root directory of this source tree. An additional grant
8 * of patent rights can be found in the PATENTS file in the same directory.
9 */
10// @remove-on-eject-end
11'use strict';
12
13// Do this as the first thing so that any code reading it knows the right env.
14process.env.BABEL_ENV = 'production';
15process.env.NODE_ENV = 'production';
16
17// Makes the script crash on unhandled rejections instead of silently
18// ignoring them. In the future, promise rejections that are not handled will
19// terminate the Node.js process with a non-zero exit code.
20process.on('unhandledRejection', err => {
21 throw err;
22});
23
24// Ensure environment variables are read.
25require('../config/env');
26
27const path = require('path');
28const chalk = require('chalk');
29const fs = require('fs-extra');
30const webpack = require('webpack');
31const config = require('../config/webpack.config.prod');
32const paths = require('../config/paths');
33const checkRequiredFiles = require('@0xaio/react-dev-utils/checkRequiredFiles');
34const formatWebpackMessages = require('@0xaio/react-dev-utils/formatWebpackMessages');
35const printHostingInstructions = require('@0xaio/react-dev-utils/printHostingInstructions');
36const FileSizeReporter = require('@0xaio/react-dev-utils/FileSizeReporter');
37const printBuildError = require('@0xaio/react-dev-utils/printBuildError');
38
39const measureFileSizesBeforeBuild =
40 FileSizeReporter.measureFileSizesBeforeBuild;
41const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
42const useYarn = fs.existsSync(paths.yarnLockFile);
43
44// These sizes are pretty large. We'll warn for bundles exceeding them.
45const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
46const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
47
48// Warn and crash if required files are missing
49if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
50 process.exit(1);
51}
52
53// First, read the current file sizes in build directory.
54// This lets us display how much they changed later.
55measureFileSizesBeforeBuild(paths.appBuild)
56 .then(previousFileSizes => {
57 // Remove all content but keep the directory so that
58 // if you're in it, you don't end up in Trash
59 fs.emptyDirSync(paths.appBuild);
60 // Merge with the public folder
61 copyPublicFolder();
62 // Start the webpack build
63 return build(previousFileSizes);
64 })
65 .then(
66 ({ stats, previousFileSizes, warnings }) => {
67 if (warnings.length) {
68 console.log(chalk.yellow('Compiled with warnings.\n'));
69 console.log(warnings.join('\n\n'));
70 console.log(
71 '\nSearch for the ' +
72 chalk.underline(chalk.yellow('keywords')) +
73 ' to learn more about each warning.'
74 );
75 console.log(
76 'To ignore, add ' +
77 chalk.cyan('// eslint-disable-next-line') +
78 ' to the line before.\n'
79 );
80 } else {
81 console.log(chalk.green('Compiled successfully.\n'));
82 }
83
84 console.log('File sizes after gzip:\n');
85 printFileSizesAfterBuild(
86 stats,
87 previousFileSizes,
88 paths.appBuild,
89 WARN_AFTER_BUNDLE_GZIP_SIZE,
90 WARN_AFTER_CHUNK_GZIP_SIZE
91 );
92 console.log();
93
94 const appPackage = require(paths.appPackageJson);
95 const publicUrl = paths.publicUrl;
96 const publicPath = config.output.publicPath;
97 const buildFolder = path.relative(process.cwd(), paths.appBuild);
98 printHostingInstructions(
99 appPackage,
100 publicUrl,
101 publicPath,
102 buildFolder,
103 useYarn
104 );
105 },
106 err => {
107 console.log(chalk.red('Failed to compile.\n'));
108 printBuildError(err);
109 process.exit(1);
110 }
111 );
112
113// Create the production build and print the deployment instructions.
114function build(previousFileSizes) {
115 console.log('Creating an optimized production build...');
116
117 let compiler = webpack(config);
118 return new Promise((resolve, reject) => {
119 compiler.run((err, stats) => {
120 if (err) {
121 return reject(err);
122 }
123 const messages = formatWebpackMessages(stats.toJson({}, true));
124 if (messages.errors.length) {
125 // Only keep the first error. Others are often indicative
126 // of the same problem, but confuse the reader with noise.
127 if (messages.errors.length > 1) {
128 messages.errors.length = 1;
129 }
130 return reject(new Error(messages.errors.join('\n\n')));
131 }
132 if (
133 process.env.CI &&
134 (typeof process.env.CI !== 'string' ||
135 process.env.CI.toLowerCase() !== 'false') &&
136 messages.warnings.length
137 ) {
138 console.log(
139 chalk.yellow(
140 '\nTreating warnings as errors because process.env.CI = true.\n' +
141 'Most CI servers set it automatically.\n'
142 )
143 );
144 return reject(new Error(messages.warnings.join('\n\n')));
145 }
146 return resolve({
147 stats,
148 previousFileSizes,
149 warnings: messages.warnings,
150 });
151 });
152 });
153}
154
155function copyPublicFolder() {
156 fs.copySync(paths.appPublic, paths.appBuild, {
157 dereference: true,
158 filter: file => file !== paths.appHtml,
159 });
160}