diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts index d62c656944f..1a19d019766 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts @@ -7,25 +7,27 @@ import {NodePath} from '@babel/core'; import * as t from '@babel/types'; -import {CompilerError} from '../CompilerError'; +import {CompilerError, ErrorSeverity} from '../CompilerError'; import {EnvironmentConfig, ExternalFunction, GeneratedSource} from '../HIR'; import {getOrInsertDefault} from '../Utils/utils'; export function validateRestrictedImports( path: NodePath, {validateBlocklistedImports}: EnvironmentConfig, -): void { +): CompilerError | null { if ( validateBlocklistedImports == null || validateBlocklistedImports.length === 0 ) { - return; + return null; } + const error = new CompilerError(); const restrictedImports = new Set(validateBlocklistedImports); path.traverse({ ImportDeclaration(importDeclPath) { if (restrictedImports.has(importDeclPath.node.source.value)) { - CompilerError.throwTodo({ + error.push({ + severity: ErrorSeverity.Todo, reason: 'Bailing out due to blocklisted import', description: `Import from module ${importDeclPath.node.source.value}`, loc: importDeclPath.node.loc ?? null, @@ -33,6 +35,11 @@ export function validateRestrictedImports( } }, }); + if (error.hasErrors()) { + return error; + } else { + return null; + } } export function addImportsToProgram( diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 128a38f6714..499a4d124ea 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -277,6 +277,17 @@ function isFilePartOfSources( return false; } +/** + * `compileProgram` is directly invoked by the react-compiler babel plugin, so + * exceptions thrown by this function will fail the babel build. + * - call `handleError` if your error is recoverable. + * Unless the error is a warning / info diagnostic, compilation of a function + * / entire file should also be skipped. + * - throw an exception if the error is fatal / not recoverable. + * Examples of this are invalid compiler configs or failure to codegen outlined + * functions *after* already emitting optimized components / hooks that invoke + * the outlined functions. + */ export function compileProgram( program: NodePath, pass: CompilerPass, @@ -300,7 +311,11 @@ export function compileProgram( }); } const environment = environmentResult.unwrap(); - validateRestrictedImports(program, environment); + const restrictedImportsErr = validateRestrictedImports(program, environment); + if (restrictedImportsErr) { + handleError(restrictedImportsErr, pass, null); + return; + } const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c'); const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';