1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
7 // Do this as the first thing so that any code reading it knows the right env.
8 process.env.BABEL_ENV = 'production';
9 process.env.NODE_ENV = 'production';
11 // Makes the script crash on unhandled rejections instead of silently
12 // ignoring them. In the future, promise rejections that are not handled will
13 // terminate the Node.js process with a non-zero exit code.
14 process.on('unhandledRejection', err => {
18 // Ensure environment variables are read.
19 require('../config/env');
21 const path = require('path');
22 const chalk = require('react-dev-utils/chalk');
23 const fs = require('fs-extra');
24 const bfj = require('bfj');
25 const webpack = require('webpack');
26 const configFactory = require('../config/webpack.config');
27 const paths = require('../config/paths');
28 const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
29 const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
30 const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
31 const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
32 const printBuildError = require('react-dev-utils/printBuildError');
34 const measureFileSizesBeforeBuild =
35 FileSizeReporter.measureFileSizesBeforeBuild;
36 const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
37 const useYarn = fs.existsSync(paths.yarnLockFile);
39 // These sizes are pretty large. We'll warn for bundles exceeding them.
40 const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
41 const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
43 const isInteractive = process.stdout.isTTY;
45 // Warn and crash if required files are missing
46 if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
50 const argv = process.argv.slice(2);
51 const writeStatsJson = argv.indexOf('--stats') !== -1;
53 // Generate configuration
54 const config = configFactory('production');
56 // We require that you explicitly set browsers and do not fall back to
57 // browserslist defaults.
58 const { checkBrowsers } = require('react-dev-utils/browsersHelper');
59 checkBrowsers(paths.appPath, isInteractive)
61 // First, read the current file sizes in build directory.
62 // This lets us display how much they changed later.
63 return measureFileSizesBeforeBuild(paths.appBuild);
65 .then(previousFileSizes => {
66 // Remove all content but keep the directory so that
67 // if you're in it, you don't end up in Trash
68 fs.emptyDirSync(paths.appBuild);
69 // Merge with the public folder
71 // Start the webpack build
72 return build(previousFileSizes);
75 ({ stats, previousFileSizes, warnings }) => {
76 if (warnings.length) {
77 console.log(chalk.yellow('Compiled with warnings.\n'));
78 console.log(warnings.join('\n\n'));
81 chalk.underline(chalk.yellow('keywords')) +
82 ' to learn more about each warning.'
86 chalk.cyan('// eslint-disable-next-line') +
87 ' to the line before.\n'
90 console.log(chalk.green('Compiled successfully.\n'));
93 console.log('File sizes after gzip:\n');
94 printFileSizesAfterBuild(
98 WARN_AFTER_BUNDLE_GZIP_SIZE,
99 WARN_AFTER_CHUNK_GZIP_SIZE
103 const appPackage = require(paths.appPackageJson);
104 const publicUrl = paths.publicUrlOrPath;
105 const publicPath = config.output.publicPath;
106 const buildFolder = path.relative(process.cwd(), paths.appBuild);
107 printHostingInstructions(
116 const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
117 if (tscCompileOnError) {
120 'Compiled with the following type errors (you may want to check these before deploying your app):\n'
123 printBuildError(err);
125 console.log(chalk.red('Failed to compile.\n'));
126 printBuildError(err);
132 if (err && err.message) {
133 console.log(err.message);
138 // Create the production build and print the deployment instructions.
139 function build(previousFileSizes) {
140 console.log('Creating an optimized production build...');
142 const compiler = webpack(config);
143 return new Promise((resolve, reject) => {
144 compiler.run((err, stats) => {
151 let errMessage = err.message;
153 // Add additional information for postcss errors
154 if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
156 '\nCompileError: Begins at CSS selector ' +
157 err['postcssNode'].selector;
160 messages = formatWebpackMessages({
161 errors: [errMessage],
165 messages = formatWebpackMessages(
166 stats.toJson({ all: false, warnings: true, errors: true })
169 if (messages.errors.length) {
170 // Only keep the first error. Others are often indicative
171 // of the same problem, but confuse the reader with noise.
172 if (messages.errors.length > 1) {
173 messages.errors.length = 1;
175 return reject(new Error(messages.errors.join('\n\n')));
179 (typeof process.env.CI !== 'string' ||
180 process.env.CI.toLowerCase() !== 'false') &&
181 messages.warnings.length
183 // Ignore sourcemap warnings in CI builds. See #8227 for more info.
184 const filteredWarnings = messages.warnings.filter(
185 w => !/Failed to parse source map/.test(w)
187 if (filteredWarnings.length) {
190 '\nTreating warnings as errors because process.env.CI = true.\n' +
191 'Most CI servers set it automatically.\n'
194 return reject(new Error(filteredWarnings.join('\n\n')));
198 const resolveArgs = {
201 warnings: messages.warnings,
204 if (writeStatsJson) {
206 .write(paths.appBuild + '/bundle-stats.json', stats.toJson())
207 .then(() => resolve(resolveArgs))
208 .catch(error => reject(new Error(error)));
211 return resolve(resolveArgs);
216 function copyPublicFolder() {
217 fs.copySync(paths.appPublic, paths.appBuild, {
219 filter: file => file !== paths.appHtml,