mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-05-17 19:52:15 +08:00
As a lot of [people](https://hackernoon.com/why-i-no-longer-use-typescript-with-react-and-why-you-shouldnt-either-e744d27452b4) is complaining about TypeScript performance in CRA, I decided to enable `async` mode in TypeScript checker. These changes basically brings the JS compilation times to TS projects. So, recompilation took less than 1 second instead of 3 seconds in medium size project. The problem with async mode is that type-errors are reported after Webpack ends up recompilation as TypeScript could be slower than Babel. PR allows to emit files compiled by Babel immediately and then wait for TS and show type errors in terminal later. Also, if there was no compilation errors and any type error occurs, we trigger a hot-reload with new errors to show error overlay in browser. Also, I wanted to start a discussion about `skipLibCheck: false` option in default `tsconfig.json`. This makes recompilations really slow and we should consider to set it to `true` or at least give users a big warning to let them know that it could be really slow. The following video is showing the updated workflow with a forced 2.5 second delay for type-check to give you an idea how it works.  I'm pretty sure that PR needs some polishing and improvements but it should works as it is. Especially a "hack" with reloading the browser after type-check looks ugly to me. cc @brunolemos as he is an initiator of an original TypeScript PR. Should fix https://github.com/facebook/create-react-app/issues/5820
149 lines
4.7 KiB
JavaScript
149 lines
4.7 KiB
JavaScript
// @remove-on-eject-begin
|
|
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
// @remove-on-eject-end
|
|
'use strict';
|
|
|
|
// Do this as the first thing so that any code reading it knows the right env.
|
|
process.env.BABEL_ENV = 'development';
|
|
process.env.NODE_ENV = 'development';
|
|
|
|
// 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;
|
|
});
|
|
|
|
// Ensure environment variables are read.
|
|
require('../config/env');
|
|
// @remove-on-eject-begin
|
|
// Do the preflight check (only happens before eject).
|
|
const verifyPackageTree = require('./utils/verifyPackageTree');
|
|
if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') {
|
|
verifyPackageTree();
|
|
}
|
|
const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup');
|
|
verifyTypeScriptSetup();
|
|
// @remove-on-eject-end
|
|
|
|
const fs = require('fs');
|
|
const chalk = require('react-dev-utils/chalk');
|
|
const webpack = require('webpack');
|
|
const WebpackDevServer = require('webpack-dev-server');
|
|
const clearConsole = require('react-dev-utils/clearConsole');
|
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
|
const {
|
|
choosePort,
|
|
createCompiler,
|
|
prepareProxy,
|
|
prepareUrls,
|
|
} = require('react-dev-utils/WebpackDevServerUtils');
|
|
const openBrowser = require('react-dev-utils/openBrowser');
|
|
const paths = require('../config/paths');
|
|
const configFactory = require('../config/webpack.config');
|
|
const createDevServerConfig = require('../config/webpackDevServer.config');
|
|
|
|
const useYarn = fs.existsSync(paths.yarnLockFile);
|
|
const isInteractive = process.stdout.isTTY;
|
|
|
|
// Warn and crash if required files are missing
|
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
|
process.exit(1);
|
|
}
|
|
|
|
// Tools like Cloud9 rely on this.
|
|
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
|
|
const HOST = process.env.HOST || '0.0.0.0';
|
|
|
|
if (process.env.HOST) {
|
|
console.log(
|
|
chalk.cyan(
|
|
`Attempting to bind to HOST environment variable: ${chalk.yellow(
|
|
chalk.bold(process.env.HOST)
|
|
)}`
|
|
)
|
|
);
|
|
console.log(
|
|
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
|
|
);
|
|
console.log(
|
|
`Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}`
|
|
);
|
|
console.log();
|
|
}
|
|
|
|
// We require that you explictly set browsers and do not fall back to
|
|
// browserslist defaults.
|
|
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
|
checkBrowsers(paths.appPath, isInteractive)
|
|
.then(() => {
|
|
// We attempt to use the default port but if it is busy, we offer the user to
|
|
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
|
return choosePort(HOST, DEFAULT_PORT);
|
|
})
|
|
.then(port => {
|
|
if (port == null) {
|
|
// We have not found a port.
|
|
return;
|
|
}
|
|
const config = configFactory('development');
|
|
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
|
const appName = require(paths.appPackageJson).name;
|
|
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
|
const urls = prepareUrls(protocol, HOST, port);
|
|
const devSocket = {
|
|
warnings: warnings =>
|
|
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
|
|
errors: errors =>
|
|
devServer.sockWrite(devServer.sockets, 'errors', errors),
|
|
};
|
|
// Create a webpack compiler that is configured with custom messages.
|
|
const compiler = createCompiler(
|
|
webpack,
|
|
config,
|
|
appName,
|
|
urls,
|
|
useYarn,
|
|
useTypeScript,
|
|
devSocket
|
|
);
|
|
// Load proxy config
|
|
const proxySetting = require(paths.appPackageJson).proxy;
|
|
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
|
|
// Serve webpack assets generated by the compiler over a web server.
|
|
const serverConfig = createDevServerConfig(
|
|
proxyConfig,
|
|
urls.lanUrlForConfig
|
|
);
|
|
const devServer = new WebpackDevServer(compiler, serverConfig);
|
|
// Launch WebpackDevServer.
|
|
devServer.listen(port, HOST, err => {
|
|
if (err) {
|
|
return console.log(err);
|
|
}
|
|
if (isInteractive) {
|
|
clearConsole();
|
|
}
|
|
console.log(chalk.cyan('Starting the development server...\n'));
|
|
openBrowser(urls.localUrlForBrowser);
|
|
});
|
|
|
|
['SIGINT', 'SIGTERM'].forEach(function(sig) {
|
|
process.on(sig, function() {
|
|
devServer.close();
|
|
process.exit();
|
|
});
|
|
});
|
|
})
|
|
.catch(err => {
|
|
if (err && err.message) {
|
|
console.log(err.message);
|
|
}
|
|
process.exit(1);
|
|
});
|