UNPKG

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