From 04adf672da38087f0ef07c72a865b751b2cd41de Mon Sep 17 00:00:00 2001 From: Gabriel Aumala Date: Sun, 19 Feb 2017 20:36:31 -0500 Subject: [PATCH 1/4] Support node scripts in BROWSER Modify OpenBrowser.js to run node scripts specified with the BROWSER environment variable . If the value of the BROWSER environment variable ends with '.js' a child process is spawned to execute the script with node.js. Any arguments passed to npm start are also passed to this script, as well as the url where the app is served. The command executed in the child process is: node [OPTIONS] Update User Guide. --- packages/react-dev-utils/openBrowser.js | 74 +++++++++++++++++++++-- packages/react-dev-utils/package.json | 1 + packages/react-scripts/template/README.md | 2 +- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/packages/react-dev-utils/openBrowser.js b/packages/react-dev-utils/openBrowser.js index 8c97f723c4f..4c7cc76a0a9 100644 --- a/packages/react-dev-utils/openBrowser.js +++ b/packages/react-dev-utils/openBrowser.js @@ -10,22 +10,61 @@ 'use strict'; 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) { + +/** + * Use an enum for the possible uses of the BROWSER environment variable + * 'browser': open a browser specified by the user. if value is not specified, + * use the system's default browser. + * 'browser': open a browser. + * 'none': Don't open anything. + * 'script': run a node.js script. + * + */ +const BROWSER_TYPES = Object.freeze({ + 'browser': 0, + 'none': 1, + 'script': 2, +}) + +/** + * Returns an object with the BROWSER environment variable's value and type + */ +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; + const browserStr = process.env.BROWSER; + const result = { value: browserStr } + if (!browserStr) + result.type = BROWSER_TYPES.browser; + else if (browserStr && browserStr.endsWith('.js')) + result.type = BROWSER_TYPES.script; + else if (browserStr.toLowerCase() === 'none') + result.type = BROWSER_TYPES.none; + else + result.type = BROWSER_TYPES.browser; + return result +} - // Special case: BROWSER="none" will prevent opening completely. - if (browser === 'none') { - return false; - } +/** + * spawns a new child process to execute a node.js script + */ +function executeNodeScript(scriptPath, url) { + const extraArgs = process.argv.slice(2); + const args = [scriptPath] + .concat(extraArgs) // add any extra flags + .concat(url); // add url last + spawn('node', args); + 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 +106,27 @@ 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 browser = getBrowserEnv(); + + switch (browser.type) { + case BROWSER_TYPES.none: + // Special case: BROWSER="none" will prevent opening completely. + return false; + case BROWSER_TYPES.script: + return executeNodeScript(browser.value, url); + case BROWSER_TYPES.browser: { + return startBrowserProcess(browser.value, url); + } + default: { + throw new Error('Unknown Browser Type: ' + browser.type); + } + } + +} + module.exports = openBrowser; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index 8fe7f53b37c..b5fedc251fe 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -29,6 +29,7 @@ "anser": "1.1.0", "babel-code-frame": "6.20.0", "chalk": "1.1.3", + "cross-spawn": "^4.0.0", "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 1c781cbe975..4d17e77cfa8 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -1551,7 +1551,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. 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. From 16b97279c8036441d36292da524480e22fa6ea8c Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 16 May 2017 00:20:47 +0100 Subject: [PATCH 2/4] Tweak code style --- packages/react-dev-utils/openBrowser.js | 93 ++++++++++++------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/packages/react-dev-utils/openBrowser.js b/packages/react-dev-utils/openBrowser.js index 4c7cc76a0a9..15b7ad360a5 100644 --- a/packages/react-dev-utils/openBrowser.js +++ b/packages/react-dev-utils/openBrowser.js @@ -9,6 +9,7 @@ 'use strict'; +var chalk = require('chalk'); var execSync = require('child_process').execSync; var spawn = require('cross-spawn'); var opn = require('opn'); @@ -16,51 +17,49 @@ var opn = require('opn'); // https://github.com/sindresorhus/opn#app var OSX_CHROME = 'google chrome'; +const Actions = Object.freeze({ + NONE: 0, + BROWSER: 1, + SCRIPT: 2, +}); -/** - * Use an enum for the possible uses of the BROWSER environment variable - * 'browser': open a browser specified by the user. if value is not specified, - * use the system's default browser. - * 'browser': open a browser. - * 'none': Don't open anything. - * 'script': run a node.js script. - * - */ -const BROWSER_TYPES = Object.freeze({ - 'browser': 0, - 'none': 1, - 'script': 2, -}) - -/** - * Returns an object with the BROWSER environment variable's value and type - */ function getBrowserEnv() { // Attempt to honor this environment variable. // It is specific to the operating system. // See https://github.com/sindresorhus/opn#app for documentation. - const browserStr = process.env.BROWSER; - const result = { value: browserStr } - if (!browserStr) - result.type = BROWSER_TYPES.browser; - else if (browserStr && browserStr.endsWith('.js')) - result.type = BROWSER_TYPES.script; - else if (browserStr.toLowerCase() === 'none') - result.type = BROWSER_TYPES.none; - else - result.type = BROWSER_TYPES.browser; - return result + 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 }; } -/** - * spawns a new child process to execute a node.js script - */ function executeNodeScript(scriptPath, url) { const extraArgs = process.argv.slice(2); - const args = [scriptPath] - .concat(extraArgs) // add any extra flags - .concat(url); // add url last - spawn('node', args); + 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; } @@ -111,22 +110,18 @@ function startBrowserProcess(browser, url) { * true if it opened a browser or ran a node.js script, otherwise false. */ function openBrowser(url) { - const browser = getBrowserEnv(); - - switch (browser.type) { - case BROWSER_TYPES.none: + const { action, value } = getBrowserEnv(); + switch (action) { + case Actions.NONE: // Special case: BROWSER="none" will prevent opening completely. return false; - case BROWSER_TYPES.script: - return executeNodeScript(browser.value, url); - case BROWSER_TYPES.browser: { - return startBrowserProcess(browser.value, url); - } - default: { - throw new Error('Unknown Browser Type: ' + browser.type); - } + case Actions.SCRIPT: + return executeNodeScript(value, url); + case Actions.BROWSER: + return startBrowserProcess(value, url); + default: + throw new Error('Not implemented.'); } - } module.exports = openBrowser; From 9a9ac1c64251c4d6f9816f29f8aeeb4a70ca9975 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 16 May 2017 00:23:52 +0100 Subject: [PATCH 3/4] Pin dep --- packages/react-dev-utils/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index b5fedc251fe..f3ebf8f8282 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -29,7 +29,7 @@ "anser": "1.1.0", "babel-code-frame": "6.20.0", "chalk": "1.1.3", - "cross-spawn": "^4.0.0", + "cross-spawn": "4.0.2", "escape-string-regexp": "1.0.5", "filesize": "3.3.0", "gzip-size": "3.0.0", From b9807d3230d17af3bc0534bd292574d659f9fc9f Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 16 May 2017 00:24:47 +0100 Subject: [PATCH 4/4] Comment out 0.10 docs --- packages/react-scripts/template/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index 4d17e77cfa8..84382d9d3ad 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -1551,7 +1551,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. 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. +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. 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.