Skip to content
This repository was archived by the owner on Mar 25, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions packages/cra-template-typescript/template/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
6 changes: 0 additions & 6 deletions packages/cra-template/template/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
6 changes: 1 addition & 5 deletions packages/react-dev-utils/FileSizeReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ var stripAnsi = require('strip-ansi');
var gzipSize = require('gzip-size').sync;

function canReadAsset(asset) {
return (
/\.(js|css)$/.test(asset) &&
!/service-worker\.js/.test(asset) &&
!/precache-manifest\.[0-9a-f]+\.js/.test(asset)
);
return /\.(js|css)$/.test(asset);
}

// Prints a detailed summary of build files.
Expand Down
84 changes: 52 additions & 32 deletions packages/react-dev-utils/WebpackDevServerUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ function createCompiler({
}) {
// "Compiler" is a low-level interface to webpack.
// It lets us listen to some events and provide our own custom messages.
let compiler;
let masterCompiler;
try {
compiler = webpack(config);
masterCompiler = webpack(config);
} catch (err) {
console.log(chalk.red('Failed to compile.'));
console.log();
Expand All @@ -128,47 +128,60 @@ function createCompiler({
// recompiling a bundle. WebpackDevServer takes care to pause serving the
// bundle, so if you refresh, it'll wait instead of serving the old one.
// "invalid" is short for "bundle invalidated", it doesn't imply any errors.
compiler.hooks.invalid.tap('invalid', () => {
masterCompiler.hooks.invalid.tap('invalid', () => {
if (isInteractive) {
clearConsole();
}
console.log('Compiling...');
});

let isFirstCompile = true;
let tsMessagesPromise;
let tsMessagesResolver;

if (useTypeScript) {
compiler.hooks.beforeCompile.tap('beforeCompile', () => {
tsMessagesPromise = new Promise(resolve => {
tsMessagesResolver = msgs => resolve(msgs);
let tsMessagesPromises = [];

masterCompiler.compilers.forEach((compiler, compilerIndex) => {
let tsMessagesResolver;
if (useTypeScript) {
compiler.hooks.beforeCompile.tap('beforeCompile', () => {
tsMessagesPromises[compilerIndex] = 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),
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', async stats => {
masterCompiler.hooks.done.tap('done', async stats => {
if (isInteractive) {
clearConsole();
}

stats.compilation = {
errors: stats.stats.reduce(
(previousErrors, s) => [...previousErrors, ...s.compilation.errors],
[]
),
warnings: stats.stats.reduce(
(previousErrors, s) => [...previousErrors, ...s.compilation.warnings],
[]
),
};

// We have switched off the default webpack output in WebpackDevServer
// options so we are going to "massage" the warnings and errors and present
// them in a readable focused way.
Expand All @@ -189,7 +202,14 @@ function createCompiler({
);
}, 100);

const messages = await tsMessagesPromise;
const masterMessages = await Promise.all(tsMessagesPromises);
const messages = masterMessages.reduce(
(previousMessages, currentMessages) => ({
errors: [...previousMessages.errors, ...currentMessages.errors],
warnings: [...previousMessages.warnings, ...currentMessages.warnings],
}),
{ errors: [], warnings: [] }
);
clearTimeout(delayedMsg);
if (tscCompileOnError) {
statsData.warnings.push(...messages.errors);
Expand Down Expand Up @@ -269,12 +289,12 @@ function createCompiler({
arg => arg.indexOf('--smoke-test') > -1
);
if (isSmokeTest) {
compiler.hooks.failed.tap('smokeTest', async () => {
await tsMessagesPromise;
masterCompiler.hooks.failed.tap('smokeTest', async () => {
await Promise.all(tsMessagesPromises);
process.exit(1);
});
compiler.hooks.done.tap('smokeTest', async stats => {
await tsMessagesPromise;
masterCompiler.hooks.done.tap('smokeTest', async stats => {
await Promise.all(tsMessagesPromises);
if (stats.hasErrors() || stats.hasWarnings()) {
process.exit(1);
} else {
Expand All @@ -283,7 +303,7 @@ function createCompiler({
});
}

return compiler;
return masterCompiler;
}

function resolveLoopback(proxy) {
Expand Down
4 changes: 2 additions & 2 deletions packages/react-dev-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-dev-utils",
"version": "10.2.1",
"name": "@ouihelp/react-dev-utils",
"version": "10020001.0.2",
"description": "webpack utilities used by Create React App",
"repository": {
"type": "git",
Expand Down
6 changes: 6 additions & 0 deletions packages/react-scripts/config/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ module.exports = {
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appServiceWorkerJs: resolveModule(resolveApp, 'src/service-worker.entry'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
Expand All @@ -86,6 +87,7 @@ module.exports = {
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appServiceWorkerJs: resolveModule(resolveApp, 'src/service-worker.entry'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
Expand Down Expand Up @@ -121,6 +123,10 @@ if (
appPublic: resolveOwn(`${templatePath}/public`),
appHtml: resolveOwn(`${templatePath}/public/index.html`),
appIndexJs: resolveModule(resolveOwn, `${templatePath}/src/index`),
appServiceWorkerJs: resolveModule(
resolveOwn,
`${templatePath}/src/service-worker.entry`
),
appPackageJson: resolveOwn('package.json'),
appSrc: resolveOwn(`${templatePath}/src`),
appTsConfig: resolveOwn(`${templatePath}/tsconfig.json`),
Expand Down
79 changes: 59 additions & 20 deletions packages/react-scripts/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const safePostCssParser = require('postcss-safe-parser');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
Expand Down Expand Up @@ -138,7 +137,7 @@ module.exports = function(webpackEnv) {
return loaders;
};

return {
const originalConfig = {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production
bail: isEnvProduction,
Expand Down Expand Up @@ -246,6 +245,9 @@ module.exports = function(webpackEnv) {
},
},
sourceMap: shouldUseSourceMap,
// We cheat on this one to avoid a bug on CI providers advertising
// overly high number of CPUs.
parallel: 4,
}),
// This is only used in production mode
new OptimizeCSSAssetsPlugin({
Expand Down Expand Up @@ -654,24 +656,6 @@ module.exports = function(webpackEnv) {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the webpack build.
isEnvProduction &&
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
exclude: [/\.map$/, /asset-manifest\.json$/],
importWorkboxFrom: 'cdn',
navigateFallback: paths.publicUrlOrPath + 'index.html',
navigateFallbackBlacklist: [
// Exclude URLs starting with /_, as they're likely an API call
new RegExp('^/_'),
// Exclude any URLs whose last part seems to be a file extension
// as they're likely a resource and not a SPA route.
// URLs containing a "?" character won't be blacklisted as they're likely
// a route with query params (e.g. auth callbacks).
new RegExp('/[^/?]+\\.[^/]+$'),
],
}),
// TypeScript type checking
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
Expand Down Expand Up @@ -716,4 +700,59 @@ module.exports = function(webpackEnv) {
// our own hints via the FileSizeReporter
performance: false,
};

const serviceWorkerConfig = {
target: 'webworker',
mode: originalConfig.mode,
bail: originalConfig.bail,
devtool: originalConfig.devtool,
entry: { 'service-worker': paths.appServiceWorkerJs },
output: {
path: originalConfig.output.path,
pathinfo: originalConfig.output.pathinfo,
filename: 'sw.js',
publicPath: originalConfig.output.publicPath,
devtoolModuleFilenameTemplate:
originalConfig.output.devtoolModuleFilenameTemplate,
},
optimization: {
minimize: originalConfig.optimization.minimize,
minimizer: originalConfig.optimization.minimizer,
},
resolve: originalConfig.resolve,
resolveLoader: originalConfig.resolveLoader,
module: originalConfig.module,
plugins: [
new webpack.DefinePlugin(env.stringified),
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
typescript: resolve.sync('typescript', {
basedir: paths.appNodeModules,
}),
async: isEnvDevelopment,
useTypescriptIncrementalApi: true,
checkSyntacticErrors: true,
resolveModuleNameModule: process.versions.pnp
? `${__dirname}/pnpTs.js`
: undefined,
resolveTypeReferenceDirectiveModule: process.versions.pnp
? `${__dirname}/pnpTs.js`
: undefined,
tsconfig: paths.appTsConfig,
reportFiles: [
'**',
'!**/__tests__/**',
'!**/?(*.)(spec|test).*',
'!**/src/setupProxy.*',
'!**/src/setupTests.*',
],
watch: paths.appSrc,
silent: true,
// The formatter is invoked directly in WebpackDevServerUtils during development
formatter: isEnvProduction ? typescriptFormatter : undefined,
}),
].filter(Boolean),
};

return [originalConfig, serviceWorkerConfig];
};
5 changes: 3 additions & 2 deletions packages/react-scripts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-scripts",
"version": "3.4.1",
"name": "@ouihelp/react-scripts",
"version": "3004001.0.4",
"description": "Configuration and scripts for Create React App.",
"repository": {
"type": "git",
Expand Down Expand Up @@ -29,6 +29,7 @@
"types": "./lib/react-app.d.ts",
"dependencies": {
"@babel/core": "7.9.0",
"@ouihelp/react-dev-utils": "10020001.0.2",
"@svgr/webpack": "4.3.3",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-scripts/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const paths = require('../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const FileSizeReporter = require('@ouihelp/react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');

const measureFileSizesBeforeBuild =
Expand Down Expand Up @@ -111,7 +111,7 @@ checkBrowsers(paths.appPath, isInteractive)

const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrlOrPath;
const publicPath = config.output.publicPath;
const publicPath = config[0].output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
Expand Down
2 changes: 1 addition & 1 deletion packages/react-scripts/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const {
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
} = require('@ouihelp/react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const configFactory = require('../config/webpack.config');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ function verifyTypeScriptSetup() {
if (!fs.existsSync(paths.appTypeDeclarations)) {
fs.writeFileSync(
paths.appTypeDeclarations,
`/// <reference types="react-scripts" />${os.EOL}`
`/// <reference types="@ouihelp/react-scripts" />${os.EOL}`
);
}
}
Expand Down