Skip to content
Merged
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
7 changes: 7 additions & 0 deletions development/webpack/utils/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,13 @@ function getOptions(
group: toOrange('Security:'),
type: 'boolean',
},
reactCompilerVerbose: {
array: false,
default: false,
description: 'Enables/disables React Compiler verbose mode',
group: toOrange('Developer assistance:'),
type: 'boolean',
},

dryRun: {
array: false,
Expand Down
4 changes: 0 additions & 4 deletions development/webpack/utils/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { join } from 'node:path';
import { readFileSync } from 'node:fs';
import { parse } from 'dotenv';
import type { ReactCompilerLoaderOption } from 'react-compiler-webpack';
import { setEnvironmentVariables } from '../../build/set-environment-variables';
import type { Variables } from '../../lib/variables';
import type { BuildTypesConfig, BuildType } from '../../lib/build-type';
Expand Down Expand Up @@ -190,6 +189,3 @@ function loadConfigVars(

return definitions;
}
export const reactCompilerOptions = {
target: '17',
} as const satisfies ReactCompilerLoaderOption;
115 changes: 115 additions & 0 deletions development/webpack/utils/loaders/reactCompilerLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {
type ReactCompilerLoaderOption,
defineReactCompilerLoaderOption,
reactCompilerLoader,
} from 'react-compiler-webpack';
import type { Logger } from 'babel-plugin-react-compiler';

/**
* React Compiler logger that tracks compilation statistics
*/
class ReactCompilerLogger {
private compiledCount = 0;

private skippedCount = 0;

private errorCount = 0;

private todoCount = 0;

private compiledFiles: string[] = [];

private skippedFiles: string[] = [];

private errorFiles: string[] = [];

private todoFiles: string[] = [];

logEvent(
filename: string | null,
event: { kind: string; detail: { options: { category: string } } },
) {
if (filename === null) {
return;
}
switch (event.kind) {
case 'CompileSuccess':
this.compiledCount++;
this.compiledFiles.push(filename);
console.log(`✅ Compiled: ${filename}`);
break;
case 'CompileSkip':
this.skippedCount++;
this.skippedFiles.push(filename);
break;
case 'CompileError':
if (event.detail?.options?.category === 'Todo') {
this.todoCount++;
this.todoFiles.push(filename);
break;
}
this.errorCount++;
this.errorFiles.push(filename);
console.error(
`❌ React Compiler error in ${filename}: ${JSON.stringify(event.detail?.options) || 'Unknown error'}`,
);
break;
default:
// Ignore other event types
break;
}
}

getStats() {
return {
compiled: this.compiledCount,
skipped: this.skippedCount,
errors: this.errorCount,
unsupported: this.todoCount,
total:
this.compiledCount +
this.skippedCount +
this.errorCount +
this.todoCount,
compiledFiles: this.compiledFiles,
skippedFiles: this.skippedFiles,
errorFiles: this.errorFiles,
unsupportedFiles: this.todoFiles,
};
}

logSummary() {
const stats = this.getStats();
console.log('\n📊 React Compiler Statistics:');
console.log(` ✅ Compiled: ${stats.compiled} files`);
console.log(` ⏭️ Skipped: ${stats.skipped} files`);
console.log(` ❌ Errors: ${stats.errors} files`);
console.log(` 🔍 Unsupported: ${stats.unsupported} files`);
console.log(` 📦 Total processed: ${stats.total} files`);
}
}

// Create a singleton logger instance
const reactCompilerLogger = new ReactCompilerLogger();

/**
* Get the React Compiler logger instance for accessing statistics
*/
export function getReactCompilerLogger(): ReactCompilerLogger {
return reactCompilerLogger;
}

export const getReactCompilerLoader = (
target: ReactCompilerLoaderOption['target'],
verbose: boolean,
) => {
const reactCompilerOptions = {
target,
logger: verbose ? (reactCompilerLogger as Logger) : undefined,
} as const satisfies ReactCompilerLoaderOption;

return {
loader: reactCompilerLoader,
options: defineReactCompilerLoaderOption(reactCompilerOptions),
};
};
33 changes: 22 additions & 11 deletions development/webpack/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ import rtlCss from 'postcss-rtlcss';
import autoprefixer from 'autoprefixer';
import discardFonts from 'postcss-discard-font-face';
import type ReactRefreshPluginType from '@pmmmwh/react-refresh-webpack-plugin';
import {
defineReactCompilerLoaderOption,
reactCompilerLoader,
} from 'react-compiler-webpack';
import tailwindcss from 'tailwindcss';
import { loadBuildTypesConfig } from '../lib/build-type';
import {
Expand All @@ -38,7 +34,11 @@ import { transformManifest } from './utils/plugins/ManifestPlugin/helpers';
import { parseArgv, getDryRunMessage } from './utils/cli';
import { getCodeFenceLoader } from './utils/loaders/codeFenceLoader';
import { getSwcLoader } from './utils/loaders/swcLoader';
import { getVariables, reactCompilerOptions } from './utils/config';
import {
getReactCompilerLoader,
getReactCompilerLogger,
} from './utils/loaders/reactCompilerLoader';
import { getVariables } from './utils/config';
import { ManifestPlugin } from './utils/plugins/ManifestPlugin';
import { getLatestCommit } from './utils/git';

Expand Down Expand Up @@ -215,13 +215,29 @@ if (args.progress) {
const { ProgressPlugin } = require('webpack');
plugins.push(new ProgressPlugin());
}

if (args.reactCompilerVerbose) {
plugins.push({
apply(compiler) {
compiler.hooks.done.tap('ReactCompilerStatsPlugin', () => {
const logger = getReactCompilerLogger();
logger.logSummary();
});
},
} as WebpackPluginInstance);
}

// #endregion plugins

const swcConfig = { args, browsersListQuery, isDevelopment };
const tsxLoader = getSwcLoader('typescript', true, safeVariables, swcConfig);
const jsxLoader = getSwcLoader('ecmascript', true, safeVariables, swcConfig);
const npmLoader = getSwcLoader('ecmascript', false, {}, swcConfig);
const cjsLoader = getSwcLoader('ecmascript', false, {}, swcConfig, 'commonjs');
const reactCompilerLoader = getReactCompilerLoader(
'17',
args.reactCompilerVerbose,
);

const config = {
entry,
Expand Down Expand Up @@ -327,12 +343,7 @@ const config = {
{
test: /(?!\.(?:test|stories|container))\.(?:m?[jt]s|[jt]sx)$/u,
include: UI_DIR_RE,
use: [
{
loader: reactCompilerLoader,
options: defineReactCompilerLoaderOption(reactCompilerOptions),
},
],
use: [reactCompilerLoader],
},
// own typescript, and own typescript with jsx
{
Expand Down
Loading