UNPKG

7.11 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('react-dev-utils/chalk');
36const fs = require('fs-extra');
37const webpack = require('webpack');
38const configFactory = require('../config/webpack.config');
39const paths = require('../config/paths');
40const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
41const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
42const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
43const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
44const printBuildError = require('react-dev-utils/printBuildError');
45
46const measureFileSizesBeforeBuild =
47 FileSizeReporter.measureFileSizesBeforeBuild;
48const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
49const useYarn = fs.existsSync(paths.yarnLockFile);
50
51// These sizes are pretty large. We'll warn for bundles exceeding them.
52const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
53const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
54
55const isInteractive = process.stdout.isTTY;
56
57// Warn and crash if required files are missing
58if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
59 process.exit(1);
60}
61
62// Generate configuration
63const config = configFactory('production');
64
65// We require that you explicitly set browsers and do not fall back to
66// browserslist defaults.
67const { checkBrowsers } = require('react-dev-utils/browsersHelper');
68checkBrowsers(paths.appPath, isInteractive)
69 .then(() => {
70 // First, read the current file sizes in build directory.
71 // This lets us display how much they changed later.
72 return measureFileSizesBeforeBuild(paths.appBuild);
73 })
74 .then(previousFileSizes => {
75 // Remove all content but keep the directory so that
76 // if you're in it, you don't end up in Trash
77 fs.emptyDirSync(paths.appBuild);
78 // Merge with the public folder
79 copyPublicFolder();
80 // Start the webpack build
81 return build(previousFileSizes);
82 })
83 .then(
84 ({ stats, previousFileSizes, warnings }) => {
85 if (warnings.length) {
86 console.log(chalk.yellow('Compiled with warnings.\n'));
87 console.log(warnings.join('\n\n'));
88 console.log(
89 '\nSearch for the ' +
90 chalk.underline(chalk.yellow('keywords')) +
91 ' to learn more about each warning.'
92 );
93 console.log(
94 'To ignore, add ' +
95 chalk.cyan('// eslint-disable-next-line') +
96 ' to the line before.\n'
97 );
98 } else {
99 console.log(chalk.green('Compiled successfully.\n'));
100 }
101
102 console.log('File sizes after gzip:\n');
103 printFileSizesAfterBuild(
104 stats,
105 previousFileSizes,
106 paths.appBuild,
107 WARN_AFTER_BUNDLE_GZIP_SIZE,
108 WARN_AFTER_CHUNK_GZIP_SIZE
109 );
110 console.log();
111
112 const appPackage = require(paths.appPackageJson);
113 const publicUrl = paths.publicUrl;
114 const publicPath = config.output.publicPath;
115 const buildFolder = path.relative(process.cwd(), paths.appBuild);
116 printHostingInstructions(
117 appPackage,
118 publicUrl,
119 publicPath,
120 buildFolder,
121 useYarn
122 );
123 },
124 err => {
125 const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
126 if (tscCompileOnError) {
127 console.log(chalk.yellow(
128 'Compiled with the following type errors (you may want to check these before deploying your app):\n'
129 ));
130 printBuildError(err);
131 } else {
132 console.log(chalk.red('Failed to compile.\n'));
133 printBuildError(err);
134 process.exit(1);
135 }
136 }
137 )
138 .catch(err => {
139 if (err && err.message) {
140 console.log(err.message);
141 }
142 process.exit(1);
143 });
144
145// Create the production build and print the deployment instructions.
146function build(previousFileSizes) {
147 // We used to support resolving modules according to `NODE_PATH`.
148 // This now has been deprecated in favor of jsconfig/tsconfig.json
149 // This lets you use absolute paths in imports inside large monorepos:
150 if (process.env.NODE_PATH) {
151 console.log(
152 chalk.yellow(
153 'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
154 )
155 );
156 console.log();
157 }
158
159 console.log('Creating an optimized production build...');
160
161 const compiler = webpack(config);
162 return new Promise((resolve, reject) => {
163 compiler.run((err, stats) => {
164 let messages;
165 if (err) {
166 if (!err.message) {
167 return reject(err);
168 }
169 messages = formatWebpackMessages({
170 errors: [err.message],
171 warnings: [],
172 });
173 } else {
174 messages = formatWebpackMessages(
175 stats.toJson({ all: false, warnings: true, errors: true })
176 );
177 }
178 if (messages.errors.length) {
179 // Only keep the first error. Others are often indicative
180 // of the same problem, but confuse the reader with noise.
181 if (messages.errors.length > 1) {
182 messages.errors.length = 1;
183 }
184 return reject(new Error(messages.errors.join('\n\n')));
185 }
186 if (
187 process.env.CI &&
188 (typeof process.env.CI !== 'string' ||
189 process.env.CI.toLowerCase() !== 'false') &&
190 messages.warnings.length
191 ) {
192 console.log(
193 chalk.yellow(
194 '\nTreating warnings as errors because process.env.CI = true.\n' +
195 'Most CI servers set it automatically.\n'
196 )
197 );
198 return reject(new Error(messages.warnings.join('\n\n')));
199 }
200
201 return resolve({
202 stats,
203 previousFileSizes,
204 warnings: messages.warnings,
205 });
206 });
207 });
208}
209
210function copyPublicFolder() {
211 fs.copySync(paths.appPublic, paths.appBuild, {
212 dereference: true,
213 filter: file => file !== paths.appHtml,
214 });
215}