Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[compiler] Add meta internal option for useMemoCache import #31654

Merged
merged 1 commit into from
Dec 2, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,22 @@ export type PluginOptions = {
target: CompilerReactTarget;
};

const CompilerReactTargetSchema = z.enum(['17', '18', '19']);
const CompilerReactTargetSchema = z.union([
z.literal('17'),
z.literal('18'),
z.literal('19'),
/**
* Used exclusively for Meta apps which are guaranteed to have compatible
* react runtime and compiler versions. Note that only the FB-internal bundles
* re-export useMemoCache (see
* https://github.com/facebook/react/blob/5b0ef217ef32333a8e56f39be04327c89efa346f/packages/react/index.fb.js#L68-L70),
* so this option is invalid / creates runtime errors for open-source users.
*/
z.object({
kind: z.literal('donotuse_meta_internal'),
runtimeModule: z.string().default('react'),
}),
Comment on lines +135 to +138
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the flexibility of also specifying the runtimeModule here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do since we're rolled out to RN desktop apps which currently have react-forget-runtime patched in (as their fork of react doesn't include useMemoCache)

]);
export type CompilerReactTarget = z.infer<typeof CompilerReactTargetSchema>;

const CompilationModeSchema = z.enum([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1123,30 +1123,23 @@ function checkFunctionReferencedBeforeDeclarationAtTopLevel(
return errors.details.length > 0 ? errors : null;
}

type ReactCompilerRuntimeModule =
| 'react/compiler-runtime' // from react namespace
| 'react-compiler-runtime'; // npm package
function getReactCompilerRuntimeModule(
opts: PluginOptions,
): ReactCompilerRuntimeModule {
let moduleName: ReactCompilerRuntimeModule | null = null;
switch (opts.target) {
case '17':
case '18': {
moduleName = 'react-compiler-runtime';
break;
}
case '19': {
moduleName = 'react/compiler-runtime';
break;
}
default:
CompilerError.invariant(moduleName != null, {
function getReactCompilerRuntimeModule(opts: PluginOptions): string {
if (opts.target === '19') {
return 'react/compiler-runtime'; // from react namespace
} else if (opts.target === '17' || opts.target === '18') {
return 'react-compiler-runtime'; // npm package
} else {
CompilerError.invariant(
opts.target != null &&
opts.target.kind === 'donotuse_meta_internal' &&
typeof opts.target.runtimeModule === 'string',
{
reason: 'Expected target to already be validated',
description: null,
loc: null,
suggestions: null,
});
},
);
return opts.target.runtimeModule;
}
return moduleName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

## Input

```javascript
// @target="donotuse_meta_internal"

function Component() {
return <div>Hello world</div>;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
isComponent: true,
};

```

## Code

```javascript
import { c as _c } from "react"; // @target="donotuse_meta_internal"

function Component() {
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <div>Hello world</div>;
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
isComponent: true,
};

```

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @target="donotuse_meta_internal"

function Component() {
return <div>Hello world</div>;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
isComponent: true,
};
1 change: 1 addition & 0 deletions compiler/packages/snap/src/SproutTodoFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ const skipFilter = new Set([
// Depends on external functions
'idx-method-no-outlining-wildcard',
'idx-method-no-outlining',
'target-flag-meta-internal',

// needs to be executed as a module
'meta-property',
Expand Down
14 changes: 11 additions & 3 deletions compiler/packages/snap/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
LoggerEvent,
PanicThresholdOptions,
PluginOptions,
CompilerReactTarget,
} from 'babel-plugin-react-compiler/src/Entrypoint';
import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR';
import type {
Expand Down Expand Up @@ -55,7 +56,7 @@ function makePluginOptions(
let validatePreserveExistingMemoizationGuarantees = false;
let customMacros: null | Array<Macro> = null;
let validateBlocklistedImports = null;
let target = '19' as const;
let target: CompilerReactTarget = '19';

if (firstLine.indexOf('@compilationMode(annotation)') !== -1) {
assert(
Expand All @@ -81,8 +82,15 @@ function makePluginOptions(

const targetMatch = /@target="([^"]+)"/.exec(firstLine);
if (targetMatch) {
// @ts-ignore
target = targetMatch[1];
if (targetMatch[1] === 'donotuse_meta_internal') {
target = {
kind: targetMatch[1],
runtimeModule: 'react',
};
} else {
// @ts-ignore
target = targetMatch[1];
}
}

if (firstLine.includes('@panicThreshold(none)')) {
Expand Down
Loading