UNPKG

7.43 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.NODE_ENV = 'production';
15
16// Makes the script crash on unhandled rejections instead of silently
17// ignoring them. In the future, promise rejections that are not handled will
18// terminate the Node.js process with a non-zero exit code.
19process.on('unhandledRejection', err => {
20 throw err;
21});
22
23// Load environment variables from .env file. Suppress warnings using silent
24// if this file is missing. dotenv will never modify any environment variables
25// that have already been set.
26// https://github.com/motdotla/dotenv
27require('dotenv').config({ silent: true });
28
29const chalk = require('chalk');
30const fs = require('fs-extra');
31const path = require('path');
32const url = require('url');
33const webpack = require('webpack');
34const config = require('../config/webpack.config.prod');
35const paths = require('../config/paths');
36const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
37const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
38
39const measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild;
40const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
41const useYarn = fs.existsSync(paths.yarnLockFile);
42
43// Warn and crash if required files are missing
44if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
45 process.exit(1);
46}
47
48// First, read the current file sizes in build directory.
49// This lets us display how much they changed later.
50measureFileSizesBeforeBuild(paths.appBuild).then(previousFileSizes => {
51 // Remove all content but keep the directory so that
52 // if you're in it, you don't end up in Trash
53 fs.emptyDirSync(paths.appBuild);
54
55 // Start the webpack build
56 build(previousFileSizes);
57
58 // Merge with the public folder
59 copyPublicFolder();
60});
61
62// Print out errors
63function printErrors(summary, errors) {
64 console.log(chalk.red(summary));
65 console.log();
66 errors.forEach(err => {
67 console.log(err.message || err);
68 console.log();
69 });
70}
71
72// Create the production build and print the deployment instructions.
73function build(previousFileSizes) {
74 console.log('Creating an optimized production build...');
75
76 let compiler;
77 try {
78 compiler = webpack(config);
79 } catch (err) {
80 printErrors('Failed to compile.', [err]);
81 process.exit(1);
82 }
83
84 compiler.run((err, stats) => {
85 if (err) {
86 printErrors('Failed to compile.', [err]);
87 process.exit(1);
88 }
89
90 if (stats.compilation.errors.length) {
91 printErrors('Failed to compile.', stats.compilation.errors);
92 process.exit(1);
93 }
94
95 if (process.env.CI && stats.compilation.warnings.length) {
96 printErrors(
97 'Failed to compile. When process.env.CI = true, warnings are treated as failures. Most CI servers set this automatically.',
98 stats.compilation.warnings
99 );
100 process.exit(1);
101 }
102
103 console.log(chalk.green('Compiled successfully.'));
104 console.log();
105
106 console.log('File sizes after gzip:');
107 console.log();
108 printFileSizesAfterBuild(stats, previousFileSizes);
109 console.log();
110
111 const appPackage = require(paths.appPackageJson);
112 const publicUrl = paths.publicUrl;
113 const publicPath = config.output.publicPath;
114 const publicPathname = url.parse(publicPath).pathname;
115 if (publicUrl && publicUrl.indexOf('.github.io/') !== -1) {
116 // "homepage": "http://user.github.io/project"
117 console.log(
118 `The project was built assuming it is hosted at ${chalk.green(publicPathname)}.`
119 );
120 console.log(
121 `You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
122 );
123 console.log();
124 console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);
125 console.log(`To publish it at ${chalk.green(publicUrl)}, run:`);
126 // If script deploy has been added to package.json, skip the instructions
127 if (typeof appPackage.scripts.deploy === 'undefined') {
128 console.log();
129 if (useYarn) {
130 console.log(` ${chalk.cyan('yarn')} add --dev gh-pages`);
131 } else {
132 console.log(` ${chalk.cyan('npm')} install --save-dev gh-pages`);
133 }
134 console.log();
135 console.log(
136 `Add the following script in your ${chalk.cyan('package.json')}.`
137 );
138 console.log();
139 console.log(` ${chalk.dim('// ...')}`);
140 console.log(` ${chalk.yellow('"scripts"')}: {`);
141 console.log(` ${chalk.dim('// ...')}`);
142 console.log(
143 ` ${chalk.yellow('"predeploy"')}: ${chalk.yellow('"npm run build",')}`
144 );
145 console.log(
146 ` ${chalk.yellow('"deploy"')}: ${chalk.yellow('"gh-pages -d build"')}`
147 );
148 console.log(' }');
149 console.log();
150 console.log('Then run:');
151 }
152 console.log();
153 console.log(` ${chalk.cyan(useYarn ? 'yarn' : 'npm')} run deploy`);
154 console.log();
155 } else if (publicPath !== '/') {
156 // "homepage": "http://mywebsite.com/project"
157 console.log(
158 `The project was built assuming it is hosted at ${chalk.green(publicPath)}.`
159 );
160 console.log(
161 `You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
162 );
163 console.log();
164 console.log(`The ${chalk.cyan('build')} folder is ready to be deployed.`);
165 console.log();
166 } else {
167 if (publicUrl) {
168 // "homepage": "http://mywebsite.com"
169 console.log(
170 `The project was built assuming it is hosted at ${chalk.green(publicUrl)}.`
171 );
172 console.log(
173 `You can control this with the ${chalk.green('homepage')} field in your ${chalk.cyan('package.json')}.`
174 );
175 console.log();
176 } else {
177 // no homepage
178 console.log(
179 'The project was built assuming it is hosted at the server root.'
180 );
181 console.log(
182 `To override this, specify the ${chalk.green('homepage')} in your ${chalk.cyan('package.json')}.`
183 );
184 console.log('For example, add this to build it for GitHub Pages:');
185 console.log();
186 console.log(
187 ` ${chalk.green('"homepage"')} ${chalk.cyan(':')} ${chalk.green('"http://myname.github.io/myapp"')}${chalk.cyan(',')}`
188 );
189 console.log();
190 }
191 const build = path.relative(process.cwd(), paths.appBuild);
192 console.log(`The ${chalk.cyan(build)} folder is ready to be deployed.`);
193 console.log('You may serve it with a static server:');
194 console.log();
195 if (useYarn) {
196 console.log(` ${chalk.cyan('yarn')} global add serve`);
197 } else {
198 console.log(` ${chalk.cyan('npm')} install -g serve`);
199 }
200 console.log(` ${chalk.cyan('serve')} -s build`);
201 console.log();
202 }
203 });
204}
205
206function copyPublicFolder() {
207 fs.copySync(paths.appPublic, paths.appBuild, {
208 dereference: true,
209 filter: file => file !== paths.appHtml,
210 });
211}