Skip to content

Commit

Permalink
[compiler] Add meta internal option for useMemoCache import
Browse files Browse the repository at this point in the history
Adds `target: 'donotuse_meta_internal'`, which inserts useMemoCache imports directly from `react`. Note that this is only valid for Meta bundles, as others do not [re-export the `c` function](https://github.com/facebook/react/blob/5b0ef217ef32333a8e56f39be04327c89efa346f/packages/react/index.fb.js#L68-L70).

```js
// target=donotuse_meta_internal
import {c as _c} from 'react';

// target=19
import {c as _c} from 'react/compiler-runtime';

// target=17,18
import {c as _c} from 'react-compiler-runtime';
```

Meta is a bit special in that react runtime and compiler are guaranteed to be up-to-date and compatible. It also has its own bundling and module resolution logic, which makes importing from `react/compiler-runtime` tricky.

I'm also fine with implementing the alternative which adds an internal stub for `react-compiler-runtime` and [bundles](https://github.com/facebook/react/blob/5b0ef217ef32333a8e56f39be04327c89efa346f/scripts/rollup/bundles.js#L120) the runtime for internal builds.
  • Loading branch information
mofeiZ committed Dec 2, 2024
1 parent 5b0ef21 commit c07531f
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 25 deletions.
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'),
}),
]);
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

0 comments on commit c07531f

Please sign in to comment.