From 74a867523e7b72a0d5b8fdd8779c687633aaf4a6 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 12:26:09 -0500 Subject: [PATCH 1/7] Offer to set browser defaults --- .../react-dev-utils/WebpackDevServerUtils.js | 2 +- packages/react-dev-utils/browsersHelper.js | 92 +++++++++---- packages/react-dev-utils/package.json | 1 + packages/react-scripts/scripts/build.js | 126 +++++++++--------- packages/react-scripts/scripts/init.js | 8 +- packages/react-scripts/scripts/start.js | 100 +++++++------- 6 files changed, 183 insertions(+), 146 deletions(-) diff --git a/packages/react-dev-utils/WebpackDevServerUtils.js b/packages/react-dev-utils/WebpackDevServerUtils.js index 4add9f9c1bc..1208d7fc776 100644 --- a/packages/react-dev-utils/WebpackDevServerUtils.js +++ b/packages/react-dev-utils/WebpackDevServerUtils.js @@ -318,7 +318,7 @@ function prepareProxy(proxy, appPublicFolder) { // However we also want to respect `proxy` for API calls. // So if `proxy` is specified as a string, we need to decide which fallback to use. // We use a heuristic: We want to proxy all the requests that are not meant - // for static assets and as all the requests for static assets will be using + // for static assets and as all the requests for static assets will be using // `GET` method, we can proxy all non-`GET` requests. // For `GET` requests, if request `accept`s text/html, we pick /index.html. // Modern browsers include text/html into `accept` header when navigating. diff --git a/packages/react-dev-utils/browsersHelper.js b/packages/react-dev-utils/browsersHelper.js index 8358f851870..231ec853add 100644 --- a/packages/react-dev-utils/browsersHelper.js +++ b/packages/react-dev-utils/browsersHelper.js @@ -9,36 +9,80 @@ const browserslist = require('browserslist'); const chalk = require('chalk'); const os = require('os'); +const inquirer = require('inquirer'); +const pkgUp = require('pkg-up'); +const fs = require('fs'); -function checkBrowsers(dir) { - const found = browserslist.findConfig(dir); +const defaultBrowsers = { + development: ['chrome', 'firefox', 'edge'].map( + browser => `last 2 ${browser} versions` + ), + production: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 11'], +}; - if (found == null) { - console.log( - chalk.red('As of react-scripts >=2 you must specify targeted browsers.') + - os.EOL + - `Please add a ${chalk.underline( - 'browserslist' - )} key to your ${chalk.bold('package.json')}.` +function checkBrowsers(dir, retry = true) { + const current = browserslist.findConfig(dir); + if (current != null) { + return Promise.resolve(current); + } + + if (!retry) { + return Promise.reject( + new Error( + chalk.red( + 'As of react-scripts >=2 you must specify targeted browsers.' + ) + + os.EOL + + `Please add a ${chalk.underline( + 'browserslist' + )} key to your ${chalk.bold('package.json')}.` + ) ); - return null; } - return found; + + const question = { + type: 'confirm', + name: 'shouldSetBrowsers', + message: + chalk.yellow("We're unable to detect target browsers.") + + `\n\nWould you like to add the defaults to your ${chalk.bold( + 'package.json' + )}?`, + default: true, + }; + return inquirer.prompt(question).then(answer => { + if (answer.shouldSetBrowsers) { + return pkgUp(dir) + .then(filePath => { + if (filePath == null) { + return Promise.reject(); + } + + const pkg = JSON.parse(fs.readFileSync(filePath)); + pkg['browserslist'] = defaultBrowsers; + fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + '\n'); + }) + .catch(() => checkBrowsers(dir, false)); + } else { + return checkBrowsers(dir, false); + } + }); } function printBrowsers(dir) { - let browsers = checkBrowsers(dir); - if (browsers == null) { - console.log('Built the bundle with default browser support.'); - return; - } - browsers = browsers[process.env.NODE_ENV] || browsers; - if (Array.isArray(browsers)) { - browsers = browsers.join(', '); - } - console.log( - `Built the bundle with browser support for ${chalk.cyan(browsers)}.` - ); + return checkBrowsers(dir).then(browsers => { + if (browsers == null) { + console.log('Built the bundle with default browser support.'); + return; + } + browsers = browsers[process.env.NODE_ENV] || browsers; + if (Array.isArray(browsers)) { + browsers = browsers.join(', '); + } + console.log( + `Built the bundle with browser support for ${chalk.cyan(browsers)}.` + ); + }); } -module.exports = { checkBrowsers, printBrowsers }; +module.exports = { defaultBrowsers, checkBrowsers, printBrowsers }; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index c9d7f324a20..24a17287ad2 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -50,6 +50,7 @@ "inquirer": "5.0.0", "is-root": "1.0.0", "opn": "5.2.0", + "pkg-up": "2.0.0", "react-error-overlay": "^3.0.0", "recursive-readdir": "2.2.1", "shell-quote": "1.6.1", diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js index a4ba1cfcdb3..69107497fc8 100644 --- a/packages/react-scripts/scripts/build.js +++ b/packages/react-scripts/scripts/build.js @@ -41,13 +41,6 @@ const printHostingInstructions = require('react-dev-utils/printHostingInstructio const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); const printBuildError = require('react-dev-utils/printBuildError'); const { printBrowsers } = require('react-dev-utils/browsersHelper'); -// @remove-on-eject-begin -// Require browsers to be specified before you eject -const { checkBrowsers } = require('react-dev-utils/browsersHelper'); -if (!checkBrowsers(paths.appPath)) { - process.exit(1); -} -// @remove-on-eject-end const measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild; @@ -63,66 +56,71 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { process.exit(1); } -// First, read the current file sizes in build directory. -// This lets us display how much they changed later. -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.' +// We require that you explictly set browsers and do not fall back to +// browserslist defaults. +const { checkBrowsers } = require('react-dev-utils/browsersHelper'); +checkBrowsers(paths.appPath).then(() => + // First, read the current file sizes in build directory. + // This lets us display how much they changed later. + 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( - 'To ignore, add ' + - chalk.cyan('// eslint-disable-next-line') + - ' to the line before.\n' + console.log(); + + const appPackage = require(paths.appPackageJson); + const publicUrl = paths.publicUrl; + const publicPath = config.output.publicPath; + const buildFolder = path.relative(process.cwd(), paths.appBuild); + printHostingInstructions( + appPackage, + publicUrl, + publicPath, + buildFolder, + useYarn ); - } else { - console.log(chalk.green('Compiled successfully.\n')); + printBrowsers(paths.appPath); + }, + err => { + console.log(chalk.red('Failed to compile.\n')); + printBuildError(err); + process.exit(1); } - - console.log('File sizes after gzip:\n'); - printFileSizesAfterBuild( - stats, - previousFileSizes, - paths.appBuild, - WARN_AFTER_BUNDLE_GZIP_SIZE, - WARN_AFTER_CHUNK_GZIP_SIZE - ); - console.log(); - - const appPackage = require(paths.appPackageJson); - const publicUrl = paths.publicUrl; - const publicPath = config.output.publicPath; - const buildFolder = path.relative(process.cwd(), paths.appBuild); - printHostingInstructions( - appPackage, - publicUrl, - publicPath, - buildFolder, - useYarn - ); - printBrowsers(paths.appPath); - }, - err => { - console.log(chalk.red('Failed to compile.\n')); - printBuildError(err); - process.exit(1); - } - ); + ) +); // Create the production build and print the deployment instructions. function build(previousFileSizes) { diff --git a/packages/react-scripts/scripts/init.js b/packages/react-scripts/scripts/init.js index 7854a803771..ab1810423bb 100644 --- a/packages/react-scripts/scripts/init.js +++ b/packages/react-scripts/scripts/init.js @@ -18,6 +18,7 @@ const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); const spawn = require('react-dev-utils/crossSpawn'); +const { defaultBrowsers } = require('react-dev-utils/browsersHelper'); module.exports = function( appPath, @@ -43,12 +44,7 @@ module.exports = function( eject: 'react-scripts eject', }; - appPackage.browserslist = { - development: ['chrome', 'firefox', 'edge'].map( - browser => `last 2 ${browser} versions` - ), - production: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 11'], - }; + appPackage.browserslist = defaultBrowsers; fs.writeFileSync( path.join(appPath, 'package.json'), diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 2940dd90bad..387937fa0e3 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -48,13 +48,6 @@ const createDevServerConfig = require('../config/webpackDevServer.config'); const useYarn = fs.existsSync(paths.yarnLockFile); const isInteractive = process.stdout.isTTY; -// @remove-on-eject-begin -// Require browsers to be specified before you eject -const { checkBrowsers } = require('react-dev-utils/browsersHelper'); -if (!checkBrowsers(paths.appPath)) { - process.exit(1); -} -// @remove-on-eject-end // Warn and crash if required files are missing if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { @@ -65,50 +58,55 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; const HOST = process.env.HOST || '0.0.0.0'; -// We attempt to use the default port but if it is busy, we offer the user to -// run on a different port. `choosePort()` Promise resolves to the next free port. -choosePort(HOST, DEFAULT_PORT) - .then(port => { - if (port == null) { - // We have not found a port. - return; - } - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; - const appName = require(paths.appPackageJson).name; - const urls = prepareUrls(protocol, HOST, port); - // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler(webpack, config, appName, urls, useYarn); - // Load proxy config - const proxySetting = require(paths.appPackageJson).proxy; - const proxyConfig = prepareProxy(proxySetting, paths.appPublic); - // Serve webpack assets generated by the compiler over a web sever. - const serverConfig = createDevServerConfig( - proxyConfig, - urls.lanUrlForConfig - ); - const devServer = new WebpackDevServer(compiler, serverConfig); - // Launch WebpackDevServer. - devServer.listen(port, HOST, err => { - if (err) { - return console.log(err); - } - if (isInteractive) { - clearConsole(); +// We require that you explictly set browsers and do not fall back to +// browserslist defaults. +const { checkBrowsers } = require('react-dev-utils/browsersHelper'); +checkBrowsers(paths.appPath).then(() => + // We attempt to use the default port but if it is busy, we offer the user to + // run on a different port. `choosePort()` Promise resolves to the next free port. + choosePort(HOST, DEFAULT_PORT) + .then(port => { + if (port == null) { + // We have not found a port. + return; } - console.log(chalk.cyan('Starting the development server...\n')); - openBrowser(urls.localUrlForBrowser); - }); + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; + const appName = require(paths.appPackageJson).name; + const urls = prepareUrls(protocol, HOST, port); + // Create a webpack compiler that is configured with custom messages. + const compiler = createCompiler(webpack, config, appName, urls, useYarn); + // Load proxy config + const proxySetting = require(paths.appPackageJson).proxy; + const proxyConfig = prepareProxy(proxySetting, paths.appPublic); + // Serve webpack assets generated by the compiler over a web sever. + const serverConfig = createDevServerConfig( + proxyConfig, + urls.lanUrlForConfig + ); + const devServer = new WebpackDevServer(compiler, serverConfig); + // Launch WebpackDevServer. + devServer.listen(port, HOST, err => { + if (err) { + return console.log(err); + } + if (isInteractive) { + clearConsole(); + } + console.log(chalk.cyan('Starting the development server...\n')); + openBrowser(urls.localUrlForBrowser); + }); - ['SIGINT', 'SIGTERM'].forEach(function(sig) { - process.on(sig, function() { - devServer.close(); - process.exit(); + ['SIGINT', 'SIGTERM'].forEach(function(sig) { + process.on(sig, function() { + devServer.close(); + process.exit(); + }); }); - }); - }) - .catch(err => { - if (err && err.message) { - console.log(err.message); - } - process.exit(1); - }); + }) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }) +); From d49f8fa63f3aca090977a130a7394975c1e40980 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 12:29:25 -0500 Subject: [PATCH 2/7] Catch error on no --- packages/react-scripts/package.json | 13 ++- packages/react-scripts/scripts/build.js | 125 +++++++++++++----------- packages/react-scripts/scripts/start.js | 24 ++--- 3 files changed, 89 insertions(+), 73 deletions(-) diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index e41acbe8a93..d6149dcc933 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -70,7 +70,16 @@ "fsevents": "1.1.2" }, "browserslist": { - "development": "last 2 chrome versions", - "production": [">1%", "last 4 versions", "Firefox ESR", "not ie < 11"] + "development": [ + "last 2 chrome versions", + "last 2 firefox versions", + "last 2 edge versions" + ], + "production": [ + ">1%", + "last 4 versions", + "Firefox ESR", + "not ie < 11" + ] } } diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js index 69107497fc8..1cb4fc00b49 100644 --- a/packages/react-scripts/scripts/build.js +++ b/packages/react-scripts/scripts/build.js @@ -59,68 +59,75 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { // We require that you explictly set browsers and do not fall back to // browserslist defaults. const { checkBrowsers } = require('react-dev-utils/browsersHelper'); -checkBrowsers(paths.appPath).then(() => - // First, read the current file sizes in build directory. - // This lets us display how much they changed later. - 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.' +checkBrowsers(paths.appPath) + .then(() => + // First, read the current file sizes in build directory. + // This lets us display how much they changed later. + 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( - 'To ignore, add ' + - chalk.cyan('// eslint-disable-next-line') + - ' to the line before.\n' + console.log(); + + const appPackage = require(paths.appPackageJson); + const publicUrl = paths.publicUrl; + const publicPath = config.output.publicPath; + const buildFolder = path.relative(process.cwd(), paths.appBuild); + printHostingInstructions( + appPackage, + publicUrl, + publicPath, + buildFolder, + useYarn ); - } else { - console.log(chalk.green('Compiled successfully.\n')); + printBrowsers(paths.appPath); + }, + err => { + console.log(chalk.red('Failed to compile.\n')); + printBuildError(err); + process.exit(1); } - - console.log('File sizes after gzip:\n'); - printFileSizesAfterBuild( - stats, - previousFileSizes, - paths.appBuild, - WARN_AFTER_BUNDLE_GZIP_SIZE, - WARN_AFTER_CHUNK_GZIP_SIZE - ); - console.log(); - - const appPackage = require(paths.appPackageJson); - const publicUrl = paths.publicUrl; - const publicPath = config.output.publicPath; - const buildFolder = path.relative(process.cwd(), paths.appBuild); - printHostingInstructions( - appPackage, - publicUrl, - publicPath, - buildFolder, - useYarn - ); - printBrowsers(paths.appPath); - }, - err => { - 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) { diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 387937fa0e3..de8ef141fe9 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -61,11 +61,11 @@ const HOST = process.env.HOST || '0.0.0.0'; // We require that you explictly set browsers and do not fall back to // browserslist defaults. const { checkBrowsers } = require('react-dev-utils/browsersHelper'); -checkBrowsers(paths.appPath).then(() => - // We attempt to use the default port but if it is busy, we offer the user to - // run on a different port. `choosePort()` Promise resolves to the next free port. - choosePort(HOST, DEFAULT_PORT) - .then(port => { +checkBrowsers(paths.appPath) + .then(() => + // We attempt to use the default port but if it is busy, we offer the user to + // run on a different port. `choosePort()` Promise resolves to the next free port. + choosePort(HOST, DEFAULT_PORT).then(port => { if (port == null) { // We have not found a port. return; @@ -103,10 +103,10 @@ checkBrowsers(paths.appPath).then(() => }); }); }) - .catch(err => { - if (err && err.message) { - console.log(err.message); - } - process.exit(1); - }) -); + ) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }); From 2d1d11dea52c84bd38bbac9fd9ba03e358bcde9b Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 12:39:54 -0500 Subject: [PATCH 3/7] Add ending newlines --- packages/create-react-app/createReactApp.js | 10 +++++++--- packages/react-dev-utils/browsersHelper.js | 2 +- packages/react-scripts/scripts/eject.js | 3 ++- packages/react-scripts/scripts/init.js | 3 ++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/create-react-app/createReactApp.js b/packages/create-react-app/createReactApp.js index a2d9fdbd86b..c289f2d7cad 100755 --- a/packages/create-react-app/createReactApp.js +++ b/packages/create-react-app/createReactApp.js @@ -48,6 +48,7 @@ const unpack = require('tar-pack').unpack; const url = require('url'); const hyperquest = require('hyperquest'); const envinfo = require('envinfo'); +const os = require('os'); const packageJson = require('./package.json'); @@ -173,7 +174,7 @@ function createApp(name, verbose, version, useNpm, template) { }; fs.writeFileSync( path.join(root, 'package.json'), - JSON.stringify(packageJson, null, 2) + JSON.stringify(packageJson, null, 2) + os.EOL ); const useYarn = useNpm ? false : shouldUseYarn(); @@ -481,7 +482,10 @@ function getPackageName(installPackage) { ); } else if (installPackage.match(/^file:/)) { const installPackagePath = installPackage.match(/^file:(.*)?$/)[1]; - const installPackageJson = require(path.join(installPackagePath, 'package.json')); + const installPackageJson = require(path.join( + installPackagePath, + 'package.json' + )); return Promise.resolve(installPackageJson.name); } return Promise.resolve(installPackage); @@ -600,7 +604,7 @@ function setCaretRangeForRuntimeDeps(packageName) { makeCaretRange(packageJson.dependencies, 'react'); makeCaretRange(packageJson.dependencies, 'react-dom'); - fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2)); + fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + os.EOL); } // If project only contains files generated by GH, it’s safe. diff --git a/packages/react-dev-utils/browsersHelper.js b/packages/react-dev-utils/browsersHelper.js index 231ec853add..5b08b80d9f7 100644 --- a/packages/react-dev-utils/browsersHelper.js +++ b/packages/react-dev-utils/browsersHelper.js @@ -60,7 +60,7 @@ function checkBrowsers(dir, retry = true) { const pkg = JSON.parse(fs.readFileSync(filePath)); pkg['browserslist'] = defaultBrowsers; - fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + '\n'); + fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + os.EOL); }) .catch(() => checkBrowsers(dir, false)); } else { diff --git a/packages/react-scripts/scripts/eject.js b/packages/react-scripts/scripts/eject.js index c8438f5d156..558aa0b0b96 100644 --- a/packages/react-scripts/scripts/eject.js +++ b/packages/react-scripts/scripts/eject.js @@ -22,6 +22,7 @@ const paths = require('../config/paths'); const createJestConfig = require('./utils/createJestConfig'); const inquirer = require('react-dev-utils/inquirer'); const spawnSync = require('react-dev-utils/crossSpawn').sync; +const os = require('os'); const green = chalk.green; const cyan = chalk.cyan; @@ -218,7 +219,7 @@ inquirer fs.writeFileSync( path.join(appPath, 'package.json'), - JSON.stringify(appPackage, null, 2) + '\n' + JSON.stringify(appPackage, null, 2) + os.EOL ); console.log(); diff --git a/packages/react-scripts/scripts/init.js b/packages/react-scripts/scripts/init.js index ab1810423bb..38deea60259 100644 --- a/packages/react-scripts/scripts/init.js +++ b/packages/react-scripts/scripts/init.js @@ -19,6 +19,7 @@ const path = require('path'); const chalk = require('chalk'); const spawn = require('react-dev-utils/crossSpawn'); const { defaultBrowsers } = require('react-dev-utils/browsersHelper'); +const os = require('os'); module.exports = function( appPath, @@ -48,7 +49,7 @@ module.exports = function( fs.writeFileSync( path.join(appPath, 'package.json'), - JSON.stringify(appPackage, null, 2) + JSON.stringify(appPackage, null, 2) + os.EOL ); const readmeExists = fs.existsSync(path.join(appPath, 'README.md')); From 7c242c4a953129bd6b47d29f9c7d27ad31c7d41a Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 12:57:18 -0500 Subject: [PATCH 4/7] Ensure we re-check to prevent defaults from leaking --- packages/react-dev-utils/browsersHelper.js | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/react-dev-utils/browsersHelper.js b/packages/react-dev-utils/browsersHelper.js index 5b08b80d9f7..80faab3069a 100644 --- a/packages/react-dev-utils/browsersHelper.js +++ b/packages/react-dev-utils/browsersHelper.js @@ -52,17 +52,20 @@ function checkBrowsers(dir, retry = true) { }; return inquirer.prompt(question).then(answer => { if (answer.shouldSetBrowsers) { - return pkgUp(dir) - .then(filePath => { - if (filePath == null) { - return Promise.reject(); - } - - const pkg = JSON.parse(fs.readFileSync(filePath)); - pkg['browserslist'] = defaultBrowsers; - fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + os.EOL); - }) - .catch(() => checkBrowsers(dir, false)); + return ( + pkgUp(dir) + .then(filePath => { + if (filePath == null) { + return Promise.reject(); + } + const pkg = JSON.parse(fs.readFileSync(filePath)); + pkg['browserslist'] = defaultBrowsers; + fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + os.EOL); + }) + // Swallow any error + .catch(() => {}) + .then(() => checkBrowsers(dir, false)) + ); } else { return checkBrowsers(dir, false); } From d942a68e42a092e7592b490319234900bbf3c848 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 13:13:43 -0500 Subject: [PATCH 5/7] Reduce nesting --- packages/react-scripts/scripts/build.js | 110 ++++++++++++------------ packages/react-scripts/scripts/start.js | 73 ++++++++-------- 2 files changed, 92 insertions(+), 91 deletions(-) diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js index 1cb4fc00b49..e66f29d6a12 100644 --- a/packages/react-scripts/scripts/build.js +++ b/packages/react-scripts/scripts/build.js @@ -64,63 +64,63 @@ checkBrowsers(paths.appPath) // First, read the current file sizes in build directory. // This lets us display how much they changed later. 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')); - } + ) + .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('File sizes after gzip:\n'); + printFileSizesAfterBuild( + stats, + previousFileSizes, + paths.appBuild, + WARN_AFTER_BUNDLE_GZIP_SIZE, + WARN_AFTER_CHUNK_GZIP_SIZE + ); + console.log(); - const appPackage = require(paths.appPackageJson); - const publicUrl = paths.publicUrl; - const publicPath = config.output.publicPath; - const buildFolder = path.relative(process.cwd(), paths.appBuild); - printHostingInstructions( - appPackage, - publicUrl, - publicPath, - buildFolder, - useYarn - ); - printBrowsers(paths.appPath); - }, - err => { - console.log(chalk.red('Failed to compile.\n')); - printBuildError(err); - process.exit(1); - } - ) + const appPackage = require(paths.appPackageJson); + const publicUrl = paths.publicUrl; + const publicPath = config.output.publicPath; + const buildFolder = path.relative(process.cwd(), paths.appBuild); + printHostingInstructions( + appPackage, + publicUrl, + publicPath, + buildFolder, + useYarn + ); + printBrowsers(paths.appPath); + }, + err => { + console.log(chalk.red('Failed to compile.\n')); + printBuildError(err); + process.exit(1); + } ) .catch(err => { if (err && err.message) { diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index de8ef141fe9..83b0fde2af5 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -65,45 +65,46 @@ checkBrowsers(paths.appPath) .then(() => // We attempt to use the default port but if it is busy, we offer the user to // run on a different port. `choosePort()` Promise resolves to the next free port. - choosePort(HOST, DEFAULT_PORT).then(port => { - if (port == null) { - // We have not found a port. - return; + choosePort(HOST, DEFAULT_PORT) + ) + .then(port => { + if (port == null) { + // We have not found a port. + return; + } + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; + const appName = require(paths.appPackageJson).name; + const urls = prepareUrls(protocol, HOST, port); + // Create a webpack compiler that is configured with custom messages. + const compiler = createCompiler(webpack, config, appName, urls, useYarn); + // Load proxy config + const proxySetting = require(paths.appPackageJson).proxy; + const proxyConfig = prepareProxy(proxySetting, paths.appPublic); + // Serve webpack assets generated by the compiler over a web sever. + const serverConfig = createDevServerConfig( + proxyConfig, + urls.lanUrlForConfig + ); + const devServer = new WebpackDevServer(compiler, serverConfig); + // Launch WebpackDevServer. + devServer.listen(port, HOST, err => { + if (err) { + return console.log(err); } - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; - const appName = require(paths.appPackageJson).name; - const urls = prepareUrls(protocol, HOST, port); - // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler(webpack, config, appName, urls, useYarn); - // Load proxy config - const proxySetting = require(paths.appPackageJson).proxy; - const proxyConfig = prepareProxy(proxySetting, paths.appPublic); - // Serve webpack assets generated by the compiler over a web sever. - const serverConfig = createDevServerConfig( - proxyConfig, - urls.lanUrlForConfig - ); - const devServer = new WebpackDevServer(compiler, serverConfig); - // Launch WebpackDevServer. - devServer.listen(port, HOST, err => { - if (err) { - return console.log(err); - } - if (isInteractive) { - clearConsole(); - } - console.log(chalk.cyan('Starting the development server...\n')); - openBrowser(urls.localUrlForBrowser); - }); + if (isInteractive) { + clearConsole(); + } + console.log(chalk.cyan('Starting the development server...\n')); + openBrowser(urls.localUrlForBrowser); + }); - ['SIGINT', 'SIGTERM'].forEach(function(sig) { - process.on(sig, function() { - devServer.close(); - process.exit(); - }); + ['SIGINT', 'SIGTERM'].forEach(function(sig) { + process.on(sig, function() { + devServer.close(); + process.exit(); }); - }) - ) + }); + }) .catch(err => { if (err && err.message) { console.log(err.message); From 9910ec383832fd3406b54858e50d3a2905ed908a Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 13:20:57 -0500 Subject: [PATCH 6/7] Add defaults message --- packages/react-dev-utils/browsersHelper.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/react-dev-utils/browsersHelper.js b/packages/react-dev-utils/browsersHelper.js index 80faab3069a..02e46d3ecf5 100644 --- a/packages/react-dev-utils/browsersHelper.js +++ b/packages/react-dev-utils/browsersHelper.js @@ -61,6 +61,22 @@ function checkBrowsers(dir, retry = true) { const pkg = JSON.parse(fs.readFileSync(filePath)); pkg['browserslist'] = defaultBrowsers; fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + os.EOL); + + browserslist.clearCaches(); + console.log(); + console.log(chalk.green('Set target browsers:')); + console.log(); + console.log( + `\t${chalk.bold('Production')}: ${chalk.cyan( + defaultBrowsers.production.join(', ') + )}` + ); + console.log( + `\t${chalk.bold('Development')}: ${chalk.cyan( + defaultBrowsers.development.join(', ') + )}` + ); + console.log(); }) // Swallow any error .catch(() => {}) From 2dc7f9f42c4b7de836e467fee94499c805484f43 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 14 Jan 2018 13:53:32 -0500 Subject: [PATCH 7/7] More explicit --- packages/react-scripts/scripts/build.js | 6 +++--- packages/react-scripts/scripts/start.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-scripts/scripts/build.js b/packages/react-scripts/scripts/build.js index e66f29d6a12..cca5ff28313 100644 --- a/packages/react-scripts/scripts/build.js +++ b/packages/react-scripts/scripts/build.js @@ -60,11 +60,11 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { // browserslist defaults. const { checkBrowsers } = require('react-dev-utils/browsersHelper'); checkBrowsers(paths.appPath) - .then(() => + .then(() => { // First, read the current file sizes in build directory. // This lets us display how much they changed later. - measureFileSizesBeforeBuild(paths.appBuild) - ) + 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 diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 83b0fde2af5..e9c5b66ae40 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -62,11 +62,11 @@ const HOST = process.env.HOST || '0.0.0.0'; // browserslist defaults. const { checkBrowsers } = require('react-dev-utils/browsersHelper'); checkBrowsers(paths.appPath) - .then(() => + .then(() => { // We attempt to use the default port but if it is busy, we offer the user to // run on a different port. `choosePort()` Promise resolves to the next free port. - choosePort(HOST, DEFAULT_PORT) - ) + return choosePort(HOST, DEFAULT_PORT); + }) .then(port => { if (port == null) { // We have not found a port.