From 1e18d651240ad808611e572442ed00473baf600a Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Tue, 9 Sep 2025 15:05:30 -0400 Subject: [PATCH 01/24] Remove OVERRIDE pragma and apply button, make config panel source of truth --- .../components/Editor/ConfigEditor.tsx | 129 +++++------------- .../components/Editor/EditorImpl.tsx | 28 ++-- .../playground/components/Editor/Input.tsx | 7 +- .../playground/components/StoreContext.tsx | 18 ++- compiler/apps/playground/lib/configUtils.ts | 120 ---------------- .../src/Utils/TestUtils.ts | 102 -------------- 6 files changed, 71 insertions(+), 333 deletions(-) delete mode 100644 compiler/apps/playground/lib/configUtils.ts diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 43b3f1e8a91..63522987db0 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -10,14 +10,8 @@ import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; import React, {useState, useCallback} from 'react'; import {Resizable} from 're-resizable'; -import {useSnackbar} from 'notistack'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; -import { - ConfigError, - generateOverridePragmaFromConfig, - updateSourceWithOverridePragma, -} from '../../lib/configUtils'; // @ts-expect-error - webpack asset/source loader handles .d.ts files as strings import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts'; @@ -28,61 +22,17 @@ export default function ConfigEditor(): React.ReactElement { const [isExpanded, setIsExpanded] = useState(false); const store = useStore(); const dispatchStore = useStoreDispatch(); - const {enqueueSnackbar} = useSnackbar(); const toggleExpanded = useCallback(() => { setIsExpanded(prev => !prev); }, []); - const handleApplyConfig: () => Promise = async () => { - try { - const config = store.config || ''; - - if (!config.trim()) { - enqueueSnackbar( - 'Config is empty. Please add configuration options first.', - { - variant: 'warning', - }, - ); - return; - } - const newPragma = await generateOverridePragmaFromConfig(config); - const updatedSource = updateSourceWithOverridePragma( - store.source, - newPragma, - ); - - dispatchStore({ - type: 'updateFile', - payload: { - source: updatedSource, - config: config, - }, - }); - } catch (error) { - console.error('Failed to apply config:', error); - - if (error instanceof ConfigError && error.message.trim()) { - enqueueSnackbar(error.message, { - variant: 'error', - }); - } else { - enqueueSnackbar('Unexpected error: failed to apply config.', { - variant: 'error', - }); - } - } - }; - const handleChange: (value: string | undefined) => void = value => { if (value === undefined) return; - // Only update the config dispatchStore({ - type: 'updateFile', + type: 'updateConfig', payload: { - source: store.source, config: value, }, }); @@ -120,49 +70,40 @@ export default function ConfigEditor(): React.ReactElement { return (
{isExpanded ? ( - <> - -

- - Config Overrides -

-
- -
-
- - + +

+ - Config Overrides +

+
+ +
+
) : (
+
+ )} +
+ ); +} diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 63522987db0..afdda60eb8f 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -95,7 +95,6 @@ export default function ConfigEditor(): React.ReactElement { lineNumbers: 'off', folding: false, renderLineHighlight: 'none', - scrollBeyondLastLine: false, hideCursorInOverviewRuler: true, overviewRulerBorder: false, overviewRulerLanes: 0, diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index d6a2bccc8ed..595242f75f2 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -27,7 +27,7 @@ import BabelPluginReactCompiler, { import clsx from 'clsx'; import invariant from 'invariant'; import {useSnackbar} from 'notistack'; -import {useDeferredValue, useMemo} from 'react'; +import {useDeferredValue, useMemo, useState, useCallback} from 'react'; import {useMountEffect} from '../../hooks'; import {defaultStore} from '../../lib/defaultStore'; import { @@ -350,13 +350,17 @@ export default function Editor(): JSX.Element { } return ( <> -
- -
- +
+
+
-
- +
+
+ +
+
+ +
diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index f4c64a14a05..4f7956e5985 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -135,30 +135,38 @@ export default function Input({errors, language}: Props): JSX.Element { }); }; + const editorContent = ( + + ); + return (
- - - + className="!h-[calc(100vh_-_3.5rem)]"> + {editorContent} + + ) : ( +
{editorContent}
+ )}
); } diff --git a/compiler/apps/playground/components/Editor/Output.tsx b/compiler/apps/playground/components/Editor/Output.tsx index ae8154f589e..b384738e750 100644 --- a/compiler/apps/playground/components/Editor/Output.tsx +++ b/compiler/apps/playground/components/Editor/Output.tsx @@ -21,9 +21,12 @@ import * as prettierPluginEstree from 'prettier/plugins/estree'; import * as prettier from 'prettier/standalone'; import {memo, ReactNode, useEffect, useState} from 'react'; import {type Store} from '../../lib/stores'; +import AccordianWindow from '../AccordianWindow'; import TabbedWindow from '../TabbedWindow'; import {monacoOptions} from './monacoOptions'; import {BabelFileResult} from '@babel/core'; +import {BASIC_OUTPUT_TAB_NAMES} from '../constants'; + const MemoizedOutput = memo(Output); export default MemoizedOutput; @@ -71,7 +74,7 @@ async function tabify( const concattedResults = new Map(); // Concat all top level function declaration results into a single tab for each pass for (const [passName, results] of compilerOutput.results) { - if (!showInternals && passName !== 'Output' && passName !== 'SourceMap') { + if (!showInternals && !BASIC_OUTPUT_TAB_NAMES.includes(passName)) { continue; } for (const result of results) { @@ -215,6 +218,7 @@ function Output({store, compilerOutput}: Props): JSX.Element { const [tabs, setTabs] = useState>( () => new Map(), ); + const [activeTab, setActiveTab] = useState('Output'); /* * Update the active tab back to the output or errors tab when the compilation state @@ -226,6 +230,7 @@ function Output({store, compilerOutput}: Props): JSX.Element { if (compilerOutput.kind !== previousOutputKind) { setPreviousOutputKind(compilerOutput.kind); setTabsOpen(new Set(['Output'])); + setActiveTab('Output'); } useEffect(() => { @@ -249,9 +254,19 @@ function Output({store, compilerOutput}: Props): JSX.Element { } } + if (!store.showInternals) { + return ( + + ); + } + return ( <> - = { automaticLayout: true, wordWrap: 'on', wrappingIndent: 'same', + scrollBeyondLastLine: false, }; diff --git a/compiler/apps/playground/components/TabbedWindow.tsx b/compiler/apps/playground/components/TabbedWindow.tsx index 4b01056f25b..a4f3b765645 100644 --- a/compiler/apps/playground/components/TabbedWindow.tsx +++ b/compiler/apps/playground/components/TabbedWindow.tsx @@ -4,103 +4,46 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +import React from 'react'; +import clsx from 'clsx'; -import {Resizable} from 're-resizable'; -import React, {useCallback} from 'react'; - -type TabsRecord = Map; - -export default function TabbedWindow(props: { - defaultTab: string | null; - tabs: TabsRecord; - tabsOpen: Set; - setTabsOpen: (newTab: Set) => void; - changedPasses: Set; +export default function TabbedWindow({ + tabs, + activeTab, + onTabChange, +}: { + tabs: Map; + activeTab: string; + onTabChange: (tab: string) => void; }): React.ReactElement { - if (props.tabs.size === 0) { + if (tabs.size === 0) { return ( -
+
No compiler output detected, see errors below
); } return ( -
- {Array.from(props.tabs.keys()).map(name => { - return ( - - ); - })} -
- ); -} - -function TabbedWindowItem({ - name, - tabs, - tabsOpen, - setTabsOpen, - hasChanged, -}: { - name: string; - tabs: TabsRecord; - tabsOpen: Set; - setTabsOpen: (newTab: Set) => void; - hasChanged: boolean; -}): React.ReactElement { - const isShow = tabsOpen.has(name); - - const toggleTabs = useCallback(() => { - const nextState = new Set(tabsOpen); - if (nextState.has(name)) { - nextState.delete(name); - } else { - nextState.add(name); - } - setTabsOpen(nextState); - }, [tabsOpen, name, setTabsOpen]); - - // Replace spaces with non-breaking spaces - const displayName = name.replace(/ /g, '\u00A0'); - - return ( -
- {isShow ? ( - -

- - {displayName} -

- {tabs.get(name) ??
No output for {name}
} -
- ) : ( -
- -
- )} +
+
+ {Array.from(tabs.keys()).map(tab => { + const isActive = activeTab === tab; + return ( + + ); + })} +
+
{tabs.get(activeTab)}
); } diff --git a/compiler/apps/playground/components/constants.ts b/compiler/apps/playground/components/constants.ts new file mode 100644 index 00000000000..7075d7dfb1d --- /dev/null +++ b/compiler/apps/playground/components/constants.ts @@ -0,0 +1,8 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export const BASIC_OUTPUT_TAB_NAMES = ['Output', 'SourceMap']; diff --git a/compiler/apps/playground/components/index.ts b/compiler/apps/playground/components/index.ts index 7fbef4c139d..d22a6b77bba 100644 --- a/compiler/apps/playground/components/index.ts +++ b/compiler/apps/playground/components/index.ts @@ -8,3 +8,4 @@ export {default as Editor} from './Editor'; export {default as Header} from './Header'; export {StoreProvider} from './StoreContext'; +export {BASIC_OUTPUT_TAB_NAMES} from './constants'; From 6faa9f1648a85ad405911ebe17b1dd07fd5bac64 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 10 Sep 2025 17:49:39 -0400 Subject: [PATCH 04/24] Add styling to panels and chevron opener --- .../components/Editor/ConfigEditor.tsx | 140 +++++++++++------- .../playground/components/Editor/Input.tsx | 18 ++- .../playground/components/Editor/Output.tsx | 3 +- .../components/Icons/IconChevron.tsx | 41 +++++ .../playground/components/TabbedWindow.tsx | 13 +- .../apps/playground/components/constants.ts | 8 - compiler/apps/playground/components/index.ts | 1 - 7 files changed, 154 insertions(+), 70 deletions(-) create mode 100644 compiler/apps/playground/components/Icons/IconChevron.tsx delete mode 100644 compiler/apps/playground/components/constants.ts diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index afdda60eb8f..48423aae3b8 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -8,10 +8,11 @@ import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; -import React, {useState, useCallback} from 'react'; +import React, {useState} from 'react'; import {Resizable} from 're-resizable'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; +import {IconChevron} from '../Icons/IconChevron'; // @ts-expect-error - webpack asset/source loader handles .d.ts files as strings import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts'; @@ -20,13 +21,26 @@ loader.config({monaco}); export default function ConfigEditor(): React.ReactElement { const [isExpanded, setIsExpanded] = useState(false); + + return ( +
+ {isExpanded ? ( + + ) : ( + + )} +
+ ); +} + +function ExpandedEditor({ + onToggle, +}: { + onToggle: (expanded: boolean) => void; +}): React.ReactElement { const store = useStore(); const dispatchStore = useStoreDispatch(); - const toggleExpanded = useCallback(() => { - setIsExpanded(prev => !prev); - }, []); - const handleChange: (value: string | undefined) => void = value => { if (value === undefined) return; @@ -68,56 +82,78 @@ export default function ConfigEditor(): React.ReactElement { }; return ( -
- {isExpanded ? ( - -

- - Config Overrides + +
+
+

+ Config Overrides

-
- -
- - ) : ( -
- + />
- )} +
+ + ); +} + +function CollapsedEditor({ + onToggle, +}: { + onToggle: (expanded: boolean) => void; +}): React.ReactElement { + return ( +
+
onToggle(true)} + style={{ + top: '50%', + marginTop: '-32px', + left: '0px', + borderTopLeftRadius: 0, + borderBottomLeftRadius: 0, + }}> + +
); } diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index 4f7956e5985..2f4a946ddf6 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -14,6 +14,7 @@ import {Resizable} from 're-resizable'; import {useEffect, useState} from 'react'; import {renderReactCompilerMarkers} from '../../lib/reactCompilerMonacoDiagnostics'; import {useStore, useStoreDispatch} from '../StoreContext'; +import TabbedWindow from '../TabbedWindow'; import {monacoOptions} from './monacoOptions'; // @ts-expect-error TODO: Make TS recognize .d.ts files, in addition to loading them with webpack. import React$Types from '../../node_modules/@types/react/index.d.ts'; @@ -151,6 +152,19 @@ export default function Input({errors, language}: Props): JSX.Element { /> ); + const tabs = new Map([['Input', editorContent]]); + const [activeTab, setActiveTab] = useState('Input'); + + const tabbedContent = ( +
+ +
+ ); + return (
{store.showInternals ? ( @@ -162,10 +176,10 @@ export default function Input({errors, language}: Props): JSX.Element { * will grow the editor to fit within parent element */ className="!h-[calc(100vh_-_3.5rem)]"> - {editorContent} + {tabbedContent} ) : ( -
{editorContent}
+
{tabbedContent}
)}
); diff --git a/compiler/apps/playground/components/Editor/Output.tsx b/compiler/apps/playground/components/Editor/Output.tsx index b384738e750..a23d1682028 100644 --- a/compiler/apps/playground/components/Editor/Output.tsx +++ b/compiler/apps/playground/components/Editor/Output.tsx @@ -25,12 +25,13 @@ import AccordianWindow from '../AccordianWindow'; import TabbedWindow from '../TabbedWindow'; import {monacoOptions} from './monacoOptions'; import {BabelFileResult} from '@babel/core'; -import {BASIC_OUTPUT_TAB_NAMES} from '../constants'; const MemoizedOutput = memo(Output); export default MemoizedOutput; +export const BASIC_OUTPUT_TAB_NAMES = ['Output', 'SourceMap']; + export type PrintedCompilerPipelineValue = | { kind: 'hir'; diff --git a/compiler/apps/playground/components/Icons/IconChevron.tsx b/compiler/apps/playground/components/Icons/IconChevron.tsx new file mode 100644 index 00000000000..1e9dfb69188 --- /dev/null +++ b/compiler/apps/playground/components/Icons/IconChevron.tsx @@ -0,0 +1,41 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {memo} from 'react'; + +export const IconChevron = memo< + JSX.IntrinsicElements['svg'] & { + /** + * The direction the arrow should point. + */ + displayDirection: 'right' | 'left'; + } +>(function IconChevron({className, displayDirection, ...props}) { + const rotationClass = + displayDirection === 'left' ? 'rotate-90' : '-rotate-90'; + const classes = className ? `${rotationClass} ${className}` : rotationClass; + + return ( + + + + + + + ); +}); diff --git a/compiler/apps/playground/components/TabbedWindow.tsx b/compiler/apps/playground/components/TabbedWindow.tsx index a4f3b765645..49ff76543bb 100644 --- a/compiler/apps/playground/components/TabbedWindow.tsx +++ b/compiler/apps/playground/components/TabbedWindow.tsx @@ -24,8 +24,8 @@ export default function TabbedWindow({ ); } return ( -
-
+
+
{Array.from(tabs.keys()).map(tab => { const isActive = activeTab === tab; return ( @@ -34,16 +34,17 @@ export default function TabbedWindow({ onClick={() => onTabChange(tab)} className={clsx( 'active:scale-95 transition-transform text-center outline-none py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full capitalize whitespace-nowrap text-sm', - !isActive && 'hover:bg-primary/5 hover:dark:bg-primary-dark/5', - isActive && - 'bg-highlight dark:bg-highlight-dark text-link dark:text-link-dark', + !isActive && 'hover:bg-primary/5', + isActive && 'bg-highlight text-link', )}> {tab} ); })}
-
{tabs.get(activeTab)}
+
+ {tabs.get(activeTab)} +
); } diff --git a/compiler/apps/playground/components/constants.ts b/compiler/apps/playground/components/constants.ts deleted file mode 100644 index 7075d7dfb1d..00000000000 --- a/compiler/apps/playground/components/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -export const BASIC_OUTPUT_TAB_NAMES = ['Output', 'SourceMap']; diff --git a/compiler/apps/playground/components/index.ts b/compiler/apps/playground/components/index.ts index d22a6b77bba..7fbef4c139d 100644 --- a/compiler/apps/playground/components/index.ts +++ b/compiler/apps/playground/components/index.ts @@ -8,4 +8,3 @@ export {default as Editor} from './Editor'; export {default as Header} from './Header'; export {StoreProvider} from './StoreContext'; -export {BASIC_OUTPUT_TAB_NAMES} from './constants'; From 078895820b43289e93d561a20d03afa29294a533 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Thu, 11 Sep 2025 13:46:01 -0400 Subject: [PATCH 05/24] Add consistent styling --- .../components/Editor/ConfigEditor.tsx | 18 +++++++++++------- .../components/Editor/EditorImpl.tsx | 6 +++--- .../playground/components/Editor/Input.tsx | 9 ++++++--- .../playground/components/Editor/Output.tsx | 16 +++++++--------- .../components/Editor/monacoOptions.ts | 1 - compiler/apps/playground/components/Header.tsx | 2 +- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 48423aae3b8..5f904960bac 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -89,14 +89,14 @@ function ExpandedEditor({ defaultSize={{width: 350, height: 'auto'}} enable={{right: true, bottom: false}} style={{position: 'relative', height: 'calc(100vh - 3.5rem)'}}> -
+
-

+

Config Overrides

onToggle(false)} style={{ @@ -106,7 +106,10 @@ function ExpandedEditor({ borderTopLeftRadius: 0, borderBottomLeftRadius: 0, }}> - +
@@ -142,17 +146,17 @@ function CollapsedEditor({ className="w-4" style={{height: 'calc(100vh - 3.5rem)', position: 'relative'}}>
onToggle(true)} style={{ top: '50%', marginTop: '-32px', - left: '0px', + left: '-8px', borderTopLeftRadius: 0, borderBottomLeftRadius: 0, }}> - +
); diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index 595242f75f2..e6c57ca0a75 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -354,11 +354,11 @@ export default function Editor(): JSX.Element {
-
-
+
+
-
+
diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index 2f4a946ddf6..206b98300be 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -6,7 +6,10 @@ */ import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react'; -import {CompilerErrorDetail} from 'babel-plugin-react-compiler'; +import { + CompilerErrorDetail, + CompilerDiagnostic, +} from 'babel-plugin-react-compiler'; import invariant from 'invariant'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; @@ -22,7 +25,7 @@ import React$Types from '../../node_modules/@types/react/index.d.ts'; loader.config({monaco}); type Props = { - errors: Array; + errors: Array; language: 'flow' | 'typescript'; }; @@ -169,7 +172,7 @@ export default function Input({errors, language}: Props): JSX.Element {
{store.showInternals ? ( - - + ); } diff --git a/compiler/apps/playground/components/Editor/monacoOptions.ts b/compiler/apps/playground/components/Editor/monacoOptions.ts index 0e288d0db24..f272913bce4 100644 --- a/compiler/apps/playground/components/Editor/monacoOptions.ts +++ b/compiler/apps/playground/components/Editor/monacoOptions.ts @@ -29,5 +29,4 @@ export const monacoOptions: Partial = { automaticLayout: true, wordWrap: 'on', wrappingIndent: 'same', - scrollBeyondLastLine: false, }; diff --git a/compiler/apps/playground/components/Header.tsx b/compiler/apps/playground/components/Header.tsx index 55f9dbdd36c..582caebffb9 100644 --- a/compiler/apps/playground/components/Header.tsx +++ b/compiler/apps/playground/components/Header.tsx @@ -72,7 +72,7 @@ export default function Header(): JSX.Element { 'before:bg-white before:rounded-full before:transition-transform before:duration-250', 'focus-within:shadow-[0_0_1px_#2196F3]', store.showInternals - ? 'bg-blue-500 before:translate-x-3.5' + ? 'bg-link before:translate-x-3.5' : 'bg-gray-300', )}> From c8fb91882240b5554221626d7fd4e08f3d65279c Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Thu, 11 Sep 2025 14:09:58 -0400 Subject: [PATCH 06/24] Fix formatting --- .../apps/playground/components/AccordianWindow.tsx | 2 +- .../playground/components/Editor/EditorImpl.tsx | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/apps/playground/components/AccordianWindow.tsx b/compiler/apps/playground/components/AccordianWindow.tsx index d375656f7b5..67950748317 100644 --- a/compiler/apps/playground/components/AccordianWindow.tsx +++ b/compiler/apps/playground/components/AccordianWindow.tsx @@ -27,7 +27,7 @@ export default function AccordianWindow(props: { ); } return ( -
+
{Array.from(props.tabs.keys()).map(name => { return ( -
+
-
-
+
+
-
+
From 5e5a84d53f115b6f3fa7db061c5f51cb261bcacd Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Thu, 11 Sep 2025 14:24:02 -0400 Subject: [PATCH 07/24] Update test --- .../page.spec.ts/compilationMode-all-output.txt | 5 ++--- .../components/{AccordianWindow.tsx => AccordionWindow.tsx} | 6 +++--- compiler/apps/playground/components/Editor/Output.tsx | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) rename compiler/apps/playground/components/{AccordianWindow.tsx => AccordionWindow.tsx} (96%) diff --git a/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt index 0084911eec1..1bea6e9d263 100644 --- a/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt +++ b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt @@ -1,5 +1,4 @@ -import { c as _c } from "react/compiler-runtime"; //  -@compilationMode:"all" +import { c as _c } from "react/compiler-runtime"; // @compilationMode:"all" function nonReactFn() {   const $ = _c(1);   let t0; @@ -10,4 +9,4 @@ function nonReactFn() {     t0 = $[0];   }   return t0; -} \ No newline at end of file +} diff --git a/compiler/apps/playground/components/AccordianWindow.tsx b/compiler/apps/playground/components/AccordionWindow.tsx similarity index 96% rename from compiler/apps/playground/components/AccordianWindow.tsx rename to compiler/apps/playground/components/AccordionWindow.tsx index 67950748317..de3b01b0b05 100644 --- a/compiler/apps/playground/components/AccordianWindow.tsx +++ b/compiler/apps/playground/components/AccordionWindow.tsx @@ -10,7 +10,7 @@ import React, {useCallback} from 'react'; type TabsRecord = Map; -export default function AccordianWindow(props: { +export default function AccordionWindow(props: { defaultTab: string | null; tabs: TabsRecord; tabsOpen: Set; @@ -30,7 +30,7 @@ export default function AccordianWindow(props: {
{Array.from(props.tabs.keys()).map(name => { return ( - Date: Thu, 11 Sep 2025 14:53:09 -0400 Subject: [PATCH 08/24] update test --- .../page.spec.ts/compilationMode-all-output.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt index 1bea6e9d263..0084911eec1 100644 --- a/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt +++ b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt @@ -1,4 +1,5 @@ -import { c as _c } from "react/compiler-runtime"; // @compilationMode:"all" +import { c as _c } from "react/compiler-runtime"; //  +@compilationMode:"all" function nonReactFn() {   const $ = _c(1);   let t0; @@ -9,4 +10,4 @@ function nonReactFn() {     t0 = $[0];   }   return t0; -} +} \ No newline at end of file From 16561a48bce88a577ac29c7e5a72f992ee942670 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Fri, 12 Sep 2025 10:37:31 -0400 Subject: [PATCH 09/24] Initial changes --- .../components/Editor/ConfigEditor.tsx | 116 ++++++++++++++---- .../components/Editor/EditorImpl.tsx | 116 ++++++++++-------- compiler/apps/playground/playwright.config.js | 6 +- 3 files changed, 162 insertions(+), 76 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 5f904960bac..6a282bd66ed 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -6,6 +6,7 @@ */ import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react'; +import {PluginOptions} from 'babel-plugin-react-compiler'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; import React, {useState} from 'react'; @@ -13,19 +14,27 @@ import {Resizable} from 're-resizable'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; import {IconChevron} from '../Icons/IconChevron'; +import prettyFormat from 'pretty-format'; // @ts-expect-error - webpack asset/source loader handles .d.ts files as strings import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts'; loader.config({monaco}); -export default function ConfigEditor(): React.ReactElement { +export default function ConfigEditor({ + appliedOptions, +}: { + appliedOptions: PluginOptions | null; +}): React.ReactElement { const [isExpanded, setIsExpanded] = useState(false); return (
{isExpanded ? ( - + ) : ( )} @@ -35,8 +44,10 @@ export default function ConfigEditor(): React.ReactElement { function ExpandedEditor({ onToggle, + appliedOptions, }: { onToggle: (expanded: boolean) => void; + appliedOptions: PluginOptions | null; }): React.ReactElement { const store = useStore(); const dispatchStore = useStoreDispatch(); @@ -81,6 +92,25 @@ function ExpandedEditor({ } }; + const formattedAppliedOptions = appliedOptions + ? prettyFormat(appliedOptions, { + printFunctionName: false, + callToJSON: false, + plugins: [ + { + test: (value: any) => value instanceof Map, + serialize: (map: Map) => { + const obj: Record = {}; + for (const [key, value] of map) { + obj[String(key)] = value; + } + return `Map(${prettyFormat(obj)})`; + }, + }, + ], + }) + : 'No options available'; + return ( -
-
-

- Config Overrides -

-
+
-
- + + {/* Config Overrides Panel */} +
+
+

+ Config Overrides +

+
+
+ +
+
+ + {/* Applied Configs Panel */} +
+
+

+ Applied Configs +

+
+
+ +
diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index c70adfaa4eb..10349940c6a 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -142,11 +142,66 @@ const COMMON_HOOKS: Array<[string, Hook]> = [ ], ]; +function parseOptions( + source: string, + mode: 'compiler' | 'linter', + configOverrides: string, +): PluginOptions { + // Extract the first line to quickly check for custom test directives + const pragma = source.substring(0, source.indexOf('\n')); + + const parsedPragmaOptions = parseConfigPragmaForTests(pragma, { + compilationMode: 'infer', + environment: + mode === 'linter' + ? { + // enabled in compiler + validateRefAccessDuringRender: false, + // enabled in linter + validateNoSetStateInRender: true, + validateNoSetStateInEffects: true, + validateNoJSXInTryStatements: true, + validateNoImpureFunctionsInRender: true, + validateStaticComponents: true, + validateNoFreezingKnownMutableFunctions: true, + validateNoVoidUseMemo: true, + } + : { + /* use defaults for compiler mode */ + }, + }); + + // Parse config overrides from config editor + let configOverrideOptions: any = {}; + const configMatch = configOverrides.match(/^\s*import.*?\n\n\((.*)\)/s); + // TODO: initialize store with URL params, not empty store + if (configOverrides.trim()) { + if (configMatch && configMatch[1]) { + const configString = configMatch[1].replace(/satisfies.*$/, '').trim(); + configOverrideOptions = new Function(`return (${configString})`)(); + } else { + throw new Error('Invalid config overrides'); + } + } + + const opts: PluginOptions = parsePluginOptions({ + ...parsedPragmaOptions, + ...configOverrideOptions, + environment: { + ...parsedPragmaOptions.environment, + ...configOverrideOptions.environment, + customHooks: new Map([...COMMON_HOOKS]), + }, + }); + + return opts; +} + function compile( source: string, mode: 'compiler' | 'linter', configOverrides: string, -): [CompilerOutput, 'flow' | 'typescript'] { +): [CompilerOutput, 'flow' | 'typescript', PluginOptions | null] { const results = new Map>(); const error = new CompilerError(); const otherErrors: Array = []; @@ -165,9 +220,10 @@ function compile( language = 'typescript'; } let transformOutput; + let baseOpts: PluginOptions | null = null; + try { - // Extract the first line to quickly check for custom test directives - const pragma = source.substring(0, source.indexOf('\n')); + baseOpts = parseOptions(source, mode, configOverrides); const logIR = (result: CompilerPipelineValue): void => { switch (result.kind) { case 'ast': { @@ -206,48 +262,10 @@ function compile( } } }; - const parsedPragmaOptions = parseConfigPragmaForTests(pragma, { - compilationMode: 'infer', - environment: - mode === 'linter' - ? { - // enabled in compiler - validateRefAccessDuringRender: false, - // enabled in linter - validateNoSetStateInRender: true, - validateNoSetStateInEffects: true, - validateNoJSXInTryStatements: true, - validateNoImpureFunctionsInRender: true, - validateStaticComponents: true, - validateNoFreezingKnownMutableFunctions: true, - validateNoVoidUseMemo: true, - } - : { - /* use defaults for compiler mode */ - }, - }); - // Parse config overrides from config editor - let configOverrideOptions: any = {}; - const configMatch = configOverrides.match(/^\s*import.*?\n\n\((.*)\)/s); - // TODO: initialize store with URL params, not empty store - if (configOverrides.trim()) { - if (configMatch && configMatch[1]) { - const configString = configMatch[1].replace(/satisfies.*$/, '').trim(); - configOverrideOptions = new Function(`return (${configString})`)(); - } else { - throw new Error('Invalid config overrides'); - } - } - - const opts: PluginOptions = parsePluginOptions({ - ...parsedPragmaOptions, - ...configOverrideOptions, - environment: { - ...parsedPragmaOptions.environment, - ...configOverrideOptions.environment, - customHooks: new Map([...COMMON_HOOKS]), - }, + // Add logger options to the parsed options + const opts = { + ...baseOpts, logger: { debugLogIRs: logIR, logEvent: (_filename: string | null, event: LoggerEvent) => { @@ -256,7 +274,8 @@ function compile( } }, }, - }); + }; + transformOutput = invokeCompiler(source, language, opts); } catch (err) { /** @@ -285,11 +304,12 @@ function compile( otherErrors.forEach(e => error.details.push(e)); } if (error.hasErrors()) { - return [{kind: 'err', results, error}, language]; + return [{kind: 'err', results, error}, language, baseOpts]; } return [ {kind: 'ok', results, transformOutput, errors: error.details}, language, + baseOpts, ]; } @@ -298,7 +318,7 @@ export default function Editor(): JSX.Element { const deferredStore = useDeferredValue(store); const dispatchStore = useStoreDispatch(); const {enqueueSnackbar} = useSnackbar(); - const [compilerOutput, language] = useMemo( + const [compilerOutput, language, appliedOptions] = useMemo( () => compile(deferredStore.source, 'compiler', deferredStore.config), [deferredStore.source, deferredStore.config], ); @@ -349,7 +369,7 @@ export default function Editor(): JSX.Element { <>
- +
diff --git a/compiler/apps/playground/playwright.config.js b/compiler/apps/playground/playwright.config.js index 2ef29293d41..10de19457ff 100644 --- a/compiler/apps/playground/playwright.config.js +++ b/compiler/apps/playground/playwright.config.js @@ -55,12 +55,16 @@ export default defineConfig({ // contextOptions: { // ignoreHTTPSErrors: true, // }, + viewport: {width: 1920, height: 1080}, }, projects: [ { name: 'chromium', - use: {...devices['Desktop Chrome']}, + use: { + ...devices['Desktop Chrome'], + viewport: {width: 1920, height: 1080}, + }, }, // { // name: 'Desktop Firefox', From ef87362d8fbda8a0c51b2e438c26987a10d1c83e Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Fri, 12 Sep 2025 14:38:55 -0400 Subject: [PATCH 10/24] update style --- .../components/Editor/ConfigEditor.tsx | 28 ++++--------------- .../components/Editor/EditorImpl.tsx | 4 +-- .../playground/components/TabbedWindow.tsx | 2 +- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 6a282bd66ed..c449653cfb3 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -95,21 +95,9 @@ function ExpandedEditor({ const formattedAppliedOptions = appliedOptions ? prettyFormat(appliedOptions, { printFunctionName: false, - callToJSON: false, - plugins: [ - { - test: (value: any) => value instanceof Map, - serialize: (map: Map) => { - const obj: Record = {}; - for (const [key, value] of map) { - obj[String(key)] = value; - } - return `Map(${prettyFormat(obj)})`; - }, - }, - ], + printBasicPrototype: false, }) - : 'No options available'; + : 'Invalid configs'; return (
- {/* Config Overrides Panel */}
-

+

Config Overrides

@@ -154,22 +141,20 @@ function ExpandedEditor({ options={{ ...monacoOptions, lineNumbers: 'off', - folding: false, renderLineHighlight: 'none', - hideCursorInOverviewRuler: true, overviewRulerBorder: false, overviewRulerLanes: 0, fontSize: 12, scrollBeyondLastLine: false, + glyphMargin: false, }} />
- {/* Applied Configs Panel */}
-

+

Applied Configs

@@ -181,14 +166,13 @@ function ExpandedEditor({ options={{ ...monacoOptions, lineNumbers: 'off', - folding: false, renderLineHighlight: 'none', - hideCursorInOverviewRuler: true, overviewRulerBorder: false, overviewRulerLanes: 0, fontSize: 12, scrollBeyondLastLine: false, readOnly: true, + glyphMargin: false, }} />
diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index 3c8e4a8b268..8b75ce6ac5e 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -220,7 +220,7 @@ function compile( language = 'typescript'; } let transformOutput; - + let baseOpts: PluginOptions | null = null; try { baseOpts = parseOptions(source, mode, configOverrides); @@ -279,7 +279,7 @@ function compile( ...baseOpts, logger: { debugLogIRs: logIR, - logEvent: (_filename: string | null, event: LoggerEvent) => { + logEvent: (_filename: string | null, event: LoggerEvent): void => { if (event.kind === 'CompileError') { otherErrors.push(event.detail); } diff --git a/compiler/apps/playground/components/TabbedWindow.tsx b/compiler/apps/playground/components/TabbedWindow.tsx index 49ff76543bb..1751bd87e26 100644 --- a/compiler/apps/playground/components/TabbedWindow.tsx +++ b/compiler/apps/playground/components/TabbedWindow.tsx @@ -33,7 +33,7 @@ export default function TabbedWindow({ key={tab} onClick={() => onTabChange(tab)} className={clsx( - 'active:scale-95 transition-transform text-center outline-none py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full capitalize whitespace-nowrap text-sm', + 'active:scale-95 transition-transform py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full text-sm', !isActive && 'hover:bg-primary/5', isActive && 'bg-highlight text-link', )}> From 0e0fcb0f3ee48832647579e621d1486b70848cfb Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Fri, 12 Sep 2025 15:20:08 -0400 Subject: [PATCH 11/24] Finalize config panel --- .../components/Editor/ConfigEditor.tsx | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index c449653cfb3..339ccb62400 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -28,17 +28,10 @@ export default function ConfigEditor({ }): React.ReactElement { const [isExpanded, setIsExpanded] = useState(false); - return ( -
- {isExpanded ? ( - - ) : ( - - )} -
+ return isExpanded ? ( + + ) : ( + ); } @@ -101,13 +94,12 @@ function ExpandedEditor({ return ( -
+ style={{position: 'relative'}}> +
-
+

Config Overrides

-
+
-
+

Applied Configs

-
+
+ className="w-4 !h-[calc(100vh_-_3.5rem)]" + style={{position: 'relative'}}>
Date: Fri, 12 Sep 2025 15:28:23 -0400 Subject: [PATCH 12/24] Update default config --- compiler/apps/playground/lib/defaultStore.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/apps/playground/lib/defaultStore.ts b/compiler/apps/playground/lib/defaultStore.ts index 17a80094a66..bb33c1b76c5 100644 --- a/compiler/apps/playground/lib/defaultStore.ts +++ b/compiler/apps/playground/lib/defaultStore.ts @@ -17,9 +17,7 @@ export const defaultConfig = `\ import type { PluginOptions } from 'babel-plugin-react-compiler/dist'; ({ - environment: { - enableResetCacheOnSourceFileChanges: false - } + //compilationMode: "all" } satisfies Partial);`; export const defaultStore: Store = { From a128cac8b364cce1a28adec0ca1fd3f58f92e8f3 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Mon, 15 Sep 2025 15:07:16 -0400 Subject: [PATCH 13/24] Test changes --- .../components/Editor/ConfigEditor.tsx | 23 ++++++++++++---- .../playground/components/Editor/Input.tsx | 16 +----------- compiler/apps/playground/package.json | 4 +-- compiler/apps/playground/tsconfig.json | 3 +++ compiler/apps/playground/yarn.lock | 26 +++++++++---------- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 339ccb62400..a2614454904 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -9,7 +9,7 @@ import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react'; import {PluginOptions} from 'babel-plugin-react-compiler'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; -import React, {useState} from 'react'; +import React, {useState, Activity} from 'react'; import {Resizable} from 're-resizable'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; @@ -21,6 +21,9 @@ import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts'; loader.config({monaco}); +console.log('Acitivty import:', Activity); +console.log('React import:', React); + export default function ConfigEditor({ appliedOptions, }: { @@ -28,10 +31,20 @@ export default function ConfigEditor({ }): React.ReactElement { const [isExpanded, setIsExpanded] = useState(false); - return isExpanded ? ( - - ) : ( - + return ( + <> + {/* + + + ; + + + + ; */} + ); } diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index 206b98300be..f25bb115a68 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -13,7 +13,6 @@ import { import invariant from 'invariant'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; -import {Resizable} from 're-resizable'; import {useEffect, useState} from 'react'; import {renderReactCompilerMarkers} from '../../lib/reactCompilerMonacoDiagnostics'; import {useStore, useStoreDispatch} from '../StoreContext'; @@ -170,20 +169,7 @@ export default function Input({errors, language}: Props): JSX.Element { return (
- {store.showInternals ? ( - - {tabbedContent} - - ) : ( -
{tabbedContent}
- )} +
{tabbedContent}
); } diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index 44c1f101230..fd84ee6624e 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -39,8 +39,8 @@ "prettier": "^3.3.3", "pretty-format": "^29.3.1", "re-resizable": "^6.9.16", - "react": "19.1.1", - "react-dom": "19.1.1" + "react": "^0.0.0-experimental-67a44bcd-20250915", + "react-dom": "^0.0.0-experimental-67a44bcd-20250915" }, "devDependencies": { "@types/node": "18.11.9", diff --git a/compiler/apps/playground/tsconfig.json b/compiler/apps/playground/tsconfig.json index eb7fcfe2b72..1ead55cc96e 100644 --- a/compiler/apps/playground/tsconfig.json +++ b/compiler/apps/playground/tsconfig.json @@ -6,6 +6,9 @@ "dom.iterable", "esnext" ], + "types": [ + "react/experimental" + ], "allowJs": true, "skipLibCheck": true, "strict": true, diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index 9bf1bb0687b..c1b73e372c5 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -3577,12 +3577,12 @@ re-resizable@^6.9.16: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee" integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw== -react-dom@19.1.1: - version "19.1.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.1.tgz#2daa9ff7f3ae384aeb30e76d5ee38c046dc89893" - integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw== +react-dom@^0.0.0-experimental-67a44bcd-20250915: + version "0.0.0-experimental-67a44bcd-20250915" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-67a44bcd-20250915.tgz#5116b798e0574fce3decfa25f7ba493623b9a564" + integrity sha512-No88tqsklmnvXZBsKUAFG71vZeJtaGQCmZp7BI4085FJ1ZHFBX7rdI37oQAZfaVaoPPZiio6XCV7/PtyUu0M6A== dependencies: - scheduler "^0.26.0" + scheduler "0.0.0-experimental-67a44bcd-20250915" react-is@^16.13.1: version "16.13.1" @@ -3594,10 +3594,10 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -react@19.1.1: - version "19.1.1" - resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af" - integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ== +react@^0.0.0-experimental-67a44bcd-20250915: + version "0.0.0-experimental-67a44bcd-20250915" + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-67a44bcd-20250915.tgz#803c74089c9abe1ba290de659c3e34d5709032b8" + integrity sha512-eMX1vgHKP6mlwNWrcH405h6F6Ut6AR7jeON+nFc7+vrcxbZvbVBTd9eZVE4ml2bxz7uoNGFNPd3p6SgtdlCvWQ== read-cache@^1.0.0: version "1.0.0" @@ -3773,10 +3773,10 @@ safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -scheduler@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" - integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== +scheduler@0.0.0-experimental-67a44bcd-20250915: + version "0.0.0-experimental-67a44bcd-20250915" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-67a44bcd-20250915.tgz#5af10b25cb263a6471d885192dc7ac42d2ff4c51" + integrity sha512-vs2NDlwa5YAI2VK/Qgpue/0ldvyiy4z3K1UkIoIull5Ehcuojf5UeE0qXvibJ1AP3zJKYWEbBMSNpneJzlbsPA== semver@^6.3.1: version "6.3.1" From 84f2e54153bc4934f60826e4c0d850902c2e34f9 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Mon, 15 Sep 2025 16:14:26 -0400 Subject: [PATCH 14/24] Change versioning for experimental --- .../components/Editor/ConfigEditor.tsx | 7 +- compiler/apps/playground/next-env.d.ts | 2 +- compiler/apps/playground/package.json | 4 +- compiler/apps/playground/tsconfig.json | 2 +- compiler/apps/playground/yarn.lock | 121 +++++++++--------- 5 files changed, 69 insertions(+), 67 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index a2614454904..97e836b1d6f 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -21,9 +21,6 @@ import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts'; loader.config({monaco}); -console.log('Acitivty import:', Activity); -console.log('React import:', React); - export default function ConfigEditor({ appliedOptions, }: { @@ -33,17 +30,15 @@ export default function ConfigEditor({ return ( <> - {/* + - ; - ; */} ); } diff --git a/compiler/apps/playground/next-env.d.ts b/compiler/apps/playground/next-env.d.ts index 830fb594ca2..9edff1c7cac 100644 --- a/compiler/apps/playground/next-env.d.ts +++ b/compiler/apps/playground/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -/// +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index fd84ee6624e..3798587632e 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -34,7 +34,7 @@ "invariant": "^2.2.4", "lz-string": "^1.5.0", "monaco-editor": "^0.52.0", - "next": "15.5.2", + "next": "15.6.0-canary.7", "notistack": "^3.0.0-alpha.7", "prettier": "^3.3.3", "pretty-format": "^29.3.1", @@ -44,7 +44,7 @@ }, "devDependencies": { "@types/node": "18.11.9", - "@types/react": "19.1.12", + "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "autoprefixer": "^10.4.13", "clsx": "^1.2.1", diff --git a/compiler/apps/playground/tsconfig.json b/compiler/apps/playground/tsconfig.json index 1ead55cc96e..4f70dcef8ab 100644 --- a/compiler/apps/playground/tsconfig.json +++ b/compiler/apps/playground/tsconfig.json @@ -19,7 +19,7 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index c1b73e372c5..20477801d64 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -715,10 +715,10 @@ dependencies: "@monaco-editor/loader" "^1.4.0" -"@next/env@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/env/-/env-15.5.2.tgz#0c6b959313cd6e71afb69bf0deb417237f1d2f8a" - integrity sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg== +"@next/env@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.6.0-canary.7.tgz#cdbf2967a9437ef09eef755e203f315acc4d8d8f" + integrity sha512-LNZ7Yd3Cl9rKvjYdeJmszf2HmSDP76SQmfafKep2Ux16ZXKoN5OjwVHFTltKNdsB3vt2t+XJzLP2rhw5lBoFBA== "@next/eslint-plugin-next@15.5.2": version "15.5.2" @@ -727,45 +727,45 @@ dependencies: fast-glob "3.3.1" -"@next/swc-darwin-arm64@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.2.tgz#f69713326fc08f2eff3726fe19165cdb429d67c7" - integrity sha512-8bGt577BXGSd4iqFygmzIfTYizHb0LGWqH+qgIF/2EDxS5JsSdERJKA8WgwDyNBZgTIIA4D8qUtoQHmxIIquoQ== - -"@next/swc-darwin-x64@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.2.tgz#560a9da4126bae75cbbd6899646ad7a2e4fdcc9b" - integrity sha512-2DjnmR6JHK4X+dgTXt5/sOCu/7yPtqpYt8s8hLkHFK3MGkka2snTv3yRMdHvuRtJVkPwCGsvBSwmoQCHatauFQ== - -"@next/swc-linux-arm64-gnu@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.2.tgz#80b2be276e775e5a9286369ae54e536b0cdf8c3a" - integrity sha512-3j7SWDBS2Wov/L9q0mFJtEvQ5miIqfO4l7d2m9Mo06ddsgUK8gWfHGgbjdFlCp2Ek7MmMQZSxpGFqcC8zGh2AA== - -"@next/swc-linux-arm64-musl@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.2.tgz#68cf676301755fd99aca11a7ebdb5eae88d7c2e4" - integrity sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g== - -"@next/swc-linux-x64-gnu@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.2.tgz#209d9a79d0f2333544f863b0daca3f7e29f2eaff" - integrity sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q== - -"@next/swc-linux-x64-musl@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.2.tgz#d4ad1cfb5e99e51db669fe2145710c1abeadbd7f" - integrity sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g== - -"@next/swc-win32-arm64-msvc@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.2.tgz#070e10e370a5447a198c2db100389646aca2c496" - integrity sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg== - -"@next/swc-win32-x64-msvc@15.5.2": - version "15.5.2" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.2.tgz#9237d40b82eaf2efc88baeba15b784d4126caf4a" - integrity sha512-W5VvyZHnxG/2ukhZF/9Ikdra5fdNftxI6ybeVKYvBPDtyx7x4jPPSNduUkfH5fo3zG0JQ0bPxgy41af2JX5D4Q== +"@next/swc-darwin-arm64@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.6.0-canary.7.tgz#628cd34ce9120000f1cb5b08963426431174fc57" + integrity sha512-POsBrxhrR3qvqXV+JZ6ZoBc8gJf8rhYe+OedceI1piPVqtJYOJa3EB4eaqcc+kMsllKRrH/goNlhLwtyhE+0Qg== + +"@next/swc-darwin-x64@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.6.0-canary.7.tgz#37d4ebab14da74a2f8028daf6d76aab410153e06" + integrity sha512-lmk9ysBuSiPlAJZTCo/3O4mXNFosg6EDIf4GrmynIwCG2as6/KxzyD1WqFp56Exp8eFDjP7SFapD10sV43vCsA== + +"@next/swc-linux-arm64-gnu@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.6.0-canary.7.tgz#ce700cc0e0d24763136838223105a524b36694fa" + integrity sha512-why8k6d0SBm3AKoOD5S7ir3g+BF34l9oFKIoZrLaZaKBvNGpFcjc7Ovc2TunNMeaMJzv9k1dHYSap0EI5oSuzg== + +"@next/swc-linux-arm64-musl@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.6.0-canary.7.tgz#c791b8e15bf2c338b4cc0387fe7afb3ef83ecfcf" + integrity sha512-HzvTRsKvYj32Va4YuJN3n3xOxvk+6QwB63d/EsgmdkeA/vrqciUAmJDYpuzZEvRc3Yp2nyPq8KZxtHAr6ISZ2Q== + +"@next/swc-linux-x64-gnu@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.6.0-canary.7.tgz#c01c3a3d8e71660c49298dd053d078379b6b5919" + integrity sha512-6yRFrg2qWXOqa+1BI53J9EmHWFzKg9U2r+5R7n7BFUp8PH5SC92WBsmYTnh/RkvAYvdupiVzMervwwswCs6kFg== + +"@next/swc-linux-x64-musl@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.6.0-canary.7.tgz#3f4b39faef4a5f88b13e4c726b008ddc9717f819" + integrity sha512-O/JjvOvNK/Wao/OIQaA6evDkxkmFFQgJ1/hI1dVk6/PAeKmW2/Q+6Dodh97eAkOwedS1ZdQl2mojf87TzLvzdQ== + +"@next/swc-win32-arm64-msvc@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.6.0-canary.7.tgz#9bc5da0907b7ce67eedda02a6d56a09d9a539ccf" + integrity sha512-p9DvrDgnePofZCtiWVY7qZtwXxiOGJlAyy2LoGPYSGOUDhjbTG8j6XMUFXpV9UwpH+l7st522psO1BVzbpT8IQ== + +"@next/swc-win32-x64-msvc@15.6.0-canary.7": + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.6.0-canary.7.tgz#5b271c591ccbe67d5fa966dd22db86c547414fd1" + integrity sha512-f1ywT3xWu4StWKA1mZRyGfelu/h+W0OEEyBxQNXzXyYa0VGZb9LyCNb5cYoNKBm0Bw18Hp1PVe0bHuusemGCcw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -854,7 +854,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== -"@types/react-dom@19.1.9": +"@types/react-dom@19.1.9", "@types/react-dom@^19.1.9": version "19.1.9" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.9.tgz#5ab695fce1e804184767932365ae6569c11b4b4b" integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ== @@ -866,6 +866,13 @@ dependencies: csstype "^3.0.2" +"@types/react@^19.1.13": + version "19.1.13" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.13.tgz#fc650ffa680d739a25a530f5d7ebe00cdd771883" + integrity sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ== + dependencies: + csstype "^3.0.2" + "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": version "8.10.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.10.0.tgz#9c8218ed62f9a322df10ded7c34990f014df44f2" @@ -3199,25 +3206,25 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@15.5.2: - version "15.5.2" - resolved "https://registry.yarnpkg.com/next/-/next-15.5.2.tgz#5e50102443fb0328a9dfcac2d82465c7bac93693" - integrity sha512-H8Otr7abj1glFhbGnvUt3gz++0AF1+QoCXEBmd/6aKbfdFwrn0LpA836Ed5+00va/7HQSDD+mOoVhn3tNy3e/Q== +next@15.6.0-canary.7: + version "15.6.0-canary.7" + resolved "https://registry.yarnpkg.com/next/-/next-15.6.0-canary.7.tgz#bfc2ac3c9a78e23d550c303d18247a263e6b5bc1" + integrity sha512-4ukX2mxat9wWT6E0Gw/3TOR9ULV1q399E42F86cwsPSFgTWa04ABhcTqO0r9J/QR1YWPR8WEgh9qUzmWA/1yEw== dependencies: - "@next/env" "15.5.2" + "@next/env" "15.6.0-canary.7" "@swc/helpers" "0.5.15" caniuse-lite "^1.0.30001579" postcss "8.4.31" styled-jsx "5.1.6" optionalDependencies: - "@next/swc-darwin-arm64" "15.5.2" - "@next/swc-darwin-x64" "15.5.2" - "@next/swc-linux-arm64-gnu" "15.5.2" - "@next/swc-linux-arm64-musl" "15.5.2" - "@next/swc-linux-x64-gnu" "15.5.2" - "@next/swc-linux-x64-musl" "15.5.2" - "@next/swc-win32-arm64-msvc" "15.5.2" - "@next/swc-win32-x64-msvc" "15.5.2" + "@next/swc-darwin-arm64" "15.6.0-canary.7" + "@next/swc-darwin-x64" "15.6.0-canary.7" + "@next/swc-linux-arm64-gnu" "15.6.0-canary.7" + "@next/swc-linux-arm64-musl" "15.6.0-canary.7" + "@next/swc-linux-x64-gnu" "15.6.0-canary.7" + "@next/swc-linux-x64-musl" "15.6.0-canary.7" + "@next/swc-win32-arm64-msvc" "15.6.0-canary.7" + "@next/swc-win32-x64-msvc" "15.6.0-canary.7" sharp "^0.34.3" node-releases@^2.0.18: From f527d55f65c15a261e3c81a375625507c7c35792 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Tue, 16 Sep 2025 15:11:35 -0400 Subject: [PATCH 15/24] add debouncing, improve show/hide --- .../components/Editor/ConfigEditor.tsx | 48 ++++++++++++++----- compiler/apps/playground/lib/stores/store.ts | 2 +- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 7ae17c3d3db..60ff6b03917 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -9,7 +9,7 @@ import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react'; import {PluginOptions} from 'babel-plugin-react-compiler'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; -import React, {useState, Activity} from 'react'; +import React, {useState, useRef, useEffect} from 'react'; import {Resizable} from 're-resizable'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; @@ -30,15 +30,21 @@ export default function ConfigEditor({ return ( <> - +
- - +
+
- +
); } @@ -52,16 +58,34 @@ function ExpandedEditor({ }): React.ReactElement { const store = useStore(); const dispatchStore = useStoreDispatch(); + const debounceTimerRef = useRef(null); + + // Cleanup timeout on unmount + useEffect(() => { + return () => { + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current); + } + }; + }, []); - const handleChange: (value: string | undefined) => void = value => { + const handleChange: (value: string | undefined) => void = ( + value: string | undefined, + ) => { if (value === undefined) return; - dispatchStore({ - type: 'updateConfig', - payload: { - config: value, - }, - }); + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current); + } + + debounceTimerRef.current = setTimeout(() => { + dispatchStore({ + type: 'updateConfig', + payload: { + config: value, + }, + }); + }, 500); // 500ms debounce delay }; const handleMount: ( diff --git a/compiler/apps/playground/lib/stores/store.ts b/compiler/apps/playground/lib/stores/store.ts index e67578c79bf..c8ad9f94707 100644 --- a/compiler/apps/playground/lib/stores/store.ts +++ b/compiler/apps/playground/lib/stores/store.ts @@ -71,7 +71,7 @@ export function initStoreFromUrlOrLocalStorage(): Store { // Make sure all properties are populated return { source: raw.source, - config: 'config' in raw ? raw.config : defaultConfig, + config: 'config' in raw && raw['`config'] ? raw.config : defaultConfig, showInternals: 'showInternals' in raw ? raw.showInternals : false, }; } From d84a5873bde38d7e0663475f4992a4f72b3fd501 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 17 Sep 2025 10:45:41 -0400 Subject: [PATCH 16/24] Remove loading indicator --- .../components/Editor/ConfigEditor.tsx | 8 ++---- .../playground/components/Editor/Input.tsx | 26 +++++++------------ .../playground/components/Editor/Output.tsx | 2 ++ .../components/Editor/monacoOptions.ts | 2 ++ compiler/apps/playground/next.config.js | 1 + 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 60ff6b03917..ac9639ff9b5 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -109,12 +109,6 @@ function ExpandedEditor({ allowSyntheticDefaultImports: true, jsx: monaco.languages.typescript.JsxEmit.React, }); - - const uri = monaco.Uri.parse(`file:///config.ts`); - const model = monaco.editor.getModel(uri); - if (model) { - model.updateOptions({tabSize: 2}); - } }; const formattedAppliedOptions = appliedOptions @@ -158,6 +152,7 @@ function ExpandedEditor({ value={store.config} onMount={handleMount} onChange={handleChange} + loading={''} options={{ ...monacoOptions, lineNumbers: 'off', @@ -182,6 +177,7 @@ function ExpandedEditor({ path={'applied-config.js'} language={'javascript'} value={formattedAppliedOptions} + loading={''} options={{ ...monacoOptions, lineNumbers: 'off', diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index f25bb115a68..d8744c3ca97 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -45,11 +45,6 @@ export default function Input({errors, language}: Props): JSX.Element { details: errors, source: store.source, }); - /** - * N.B. that `tabSize` is a model property, not an editor property. - * So, the tab size has to be set per model. - */ - model.updateOptions({tabSize: 2}); }, [monaco, errors, store.source]); useEffect(() => { @@ -151,25 +146,24 @@ export default function Input({errors, language}: Props): JSX.Element { onMount={handleMount} onChange={handleChange} options={monacoOptions} + loading={''} /> ); const tabs = new Map([['Input', editorContent]]); const [activeTab, setActiveTab] = useState('Input'); - const tabbedContent = ( -
- -
- ); - return (
-
{tabbedContent}
+
+
+ +
+
); } diff --git a/compiler/apps/playground/components/Editor/Output.tsx b/compiler/apps/playground/components/Editor/Output.tsx index 22f908e51bb..bf73c192c11 100644 --- a/compiler/apps/playground/components/Editor/Output.tsx +++ b/compiler/apps/playground/components/Editor/Output.tsx @@ -324,6 +324,7 @@ function TextTabContent({ = { automaticLayout: true, wordWrap: 'on', wrappingIndent: 'same', + + tabSize: 2, }; diff --git a/compiler/apps/playground/next.config.js b/compiler/apps/playground/next.config.js index fc8a9492e4e..f34f958ec6d 100644 --- a/compiler/apps/playground/next.config.js +++ b/compiler/apps/playground/next.config.js @@ -11,6 +11,7 @@ const path = require('path'); const nextConfig = { experimental: { reactCompiler: true, + viewTransition: true, }, reactStrictMode: true, webpack: (config, options) => { From b201a1d00b43951d5eccf59f66e20700bbd77e3a Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 17 Sep 2025 16:41:34 -0400 Subject: [PATCH 17/24] remove old index --- compiler/apps/playground/app/index.tsx | 56 -------------------------- 1 file changed, 56 deletions(-) delete mode 100644 compiler/apps/playground/app/index.tsx diff --git a/compiler/apps/playground/app/index.tsx b/compiler/apps/playground/app/index.tsx deleted file mode 100644 index 3bbf2e9b555..00000000000 --- a/compiler/apps/playground/app/index.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type {NextPage} from 'next'; -import Head from 'next/head'; -import {SnackbarProvider} from 'notistack'; -import {Editor, Header, StoreProvider} from '../components'; -import MessageSnackbar from '../components/Message'; - -const Home: NextPage = () => { - return ( -
- - - {process.env.NODE_ENV === 'development' - ? '[DEV] React Compiler Playground' - : 'React Compiler Playground'} - - - - - - - - - -
- - - -
- ); -}; - -export default Home; From bdde8ec3b722aeb47645294959a14c03a6d99c22 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 17 Sep 2025 16:41:44 -0400 Subject: [PATCH 18/24] Try new store loading --- .../components/Editor/ConfigEditor.tsx | 4 +- .../components/Editor/EditorImpl.tsx | 42 +------------------ .../playground/components/StoreContext.tsx | 26 ++++++++++-- 3 files changed, 25 insertions(+), 47 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index ac9639ff9b5..2392611f365 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -61,8 +61,8 @@ function ExpandedEditor({ const debounceTimerRef = useRef(null); // Cleanup timeout on unmount - useEffect(() => { - return () => { + useEffect((): (() => void) => { + return (): void => { if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index 8b75ce6ac5e..696bbd2559c 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -24,19 +24,8 @@ import BabelPluginReactCompiler, { printFunctionWithOutlined, type LoggerEvent, } from 'babel-plugin-react-compiler'; -import invariant from 'invariant'; -import {useSnackbar} from 'notistack'; import {useDeferredValue, useMemo} from 'react'; -import {useMountEffect} from '../../hooks'; -import {defaultStore} from '../../lib/defaultStore'; -import { - createMessage, - initStoreFromUrlOrLocalStorage, - MessageLevel, - MessageSource, - type Store, -} from '../../lib/stores'; -import {useStore, useStoreDispatch} from '../StoreContext'; +import {useStore} from '../StoreContext'; import ConfigEditor from './ConfigEditor'; import Input from './Input'; import { @@ -174,7 +163,6 @@ function parseOptions( // Parse config overrides from config editor let configOverrideOptions: any = {}; const configMatch = configOverrides.match(/^\s*import.*?\n\n\((.*)\)/s); - // TODO: initialize store with URL params, not empty store if (configOverrides.trim()) { if (configMatch && configMatch[1]) { const configString = configMatch[1].replace(/satisfies.*$/, '').trim(); @@ -327,8 +315,6 @@ function compile( export default function Editor(): JSX.Element { const store = useStore(); const deferredStore = useDeferredValue(store); - const dispatchStore = useStoreDispatch(); - const {enqueueSnackbar} = useSnackbar(); const [compilerOutput, language, appliedOptions] = useMemo( () => compile(deferredStore.source, 'compiler', deferredStore.config), [deferredStore.source, deferredStore.config], @@ -338,32 +324,6 @@ export default function Editor(): JSX.Element { [deferredStore.source, deferredStore.config], ); - useMountEffect(() => { - // Initialize store - let mountStore: Store; - try { - mountStore = initStoreFromUrlOrLocalStorage(); - } catch (e) { - invariant(e instanceof Error, 'Only Error may be caught.'); - enqueueSnackbar(e.message, { - variant: 'warning', - ...createMessage( - 'Bad URL - fell back to the default Playground.', - MessageLevel.Info, - MessageSource.Playground, - ), - }); - mountStore = defaultStore; - } - - dispatchStore({ - type: 'setStore', - payload: { - store: mountStore, - }, - }); - }); - let mergedOutput: CompilerOutput; let errors: Array; if (compilerOutput.kind === 'ok') { diff --git a/compiler/apps/playground/components/StoreContext.tsx b/compiler/apps/playground/components/StoreContext.tsx index 52de6c0fa3e..3f55678edf1 100644 --- a/compiler/apps/playground/components/StoreContext.tsx +++ b/compiler/apps/playground/components/StoreContext.tsx @@ -6,10 +6,14 @@ */ import type {Dispatch, ReactNode} from 'react'; -import {useEffect, useReducer} from 'react'; +import {useState, useEffect, useReducer} from 'react'; import createContext from '../lib/createContext'; -import {emptyStore} from '../lib/defaultStore'; -import {saveStore, type Store} from '../lib/stores'; +import {emptyStore, defaultStore} from '../lib/defaultStore'; +import { + saveStore, + initStoreFromUrlOrLocalStorage, + type Store, +} from '../lib/stores'; const StoreContext = createContext(); @@ -30,6 +34,20 @@ export const useStoreDispatch = StoreDispatchContext.useContext; */ export function StoreProvider({children}: {children: ReactNode}): JSX.Element { const [store, dispatch] = useReducer(storeReducer, emptyStore); + const [isPageReady, setIsPageReady] = useState(false); + + useEffect(() => { + let mountStore: Store; + try { + mountStore = initStoreFromUrlOrLocalStorage(); + } catch (e) { + console.error('Failed to initialize store from URL or local storage', e); + mountStore = defaultStore; + } + dispatch({type: 'setStore', payload: {store: mountStore}}); + setIsPageReady(true); + }, []); + useEffect(() => { if (store !== emptyStore) { saveStore(store); @@ -39,7 +57,7 @@ export function StoreProvider({children}: {children: ReactNode}): JSX.Element { return ( - {children} + {isPageReady ? children : null} ); From 87339bbd92f24fae0a4e99e69d143f586344ad34 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 17 Sep 2025 16:53:22 -0400 Subject: [PATCH 19/24] Remove unecessary text --- compiler/apps/playground/components/AccordionWindow.tsx | 9 --------- compiler/apps/playground/components/TabbedWindow.tsx | 7 ------- 2 files changed, 16 deletions(-) diff --git a/compiler/apps/playground/components/AccordionWindow.tsx b/compiler/apps/playground/components/AccordionWindow.tsx index de3b01b0b05..bebbb0c4787 100644 --- a/compiler/apps/playground/components/AccordionWindow.tsx +++ b/compiler/apps/playground/components/AccordionWindow.tsx @@ -17,15 +17,6 @@ export default function AccordionWindow(props: { setTabsOpen: (newTab: Set) => void; changedPasses: Set; }): React.ReactElement { - if (props.tabs.size === 0) { - return ( -
- No compiler output detected, see errors below -
- ); - } return (
{Array.from(props.tabs.keys()).map(name => { diff --git a/compiler/apps/playground/components/TabbedWindow.tsx b/compiler/apps/playground/components/TabbedWindow.tsx index 1751bd87e26..d2335687c22 100644 --- a/compiler/apps/playground/components/TabbedWindow.tsx +++ b/compiler/apps/playground/components/TabbedWindow.tsx @@ -16,13 +16,6 @@ export default function TabbedWindow({ activeTab: string; onTabChange: (tab: string) => void; }): React.ReactElement { - if (tabs.size === 0) { - return ( -
- No compiler output detected, see errors below -
- ); - } return (
From 201301eace94a17791f1573c9ea98a8fd6856978 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 17 Sep 2025 17:57:22 -0400 Subject: [PATCH 20/24] update tests --- compiler/apps/playground/__tests__/e2e/page.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/apps/playground/__tests__/e2e/page.spec.ts b/compiler/apps/playground/__tests__/e2e/page.spec.ts index 296f45a2776..17505024ffe 100644 --- a/compiler/apps/playground/__tests__/e2e/page.spec.ts +++ b/compiler/apps/playground/__tests__/e2e/page.spec.ts @@ -136,7 +136,7 @@ test('editor should compile from hash successfully', async ({page}) => { path: 'test-results/01-compiles-from-hash.png', }); const text = - (await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? []; + (await page.locator('.monaco-editor').nth(3).allInnerTexts()) ?? []; const output = await formatPrint(text); expect(output).not.toEqual(''); @@ -162,7 +162,7 @@ test('reset button works', async ({page}) => { path: 'test-results/02-reset-button-works.png', }); const text = - (await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? []; + (await page.locator('.monaco-editor').nth(3).allInnerTexts()) ?? []; const output = await formatPrint(text); expect(output).not.toEqual(''); @@ -183,7 +183,7 @@ TEST_CASE_INPUTS.forEach((t, idx) => }); const text = - (await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? []; + (await page.locator('.monaco-editor').nth(3).allInnerTexts()) ?? []; let output: string; if (t.noFormat) { output = text.join(''); From 8a7d036ebf615a66cf78d9d64a97ca1a90324d3d Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Wed, 17 Sep 2025 19:25:00 -0400 Subject: [PATCH 21/24] update yarn --- compiler/apps/playground/yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index 20477801d64..4661c0cca5c 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -854,7 +854,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== -"@types/react-dom@19.1.9", "@types/react-dom@^19.1.9": +"@types/react-dom@19.1.9": version "19.1.9" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.9.tgz#5ab695fce1e804184767932365ae6569c11b4b4b" integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ== @@ -866,7 +866,7 @@ dependencies: csstype "^3.0.2" -"@types/react@^19.1.13": +"@types/react@19.1.13": version "19.1.13" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.13.tgz#fc650ffa680d739a25a530f5d7ebe00cdd771883" integrity sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ== From 59f54a2b7ecc1e76b5f62d7c45be027e9f9f0e93 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Thu, 18 Sep 2025 12:54:54 -0400 Subject: [PATCH 22/24] Revert experimental react for now --- .../components/Editor/ConfigEditor.tsx | 1 + compiler/apps/playground/next.config.js | 1 - compiler/apps/playground/package.json | 4 +-- compiler/apps/playground/yarn.lock | 26 +++++++++---------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 2392611f365..827ef587975 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -29,6 +29,7 @@ export default function ConfigEditor({ const [isExpanded, setIsExpanded] = useState(false); return ( + // TODO: Use when it is compatible with Monaco: https://github.com/suren-atoyan/monaco-react/issues/753 <>
{ diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index 3798587632e..08aed45e0f3 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -39,8 +39,8 @@ "prettier": "^3.3.3", "pretty-format": "^29.3.1", "re-resizable": "^6.9.16", - "react": "^0.0.0-experimental-67a44bcd-20250915", - "react-dom": "^0.0.0-experimental-67a44bcd-20250915" + "react": "19.1.1", + "react-dom": "19.1.1" }, "devDependencies": { "@types/node": "18.11.9", diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index 4661c0cca5c..53f0d24db70 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -3584,12 +3584,12 @@ re-resizable@^6.9.16: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee" integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw== -react-dom@^0.0.0-experimental-67a44bcd-20250915: - version "0.0.0-experimental-67a44bcd-20250915" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-67a44bcd-20250915.tgz#5116b798e0574fce3decfa25f7ba493623b9a564" - integrity sha512-No88tqsklmnvXZBsKUAFG71vZeJtaGQCmZp7BI4085FJ1ZHFBX7rdI37oQAZfaVaoPPZiio6XCV7/PtyUu0M6A== +react-dom@19.1.1: + version "19.1.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.1.tgz#2daa9ff7f3ae384aeb30e76d5ee38c046dc89893" + integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw== dependencies: - scheduler "0.0.0-experimental-67a44bcd-20250915" + scheduler "^0.26.0" react-is@^16.13.1: version "16.13.1" @@ -3601,10 +3601,10 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -react@^0.0.0-experimental-67a44bcd-20250915: - version "0.0.0-experimental-67a44bcd-20250915" - resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-67a44bcd-20250915.tgz#803c74089c9abe1ba290de659c3e34d5709032b8" - integrity sha512-eMX1vgHKP6mlwNWrcH405h6F6Ut6AR7jeON+nFc7+vrcxbZvbVBTd9eZVE4ml2bxz7uoNGFNPd3p6SgtdlCvWQ== +react@19.1.1: + version "19.1.1" + resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af" + integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ== read-cache@^1.0.0: version "1.0.0" @@ -3780,10 +3780,10 @@ safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -scheduler@0.0.0-experimental-67a44bcd-20250915: - version "0.0.0-experimental-67a44bcd-20250915" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-67a44bcd-20250915.tgz#5af10b25cb263a6471d885192dc7ac42d2ff4c51" - integrity sha512-vs2NDlwa5YAI2VK/Qgpue/0ldvyiy4z3K1UkIoIull5Ehcuojf5UeE0qXvibJ1AP3zJKYWEbBMSNpneJzlbsPA== +scheduler@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" + integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== semver@^6.3.1: version "6.3.1" From d158da1985288ca0be4c44a6e30e3b38d3d91585 Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Thu, 18 Sep 2025 13:09:02 -0400 Subject: [PATCH 23/24] remove cleanup effect --- .../apps/playground/components/Editor/ConfigEditor.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index 827ef587975..add42018a38 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -61,15 +61,6 @@ function ExpandedEditor({ const dispatchStore = useStoreDispatch(); const debounceTimerRef = useRef(null); - // Cleanup timeout on unmount - useEffect((): (() => void) => { - return (): void => { - if (debounceTimerRef.current) { - clearTimeout(debounceTimerRef.current); - } - }; - }, []); - const handleChange: (value: string | undefined) => void = ( value: string | undefined, ) => { From 030099ec9ecf6596ffc4a860b3e06df8aa6b555e Mon Sep 17 00:00:00 2001 From: Eugene Choi <4eugenechoi@gmail.com> Date: Thu, 18 Sep 2025 15:33:12 -0400 Subject: [PATCH 24/24] typo fix --- compiler/apps/playground/lib/stores/store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/apps/playground/lib/stores/store.ts b/compiler/apps/playground/lib/stores/store.ts index c8ad9f94707..6655efa2740 100644 --- a/compiler/apps/playground/lib/stores/store.ts +++ b/compiler/apps/playground/lib/stores/store.ts @@ -71,7 +71,7 @@ export function initStoreFromUrlOrLocalStorage(): Store { // Make sure all properties are populated return { source: raw.source, - config: 'config' in raw && raw['`config'] ? raw.config : defaultConfig, + config: 'config' in raw && raw['config'] ? raw.config : defaultConfig, showInternals: 'showInternals' in raw ? raw.showInternals : false, }; }