123 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) 2015-present, Facebook, Inc.
 | |
|  *
 | |
|  * This source code is licensed under the MIT license found in the
 | |
|  * LICENSE file at
 | |
|  * https://github.com/facebook/create-react-app/blob/master/LICENSE
 | |
|  */
 | |
| 
 | |
| const open = require('open')
 | |
| const execa = require('execa')
 | |
| const chalk = require('chalk')
 | |
| const execSync = require('child_process').execSync
 | |
| 
 | |
| // https://github.com/sindresorhus/open#app
 | |
| const OSX_CHROME = 'google chrome'
 | |
| 
 | |
| 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/open#app for documentation.
 | |
|   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 = execa('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 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
 | |
|   // existing tab when possible instead of creating a new one.
 | |
|   const shouldTryOpenChromeWithAppleScript =
 | |
|     process.platform === 'darwin' &&
 | |
|     (typeof browser !== 'string' || browser === OSX_CHROME)
 | |
| 
 | |
|   if (shouldTryOpenChromeWithAppleScript) {
 | |
|     try {
 | |
|       // Try our best to reuse existing tab
 | |
|       // on OS X Google Chrome with AppleScript
 | |
|       execSync('ps cax | grep "Google Chrome"')
 | |
|       execSync('osascript openChrome.applescript "' + encodeURI(url) + '"', {
 | |
|         cwd: __dirname,
 | |
|         stdio: 'ignore'
 | |
|       })
 | |
|       return true
 | |
|     } catch (err) {
 | |
|       // Ignore errors.
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Another special case: on OS X, check if BROWSER has been set to "open".
 | |
|   // In this case, instead of passing the string `open` to `open` function (which won't work),
 | |
|   // just ignore it (thus ensuring the intended behavior, i.e. opening the system browser):
 | |
|   // https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768
 | |
|   if (process.platform === 'darwin' && browser === 'open') {
 | |
|     browser = undefined
 | |
|   }
 | |
| 
 | |
|   // Fallback to open
 | |
|   // (It will always open new tab)
 | |
|   try {
 | |
|     const options = { app: { name: browser }, url: true }
 | |
|     open(url, options).catch(() => {}) // Prevent `unhandledRejection` error.
 | |
|     return true
 | |
|   } catch (err) {
 | |
|     return false
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Reads the BROWSER environment variable and decides what to do with it. Returns
 | |
|  * true if it opened a browser or ran a node.js script, otherwise false.
 | |
|  */
 | |
| exports.openBrowser = function (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.')
 | |
|   }
 | |
| }
 |