diff --git a/packages/react-dev-utils/openBrowser.js b/packages/react-dev-utils/openBrowser.js index 8c97f723c4fc67cf1d7a8f875537af9dfffa4fec..15b7ad360a507c571dc6ed3f0789dd45ef8744cf 100644 --- a/packages/react-dev-utils/openBrowser.js +++ b/packages/react-dev-utils/openBrowser.js @@ -9,23 +9,61 @@ 'use strict'; +var chalk = require('chalk'); var execSync = require('child_process').execSync; +var spawn = require('cross-spawn'); var opn = require('opn'); // https://github.com/sindresorhus/opn#app var OSX_CHROME = 'google chrome'; -function openBrowser(url) { +const Actions = Object.freeze({ + NONE: 0, + BROWSER: 1, + SCRIPT: 2, +}); + +function getBrowserEnv() { // Attempt to honor this environment variable. // It is specific to the operating system. // See https://github.com/sindresorhus/opn#app for documentation. - var browser = process.env.BROWSER; - - // Special case: BROWSER="none" will prevent opening completely. - if (browser === 'none') { - return false; + const value = process.env.BROWSER; + let action; + if (!value) { + // Default. + action = Actions.BROWSER; + } else if (value.toLowerCase().endsWith('.js')) { + action = Actions.SCRIPT; + } else if (value.toLowerCase() === 'none') { + action = Actions.NONE; + } else { + action = Actions.BROWSER; } + return { action, value }; +} + +function executeNodeScript(scriptPath, url) { + const extraArgs = process.argv.slice(2); + const child = spawn('node', [scriptPath, ...extraArgs, url], { + stdio: 'inherit', + }); + child.on('close', code => { + if (code !== 0) { + console.log(); + console.log( + chalk.red( + 'The script specified as BROWSER environment variable failed.' + ) + ); + console.log(chalk.cyan(scriptPath) + ' exited with code ' + code + '.'); + console.log(); + return; + } + }); + return true; +} +function startBrowserProcess(browser, url) { // If we're on OS X, the user hasn't specifically // requested a different browser, we can try opening // Chrome with AppleScript. This lets us reuse an @@ -67,4 +105,23 @@ function openBrowser(url) { } } +/** + * Reads the BROWSER evironment variable and decides what to do with it. Returns + * true if it opened a browser or ran a node.js script, otherwise false. + */ +function openBrowser(url) { + const { action, value } = getBrowserEnv(); + switch (action) { + case Actions.NONE: + // Special case: BROWSER="none" will prevent opening completely. + return false; + case Actions.SCRIPT: + return executeNodeScript(value, url); + case Actions.BROWSER: + return startBrowserProcess(value, url); + default: + throw new Error('Not implemented.'); + } +} + module.exports = openBrowser; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index a5d4c75fe78a56e72d2b4fb3265ae269d117fc92..b33f200a09243421dd7117eaa1a5f6ce6098ba97 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -32,6 +32,7 @@ "anser": "1.1.0", "babel-code-frame": "6.20.0", "chalk": "1.1.3", + "cross-spawn": "4.0.2", "escape-string-regexp": "1.0.5", "filesize": "3.3.0", "gzip-size": "3.0.0", diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index f987de2f9ae8b37b66de4a68a0191ff00dfc553f..c178e573816ffdf6b1cc6f67f34f0daff3f5cdeb 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -1560,7 +1560,7 @@ You can adjust various development and production settings by setting environmen Variable | Development | Production | Usage :--- | :---: | :---: | :--- -BROWSER | :white_check_mark: | :x: | By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a [browser](https://github.com/sindresorhus/opn#app) to override this behavior, or set it to `none` to disable it completely. +BROWSER | :white_check_mark: | :x: | By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a [browser](https://github.com/sindresorhus/opn#app) to override this behavior, or set it to `none` to disable it completely. <!-- TODO: enable with 0.10: If you need to customize the way the browser is launched, you can specify a node script instead. Any arguments passed to `npm start` will also be passed to this script, and the url where your app is served will be the last argument. Your script's file name must have the `.js` extension. --> HOST | :white_check_mark: | :x: | By default, the development web server binds to `localhost`. You may use this variable to specify a different host. PORT | :white_check_mark: | :x: | By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port. HTTPS | :white_check_mark: | :x: | When set to `true`, Create React App will run the development server in `https` mode.