I am working with a repo with a number of Node packages created with create-react-app
, all of which are built and tested by the CI system. Each package's build/test, done with react-scripts build
followed by react-scripts test --silent
, is currently producing over twenty lines of output resulting in a build log with well over a hundred lines of material such as "File sizes after gzip" and "Find out more about deployment here." This makes it more difficult to see error messages, warnings or other problems in that log.
Is there some way for me to quiet this down short of writing my own custom build script (and possibly test script, too) for each one of the packages? If I do need custom scripts, what's the best way to re-use as much as possible of the existing code that's doing the build and test?
react-scripts build
runs bin/react-scripts.js
from the react-scripts
package which basically just runs scripts/build.js
from that same package.
Sadly, that build.js
script (as of 2018-10-15, anyway) is hard-coded to call functions such as printFileSizesAfterBuild()
and printHostingInstructions()
, without any option to disable these. So there's currently no way to change this except to make a copy of build.js
, modify it not to print the things you don't want, and use that instead.
There is a pull request PR #5429 from @LukasGjetting to add a --silent
option to the build script. It's been closed due to lack of inactivity, and the create-react-app
developers have made it fairly clear in other places that they're not intending to make react-scripts
very configurable; the solution they suggest is just to use your own build.js
script.
If you copy the build.js script from /node_modules/react-scripts/scripts/build.js
in the root of your application, make the paths relative to a const basepath = __dirname+'/node_modules/react-scripts/scripts/'
and elminate unnecessary logs.
Adjust the package.json
scripts build to: node build
and you have a very quiet build for a react app :)
Sample build script:
// @remove-on-eject-begin
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @remove-on-eject-end
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
const basepath = __dirname + '/node_modules/react-scripts/scripts/';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require(basepath + '../config/env');
// @remove-on-eject-begin
// Do the preflight checks (only happens before eject).
const verifyPackageTree = require(basepath + 'utils/verifyPackageTree');
if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') {
verifyPackageTree();
}
const verifyTypeScriptSetup = require(basepath + 'utils/verifyTypeScriptSetup');
verifyTypeScriptSetup();
// @remove-on-eject-end
const path = require('path');
const chalk = require('react-dev-utils/chalk');
const fs = require('fs-extra');
const webpack = require('webpack');
const configFactory = require(basepath + '../config/webpack.config');
const paths = require(basepath + '../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Generate configuration
const config = configFactory('production');
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const {
checkBrowsers
} = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
return measureFileSizesBeforeBuild(paths.appBuild);
})
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({
stats,
previousFileSizes,
warnings
}) => {
// if (warnings.length) {
// console.log(chalk.yellow('Compiled with warnings.\n'));
// console.log(warnings.join('\n\n'));
// console.log(
// '\nSearch for the ' +
// chalk.underline(chalk.yellow('keywords')) +
// ' to learn more about each warning.'
// );
// console.log(
// 'To ignore, add ' +
// chalk.cyan('// eslint-disable-next-line') +
// ' to the line before.\n'
// );
// } else {
// console.log(chalk.green('Compiled successfully.\n'));
// }
//
// console.log('File sizes after gzip:\n');
// printFileSizesAfterBuild(
// stats,
// previousFileSizes,
// paths.appBuild,
// WARN_AFTER_BUNDLE_GZIP_SIZE,
// WARN_AFTER_CHUNK_GZIP_SIZE
// );
// console.log();
console.log(chalk.green('Compiled successfully.\n'));
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrlOrPath;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
// printHostingInstructions(
// appPackage,
// publicUrl,
// publicPath,
// buildFolder,
// useYarn
// );
},
err => {
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
if (tscCompileOnError) {
console.log(
chalk.yellow(
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
)
);
printBuildError(err);
} else {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
}
)
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
// We used to support resolving modules according to `NODE_PATH`.
// This now has been deprecated in favor of jsconfig/tsconfig.json
// This lets you use absolute paths in imports inside large monorepos:
if (process.env.NODE_PATH) {
console.log(
chalk.yellow(
'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.'
)
);
console.log();
}
const compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
let messages;
if (err) {
if (!err.message) {
return reject(err);
}
let errMessage = err.message;
// Add additional information for postcss errors
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
errMessage +=
'\nCompileError: Begins at CSS selector ' +
err['postcssNode'].selector;
}
messages = formatWebpackMessages({
errors: [errMessage],
warnings: [],
});
} else {
messages = formatWebpackMessages(
stats.toJson({
all: false,
warnings: true,
errors: true
})
);
}
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(messages.warnings.join('\n\n')));
}
return resolve({
stats,
previousFileSizes,
warnings: messages.warnings,
});
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}
and sample package.json script option:
"scripts": {
"start": "react-scripts start", "build": "node build"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With