mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-04-24 05:05:53 +08:00
Speed up TypeScript v2 (#6406)
* Revert "Revert "Speed up TypeScript projects (#5903)""
This reverts commit 544a5943ce.
* Move fork-ts-checker dep to react-dev-utils
* Convert WebpackDevServerUtils.createCompiler to take in options arg
* Update README.md for react-dev-utils
This commit is contained in:
12
packages/react-dev-utils/ForkTsCheckerWebpackPlugin.js
vendored
Normal file
12
packages/react-dev-utils/ForkTsCheckerWebpackPlugin.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
|
||||
module.exports = ForkTsCheckerWebpackPlugin;
|
||||
@@ -325,9 +325,19 @@ printHostingInstructions(appPackage, publicUrl, publicPath, 'build', true);
|
||||
|
||||
Returns a Promise resolving to either `defaultPort` or next available port if the user confirms it is okay to do. If the port is taken and the user has refused to use another port, or if the terminal is not interactive and can’t present user with the choice, resolves to `null`.
|
||||
|
||||
##### `createCompiler(webpack: Function, config: Object, appName: string, urls: Object, useYarn: boolean): WebpackCompiler`
|
||||
##### `createCompiler(args: Object): WebpackCompiler`
|
||||
|
||||
Creates a Webpack compiler instance for WebpackDevServer with built-in helpful messages. Takes the `require('webpack')` entry point as the first argument. To provide the `urls` argument, use `prepareUrls()` described below.
|
||||
Creates a Webpack compiler instance for WebpackDevServer with built-in helpful messages.
|
||||
|
||||
The `args` object accepts a number of properties:
|
||||
|
||||
- **appName** `string`: The name that will be printed to the terminal.
|
||||
- **config** `Object`: The webpack configuration options to be provided to the webpack constructor.
|
||||
- **devSocket** `Object`: Required if `useTypeScript` is `true`. This object should include `errors` and `warnings` which are functions accepting an array of errors or warnings emitted by the type checking. This is useful when running `fork-ts-checker-webpack-plugin` with `async: true` to report errors that are emitted after the webpack build is complete.
|
||||
- **urls** `Object`: To provide the `urls` argument, use `prepareUrls()` described below.
|
||||
- **useYarn** `boolean`: If `true`, yarn instructions will be emitted in the terminal instead of npm.
|
||||
- **useTypeScript** `boolean`: If `true`, TypeScript type checking will be enabled. Be sure to provide the `devSocket` argument above if this is set to `true`.
|
||||
- **webpack** `function`: A reference to the webpack constructor.
|
||||
|
||||
##### `prepareProxy(proxySetting: string, appPublicFolder: string): Object`
|
||||
|
||||
|
||||
116
packages/react-dev-utils/WebpackDevServerUtils.js
vendored
116
packages/react-dev-utils/WebpackDevServerUtils.js
vendored
@@ -17,22 +17,10 @@ const inquirer = require('inquirer');
|
||||
const clearConsole = require('./clearConsole');
|
||||
const formatWebpackMessages = require('./formatWebpackMessages');
|
||||
const getProcessForPort = require('./getProcessForPort');
|
||||
const typescriptFormatter = require('./typescriptFormatter');
|
||||
const forkTsCheckerWebpackPlugin = require('./ForkTsCheckerWebpackPlugin');
|
||||
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
let handleCompile;
|
||||
|
||||
// You can safely remove this after ejecting.
|
||||
// We only use this block for testing of Create React App itself:
|
||||
const isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1);
|
||||
if (isSmokeTest) {
|
||||
handleCompile = (err, stats) => {
|
||||
if (err || stats.hasErrors() || stats.hasWarnings()) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function prepareUrls(protocol, host, port) {
|
||||
const formatUrl = hostname =>
|
||||
@@ -113,12 +101,20 @@ function printInstructions(appName, urls, useYarn) {
|
||||
console.log();
|
||||
}
|
||||
|
||||
function createCompiler(webpack, config, appName, urls, useYarn) {
|
||||
function createCompiler({
|
||||
appName,
|
||||
config,
|
||||
devSocket,
|
||||
urls,
|
||||
useYarn,
|
||||
useTypeScript,
|
||||
webpack,
|
||||
}) {
|
||||
// "Compiler" is a low-level interface to Webpack.
|
||||
// It lets us listen to some events and provide our own custom messages.
|
||||
let compiler;
|
||||
try {
|
||||
compiler = webpack(config, handleCompile);
|
||||
compiler = webpack(config);
|
||||
} catch (err) {
|
||||
console.log(chalk.red('Failed to compile.'));
|
||||
console.log();
|
||||
@@ -139,10 +135,35 @@ function createCompiler(webpack, config, appName, urls, useYarn) {
|
||||
});
|
||||
|
||||
let isFirstCompile = true;
|
||||
let tsMessagesPromise;
|
||||
let tsMessagesResolver;
|
||||
|
||||
if (useTypeScript) {
|
||||
compiler.hooks.beforeCompile.tap('beforeCompile', () => {
|
||||
tsMessagesPromise = new Promise(resolve => {
|
||||
tsMessagesResolver = msgs => resolve(msgs);
|
||||
});
|
||||
});
|
||||
|
||||
forkTsCheckerWebpackPlugin
|
||||
.getCompilerHooks(compiler)
|
||||
.receive.tap('afterTypeScriptCheck', (diagnostics, lints) => {
|
||||
const allMsgs = [...diagnostics, ...lints];
|
||||
const format = message =>
|
||||
`${message.file}\n${typescriptFormatter(message, true)}`;
|
||||
|
||||
tsMessagesResolver({
|
||||
errors: allMsgs.filter(msg => msg.severity === 'error').map(format),
|
||||
warnings: allMsgs
|
||||
.filter(msg => msg.severity === 'warning')
|
||||
.map(format),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// "done" event fires when Webpack has finished recompiling the bundle.
|
||||
// Whether or not you have warnings or errors, you will get this event.
|
||||
compiler.hooks.done.tap('done', stats => {
|
||||
compiler.hooks.done.tap('done', async stats => {
|
||||
if (isInteractive) {
|
||||
clearConsole();
|
||||
}
|
||||
@@ -152,9 +173,43 @@ function createCompiler(webpack, config, appName, urls, useYarn) {
|
||||
// them in a readable focused way.
|
||||
// We only construct the warnings and errors for speed:
|
||||
// https://github.com/facebook/create-react-app/issues/4492#issuecomment-421959548
|
||||
const messages = formatWebpackMessages(
|
||||
stats.toJson({ all: false, warnings: true, errors: true })
|
||||
);
|
||||
const statsData = stats.toJson({
|
||||
all: false,
|
||||
warnings: true,
|
||||
errors: true,
|
||||
});
|
||||
|
||||
if (useTypeScript && statsData.errors.length === 0) {
|
||||
const delayedMsg = setTimeout(() => {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Files successfully emitted, waiting for typecheck results...'
|
||||
)
|
||||
);
|
||||
}, 100);
|
||||
|
||||
const messages = await tsMessagesPromise;
|
||||
clearTimeout(delayedMsg);
|
||||
statsData.errors.push(...messages.errors);
|
||||
statsData.warnings.push(...messages.warnings);
|
||||
|
||||
// Push errors and warnings into compilation result
|
||||
// to show them after page refresh triggered by user.
|
||||
stats.compilation.errors.push(...messages.errors);
|
||||
stats.compilation.warnings.push(...messages.warnings);
|
||||
|
||||
if (messages.errors.length > 0) {
|
||||
devSocket.errors(messages.errors);
|
||||
} else if (messages.warnings.length > 0) {
|
||||
devSocket.warnings(messages.warnings);
|
||||
}
|
||||
|
||||
if (isInteractive) {
|
||||
clearConsole();
|
||||
}
|
||||
}
|
||||
|
||||
const messages = formatWebpackMessages(statsData);
|
||||
const isSuccessful = !messages.errors.length && !messages.warnings.length;
|
||||
if (isSuccessful) {
|
||||
console.log(chalk.green('Compiled successfully!'));
|
||||
@@ -194,6 +249,27 @@ function createCompiler(webpack, config, appName, urls, useYarn) {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// You can safely remove this after ejecting.
|
||||
// We only use this block for testing of Create React App itself:
|
||||
const isSmokeTest = process.argv.some(
|
||||
arg => arg.indexOf('--smoke-test') > -1
|
||||
);
|
||||
if (isSmokeTest) {
|
||||
compiler.hooks.failed.tap('smokeTest', async () => {
|
||||
await tsMessagesPromise;
|
||||
process.exit(1);
|
||||
});
|
||||
compiler.hooks.done.tap('smokeTest', async stats => {
|
||||
await tsMessagesPromise;
|
||||
if (stats.hasErrors() || stats.hasWarnings()) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return compiler;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"url": "https://github.com/facebook/create-react-app/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
"node": ">=8.10"
|
||||
},
|
||||
"files": [
|
||||
"browsersHelper.js",
|
||||
@@ -20,6 +20,7 @@
|
||||
"eslintFormatter.js",
|
||||
"evalSourceMapMiddleware.js",
|
||||
"FileSizeReporter.js",
|
||||
"ForkTsCheckerWebpackPlugin.js",
|
||||
"formatWebpackMessages.js",
|
||||
"getCacheIdentifier.js",
|
||||
"getCSSModuleLocalIdent.js",
|
||||
@@ -54,6 +55,7 @@
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"filesize": "3.6.1",
|
||||
"find-up": "3.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "1.0.0-alpha.6",
|
||||
"global-modules": "2.0.0",
|
||||
"globby": "8.0.2",
|
||||
"gzip-size": "5.0.0",
|
||||
|
||||
@@ -45,12 +45,15 @@ function formatter(message, useColors) {
|
||||
}
|
||||
|
||||
const severity = hasGetters ? message.getSeverity() : message.severity;
|
||||
const types = { diagnostic: 'TypeScript', lint: 'TSLint' };
|
||||
|
||||
return [
|
||||
messageColor.bold(`Type ${severity.toLowerCase()}: `) +
|
||||
messageColor.bold(`${types[message.type]} ${severity.toLowerCase()}: `) +
|
||||
(hasGetters ? message.getContent() : message.content) +
|
||||
' ' +
|
||||
messageColor.underline(`TS${message.code}`),
|
||||
messageColor.underline(
|
||||
(message.type === 'lint' ? 'Rule: ' : 'TS') + message.code
|
||||
),
|
||||
'',
|
||||
frame,
|
||||
].join(os.EOL);
|
||||
|
||||
18
packages/react-dev-utils/webpackHotDevClient.js
vendored
18
packages/react-dev-utils/webpackHotDevClient.js
vendored
@@ -106,7 +106,7 @@ function handleSuccess() {
|
||||
tryApplyUpdates(function onHotUpdateSuccess() {
|
||||
// Only dismiss it when we're sure it's a hot update.
|
||||
// Otherwise it would flicker right before the reload.
|
||||
ErrorOverlay.dismissBuildError();
|
||||
tryDismissErrorOverlay();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -140,19 +140,15 @@ function handleWarnings(warnings) {
|
||||
}
|
||||
}
|
||||
|
||||
printWarnings();
|
||||
|
||||
// Attempt to apply hot updates or reload.
|
||||
if (isHotUpdate) {
|
||||
tryApplyUpdates(function onSuccessfulHotUpdate() {
|
||||
// Only print warnings if we aren't refreshing the page.
|
||||
// Otherwise they'll disappear right away anyway.
|
||||
printWarnings();
|
||||
// Only dismiss it when we're sure it's a hot update.
|
||||
// Otherwise it would flicker right before the reload.
|
||||
ErrorOverlay.dismissBuildError();
|
||||
tryDismissErrorOverlay();
|
||||
});
|
||||
} else {
|
||||
// Print initial warnings immediately.
|
||||
printWarnings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +179,12 @@ function handleErrors(errors) {
|
||||
// We will reload on next success instead.
|
||||
}
|
||||
|
||||
function tryDismissErrorOverlay() {
|
||||
if (!hasCompileErrors) {
|
||||
ErrorOverlay.dismissBuildError();
|
||||
}
|
||||
}
|
||||
|
||||
// There is a newer version of the code available.
|
||||
function handleAvailableHash(hash) {
|
||||
// Update last known compilation hash.
|
||||
|
||||
Reference in New Issue
Block a user