@samitouri / QOS-React / commits / 67a44bcd1b

Playground applied configs (#34474)

<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory. Before submitting a pull request, please make sure the following is done: 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. 6. If you need a debugger, run `yarn test --debug --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). 10. If you haven't already, complete the CLA. Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html --> ## Summary Added an "Applied Configs" section under the Config Overrides panel. Users will now be able to see the full list of configs applied to the compiler in the playground. Adds greater discoverability for config options to override as well. Updated the default config as well to be a commented config option, so users will start with empty overrides. <!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? --> ## How did you test this change? https://github.com/user-attachments/assets/1a57b2d5-0405-4fc8-9990-1747c30181c0 <!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface. How exactly did you verify that your PR solves the issue you wanted to solve? If you leave this empty, your PR will very likely be closed. -->

Eugene Choi committed Sep 15, 2025 at 12:13 UTC 67a44bcd1b09ab809cf503b39c2568212e13e1a5
4 files changed +89 -56
compiler/apps/playground/components/Editor/ConfigEditor.tsx
+81 -47
@@ -6,6 +6,7 @@
6 */
7
8 import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';
9 +import {PluginOptions} from 'babel-plugin-react-compiler';
10 import type {editor} from 'monaco-editor';
11 import * as monaco from 'monaco-editor';
12 import React, {useState} from 'react';
@@ -13,30 +14,33 @@ import {Resizable} from 're-resizable';
14 import {useStore, useStoreDispatch} from '../StoreContext';
15 import {monacoOptions} from './monacoOptions';
16 import {IconChevron} from '../Icons/IconChevron';
17 +import prettyFormat from 'pretty-format';
18
19 // @ts-expect-error - webpack asset/source loader handles .d.ts files as strings
20 import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts';
21
22 loader.config({monaco});
23
22 -export default function ConfigEditor(): React.ReactElement {
24 +export default function ConfigEditor({
25 + appliedOptions,
26 +}: {
27 + appliedOptions: PluginOptions | null;
28 +}): React.ReactElement {
29 const [isExpanded, setIsExpanded] = useState(false);
30
25 - return (
26 - <div className="flex flex-row relative">
27 - {isExpanded ? (
28 - <ExpandedEditor onToggle={setIsExpanded} />
29 - ) : (
30 - <CollapsedEditor onToggle={setIsExpanded} />
31 - )}
32 - </div>
31 + return isExpanded ? (
32 + <ExpandedEditor onToggle={setIsExpanded} appliedOptions={appliedOptions} />
33 + ) : (
34 + <CollapsedEditor onToggle={setIsExpanded} />
35 );
36 }
37
38 function ExpandedEditor({
39 onToggle,
40 + appliedOptions,
41 }: {
42 onToggle: (expanded: boolean) => void;
43 + appliedOptions: PluginOptions | null;
44 }): React.ReactElement {
45 const store = useStore();
46 const dispatchStore = useStoreDispatch();
@@ -81,22 +85,22 @@ function ExpandedEditor({
85 }
86 };
87
88 + const formattedAppliedOptions = appliedOptions
89 + ? prettyFormat(appliedOptions, {
90 + printFunctionName: false,
91 + printBasicPrototype: false,
92 + })
93 + : 'Invalid configs';
94 +
95 return (
96 <Resizable
86 - className="border-r"
97 minWidth={300}
98 maxWidth={600}
89 - defaultSize={{width: 350, height: 'auto'}}
90 - enable={{right: true, bottom: false}}
91 - style={{position: 'relative', height: 'calc(100vh - 3.5rem)'}}>
92 - <div className="bg-gray-700 p-2">
93 - <div className="pb-2">
94 - <h2 className="inline-block text-secondary-dark text-center outline-none py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full capitalize whitespace-nowrap text-sm">
95 - Config Overrides
96 - </h2>
97 - </div>
99 + defaultSize={{width: 350}}
100 + enable={{right: true, bottom: false}}>
101 + <div className="bg-blue-10 relative h-full flex flex-col !h-[calc(100vh_-_3.5rem)] border border-gray-300">
102 <div
99 - className="absolute w-10 h-16 bg-gray-700 hover:translate-x-2 transition-transform rounded-r-full flex items-center justify-center z-[5] cursor-pointer"
103 + className="absolute w-8 h-16 bg-blue-10 rounded-r-full flex items-center justify-center z-[2] cursor-pointer border border-l-0 border-gray-300"
104 title="Minimize config editor"
105 onClick={() => onToggle(false)}
106 style={{
@@ -106,30 +110,60 @@ function ExpandedEditor({
110 borderTopLeftRadius: 0,
111 borderBottomLeftRadius: 0,
112 }}>
109 - <IconChevron
110 - displayDirection="left"
111 - className="text-secondary-dark"
112 - />
113 + <IconChevron displayDirection="left" className="text-blue-50" />
114 + </div>
115 +
116 + <div className="flex-1 flex flex-col m-2 mb-2">
117 + <div className="pb-2">
118 + <h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">
119 + Config Overrides
120 + </h2>
121 + </div>
122 + <div className="flex-1 rounded-lg overflow-hidden border border-gray-300">
123 + <MonacoEditor
124 + path={'config.ts'}
125 + language={'typescript'}
126 + value={store.config}
127 + onMount={handleMount}
128 + onChange={handleChange}
129 + options={{
130 + ...monacoOptions,
131 + lineNumbers: 'off',
132 + renderLineHighlight: 'none',
133 + overviewRulerBorder: false,
134 + overviewRulerLanes: 0,
135 + fontSize: 12,
136 + scrollBeyondLastLine: false,
137 + glyphMargin: false,
138 + }}
139 + />
140 + </div>
141 </div>
114 - <div className="h-[calc(100vh_-_3.5rem_-_3.5rem)] rounded-lg overflow-hidden">
115 - <MonacoEditor
116 - path={'config.ts'}
117 - language={'typescript'}
118 - value={store.config}
119 - onMount={handleMount}
120 - onChange={handleChange}
121 - options={{
122 - ...monacoOptions,
123 - lineNumbers: 'off',
124 - folding: false,
125 - renderLineHighlight: 'none',
126 - hideCursorInOverviewRuler: true,
127 - overviewRulerBorder: false,
128 - overviewRulerLanes: 0,
129 - fontSize: 12,
130 - scrollBeyondLastLine: false,
131 - }}
132 - />
142 +
143 + <div className="flex-1 flex flex-col m-2">
144 + <div className="pb-2">
145 + <h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">
146 + Applied Configs
147 + </h2>
148 + </div>
149 + <div className="flex-1 rounded-lg overflow-hidden border border-gray-300">
150 + <MonacoEditor
151 + path={'applied-config.js'}
152 + language={'javascript'}
153 + value={formattedAppliedOptions}
154 + options={{
155 + ...monacoOptions,
156 + lineNumbers: 'off',
157 + renderLineHighlight: 'none',
158 + overviewRulerBorder: false,
159 + overviewRulerLanes: 0,
160 + fontSize: 12,
161 + scrollBeyondLastLine: false,
162 + readOnly: true,
163 + glyphMargin: false,
164 + }}
165 + />
166 + </div>
167 </div>
168 </div>
169 </Resizable>
@@ -143,10 +177,10 @@ function CollapsedEditor({
177 }): React.ReactElement {
178 return (
179 <div
146 - className="w-4"
147 - style={{height: 'calc(100vh - 3.5rem)', position: 'relative'}}>
180 + className="w-4 !h-[calc(100vh_-_3.5rem)]"
181 + style={{position: 'relative'}}>
182 <div
149 - className="absolute w-10 h-16 bg-gray-700 hover:translate-x-2 transition-transform rounded-r-full flex items-center justify-center z-[5] cursor-pointer"
183 + className="absolute w-10 h-16 bg-blue-10 hover:translate-x-2 transition-transform rounded-r-full flex items-center justify-center z-[2] cursor-pointer border border-gray-300"
184 title="Expand config editor"
185 onClick={() => onToggle(true)}
186 style={{
@@ -156,7 +190,7 @@ function CollapsedEditor({
190 borderTopLeftRadius: 0,
191 borderBottomLeftRadius: 0,
192 }}>
159 - <IconChevron displayDirection="right" className="text-secondary-dark" />
193 + <IconChevron displayDirection="right" className="text-blue-50" />
194 </div>
195 </div>
196 );
compiler/apps/playground/components/Editor/EditorImpl.tsx
+6 -5
@@ -201,7 +201,7 @@ function compile(
201 source: string,
202 mode: 'compiler' | 'linter',
203 configOverrides: string,
204 -): [CompilerOutput, 'flow' | 'typescript'] {
204 +): [CompilerOutput, 'flow' | 'typescript', PluginOptions | null] {
205 const results = new Map<string, Array<PrintedCompilerPipelineValue>>();
206 const error = new CompilerError();
207 const otherErrors: Array<CompilerErrorDetail | CompilerDiagnostic> = [];
@@ -279,7 +279,7 @@ function compile(
279 ...baseOpts,
280 logger: {
281 debugLogIRs: logIR,
282 - logEvent: (_filename: string | null, event: LoggerEvent) => {
282 + logEvent: (_filename: string | null, event: LoggerEvent): void => {
283 if (event.kind === 'CompileError') {
284 otherErrors.push(event.detail);
285 }
@@ -315,11 +315,12 @@ function compile(
315 otherErrors.forEach(e => error.details.push(e));
316 }
317 if (error.hasErrors()) {
318 - return [{kind: 'err', results, error}, language];
318 + return [{kind: 'err', results, error}, language, baseOpts];
319 }
320 return [
321 {kind: 'ok', results, transformOutput, errors: error.details},
322 language,
323 + baseOpts,
324 ];
325 }
326
@@ -328,7 +329,7 @@ export default function Editor(): JSX.Element {
329 const deferredStore = useDeferredValue(store);
330 const dispatchStore = useStoreDispatch();
331 const {enqueueSnackbar} = useSnackbar();
331 - const [compilerOutput, language] = useMemo(
332 + const [compilerOutput, language, appliedOptions] = useMemo(
333 () => compile(deferredStore.source, 'compiler', deferredStore.config),
334 [deferredStore.source, deferredStore.config],
335 );
@@ -379,7 +380,7 @@ export default function Editor(): JSX.Element {
380 <>
381 <div className="relative flex top-14">
382 <div className="flex-shrink-0">
382 - <ConfigEditor />
383 + <ConfigEditor appliedOptions={appliedOptions} />
384 </div>
385 <div className="flex flex-1 min-w-0">
386 <div className="flex-1 min-w-[550px] sm:min-w-0">
compiler/apps/playground/components/TabbedWindow.tsx
+1 -1
@@ -33,7 +33,7 @@ export default function TabbedWindow({
33 key={tab}
34 onClick={() => onTabChange(tab)}
35 className={clsx(
36 - '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',
36 + 'active:scale-95 transition-transform py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full text-sm',
37 !isActive && 'hover:bg-primary/5',
38 isActive && 'bg-highlight text-link',
39 )}>
compiler/apps/playground/lib/defaultStore.ts
+1 -3
@@ -17,9 +17,7 @@ export const defaultConfig = `\
17 import type { PluginOptions } from 'babel-plugin-react-compiler/dist';
18
19 ({
20 - environment: {
21 - enableResetCacheOnSourceFileChanges: false
22 - }
20 + //compilationMode: "all"
21 } satisfies Partial<PluginOptions>);`;
22
23 export const defaultStore: Store = {