Skip to content

Commit

Permalink
add logging of existing default port process on start (#816)
Browse files Browse the repository at this point in the history
* add logging of existing port process on start

* Move port process wording in start command on to next line

* Color the named processes as cyan in terminal output

* Add handling for multiple processes on a part

- With the currently process filtering, if multiple processes are returned as running on port 3000, this command would fail. This splits apart the process IDing and the process naming, to support multiple processes.
- One curious thing about the bash command to get processes, is that it'll include browsers with a window open on localhost:3000. May want to reconsider that.

* Add process directory to existing port warning

- also moved terminal coloring up, when getting the process, to be able to distinguish the process command from the directory

* Change output color to all cyan, except "in"

* Rename getProcessNameOnPort -> getProcessForPort

- better reflects its broadened scope (both command and directory)

* Add checking if process is a CRA instance, to customize port running message

- moved from using package.json to a regex, for reliability

* Move getProcessForPort to react-dev-utils

- also allowed for breakdown of commands into helper methods

* Add documentation for getProcessForPort

* Add getProcessForPort to list of dev-scripts files

* Use app's package name when CRA app is running on another port

* Filter port process by those listening

- Removed the handling of multiple process IDs since you can filtering by listening process (and not have the browser in the list of processes)
- Trimmed the terminal outputs for better matching (process id) and better terminal output (directory of process)

* Update README on port helpers, to specify only one port returned

* Add ignore of stderr when executing process commands

- Make sure any potential errors don't leak to the user
  • Loading branch information
ianmcnally authored and fson committed Nov 22, 2016
1 parent 9c45b25 commit 05c3b55
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
16 changes: 16 additions & 0 deletions packages/react-dev-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,22 @@ compiler.plugin('done', function(stats) {
});
```

#### `getProcessForPort(port: number): string`

Finds the currently running process on `port`.
Returns a string containing the name and directory, e.g.,

```
create-react-app
in /Users/developer/create-react-app
```

```js
var getProcessForPort = require('react-dev-utils/getProcessForPort');

getProcessForPort(3000);
```

#### `openBrowser(url: string): boolean`

Attempts to open the browser with a given URL.
Expand Down
61 changes: 61 additions & 0 deletions packages/react-dev-utils/getProcessForPort.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var chalk = require('chalk');
var execSync = require('child_process').execSync;
var path = require('path');

var execOptions = {
encoding: 'utf8',
stdio: [
'pipe', // stdin (default)
'pipe', // stdout (default)
'ignore' //stderr
]
};

function isProcessAReactApp(processCommand) {
return /^node .*react-scripts\/scripts\/start\.js\s?$/.test(processCommand);
}

function getProcessIdOnPort(port) {
return execSync('lsof -i:' + port + ' -P -t -sTCP:LISTEN', execOptions).trim();
}

function getPackageNameInDirectory(directory) {
var packagePath = path.join(directory.trim(), 'package.json');

try {
return require(packagePath).name;
} catch(e) {
return null;
}

}

function getProcessCommand(processId, processDirectory) {
var command = execSync('ps -o command -p ' + processId + ' | sed -n 2p', execOptions);

if (isProcessAReactApp(command)) {
const packageName = getPackageNameInDirectory(processDirectory);
return (packageName) ? packageName + '\n' : command;
} else {
return command;
}

}

function getDirectoryOfProcessById(processId) {
return execSync('lsof -p '+ processId + ' | grep cwd | awk \'{print $9}\'', execOptions).trim();
}

function getProcessForPort(port) {
try {
var processId = getProcessIdOnPort(port);
var directory = getDirectoryOfProcessById(processId);
var command = getProcessCommand(processId, directory);
return chalk.cyan(command) + chalk.blue(' in ') + chalk.cyan(directory);
} catch(e) {
return null;
}
}

module.exports = getProcessForPort;

1 change: 1 addition & 0 deletions packages/react-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"clearConsole.js",
"checkRequiredFiles.js",
"formatWebpackMessages.js",
"getProcessForPort.js",
"InterpolateHtmlPlugin.js",
"openChrome.applescript",
"openBrowser.js",
Expand Down
7 changes: 5 additions & 2 deletions packages/react-scripts/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var detect = require('detect-port');
var clearConsole = require('react-dev-utils/clearConsole');
var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
var getProcessForPort = require('react-dev-utils/getProcessForPort');
var openBrowser = require('react-dev-utils/openBrowser');
var prompt = require('react-dev-utils/prompt');
var pathExists = require('path-exists');
Expand Down Expand Up @@ -273,9 +274,11 @@ detect(DEFAULT_PORT).then(port => {
}

clearConsole();
var existingProcess = getProcessForPort(DEFAULT_PORT);
var question =
chalk.yellow('Something is already running on port ' + DEFAULT_PORT + '.') +
'\n\nWould you like to run the app on another port instead?';
chalk.yellow('Something is already running on port ' + DEFAULT_PORT + '.' +
((existingProcess) ? ' Probably:\n ' + existingProcess : '')) +
'\n\nWould you like to run the app on another port instead?';

prompt(question, true).then(shouldChangePort => {
if (shouldChangePort) {
Expand Down

0 comments on commit 05c3b55

Please sign in to comment.