start.js 5.27 KB
Newer Older
1
// @remove-on-eject-begin
Christopher Chedeau's avatar
Christopher Chedeau committed
2
3
4
5
6
7
8
9
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
10
// @remove-on-eject-end
11
12
'use strict';

13
14
15
16
17
18
19
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

20
21
process.env.NODE_ENV = 'development';

22
23
// Ensure environment variables are read.
require('../config/env');
24

25
const address = require('address');
26
27
const fs = require('fs');
const chalk = require('chalk');
28
const detect = require('@timer/detect-port');
29
30
31
32
33
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const getProcessForPort = require('react-dev-utils/getProcessForPort');
const openBrowser = require('react-dev-utils/openBrowser');
34
const inquirer = require('inquirer');
35
36
37
38
const paths = require('../config/paths');
const config = require('../config/webpack.config.dev');
const devServerConfig = require('../config/webpackDevServer.config');
const createWebpackCompiler = require('./utils/createWebpackCompiler');
39
const prepareProxy = require('react-dev-utils/prepareProxy');
Joe Haddad's avatar
Joe Haddad committed
40
const url = require('url');
41
42
43
44

const useYarn = fs.existsSync(paths.yarnLockFile);
const cli = useYarn ? 'yarn' : 'npm';
const isInteractive = process.stdout.isTTY;
Ville Immonen's avatar
Ville Immonen committed
45

46
47
48
49
50
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
  process.exit(1);
}

51
// Tools like Cloud9 rely on this.
52
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
53
const HOST = process.env.HOST || '0.0.0.0';
54

Daniel Grant's avatar
Daniel Grant committed
55
function run(port) {
56
  const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
57

58
59
60
61
62
63
64
65
66
67
68
69
  const formatUrl = hostname => url.format({
    protocol,
    hostname,
    port,
    pathname: '/',
  });
  const prettyPrintUrl = hostname => url.format({
    protocol,
    hostname,
    port: chalk.bold(port),
    pathname: '/',
  });
70
71

  const isUnspecifiedAddress = HOST === '0.0.0.0' || HOST === '::';
72
  let prettyHost, lanAddress, prettyLanUrl;
73
  if (isUnspecifiedAddress) {
74
    prettyHost = 'localhost';
75
76
    try {
      lanAddress = address.ip();
77
78
79
      if (lanAddress) {
        prettyLanUrl = prettyPrintUrl(lanAddress);
      }
80
81
82
    } catch (_e) {
      // ignored
    }
83
84
85
  } else {
    prettyHost = HOST;
  }
86
  const prettyLocalUrl = prettyPrintUrl(prettyHost);
87

Daniel Grant's avatar
Daniel Grant committed
88
  // Create a webpack compiler that is configured with custom messages.
89
90
91
92
93
94
95
  const compiler = createWebpackCompiler(
    config,
    function onReady(showInstructions) {
      if (!showInstructions) {
        return;
      }
      console.log();
96
97
98
      console.log(
        `You can now view ${chalk.bold(require(paths.appPackageJson).name)} in the browser.`
      );
99
      console.log();
100

101
102
103
      if (prettyLanUrl) {
        console.log(`  ${chalk.bold('Local:')}            ${prettyLocalUrl}`);
        console.log(`  ${chalk.bold('On Your Network:')}  ${prettyLanUrl}`);
104
      } else {
105
        console.log(`  ${prettyLocalUrl}`);
106
107
      }

108
109
110
111
112
113
      console.log();
      console.log('Note that the development build is not optimized.');
      console.log(
        `To create a production build, use ${chalk.cyan(`${cli} run build`)}.`
      );
      console.log();
114
    }
115
  );
116

117
118
  // Load proxy config
  const proxy = require(paths.appPackageJson).proxy;
Daniel Grant's avatar
Daniel Grant committed
119
  // Serve webpack assets generated by the compiler over a web sever.
120
121
  const devServer = new WebpackDevServer(
    compiler,
122
    devServerConfig(prepareProxy(proxy), lanAddress)
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  );

  // Launch WebpackDevServer.
  devServer.listen(port, HOST, err => {
    if (err) {
      return console.log(err);
    }

    if (isInteractive) {
      clearConsole();
    }
    console.log(chalk.cyan('Starting the development server...'));
    console.log();

137
    openBrowser(formatUrl(prettyHost));
138
  });
139
140
}

141
142
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `detect()` Promise resolves to the next free port.
143
144
145
146
147
148
detect(DEFAULT_PORT, HOST).then(
  port => {
    if (port === DEFAULT_PORT) {
      run(port);
      return;
    }
Christopher Chedeau's avatar
.    
Christopher Chedeau committed
149

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    if (isInteractive) {
      clearConsole();
      const existingProcess = getProcessForPort(DEFAULT_PORT);
      const question = {
        type: 'confirm',
        name: 'shouldChangePort',
        message: 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?',
        default: true,
      };

      inquirer.prompt(question).then(answer => {
        if (answer.shouldChangePort) {
          run(port);
        }
      });
    } else {
      console.log(
        chalk.red(`Something is already running on port ${DEFAULT_PORT}.`)
      );
    }
  },
  err => {
175
    console.log(
176
      chalk.red(`Could not find an open port at ${chalk.bold(HOST)}.`)
177
    );
178
179
    console.log('Network error message: ' + err.message || err);
    console.log();
180
  }
181
);