Skip to content

Commit

Permalink
fix: prevent unnecessary wrapping of single line jsx elements (#2183)
Browse files Browse the repository at this point in the history
When having a single line statement with an import statement everything works as expected.

```jsx
    import * as React from "react";
    <ReactComponent />;
```

However if you remove the import statement, a semicolon `;` appears in the output. We no longer need the explicit import statements as this can be configured globally, and we have an eslint rule requiring us to close every js statement with a semicolon.

```jsx
    <ReactComponent />;
```

This happens because of the fix/changes done in this issue: #842, which causes every statement starting with JSX to be wrapped in a Fragment. This will cause the semicolon to be added inside the Fragment, and cause it to be rendered.

This change causes the examples to only be wrapped in a Fragment if multiple jsx statements are returned on root level of the example by checking for the error before wrapping.

Co-authored-by: Thomas Roest <[email protected]>
  • Loading branch information
ThomasRoest and Thomas Roest authored Jan 7, 2025
1 parent 3ae63b6 commit c223f9a
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 14 deletions.
20 changes: 9 additions & 11 deletions src/client/utils/__tests__/compileCode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,16 @@ React.createElement( Button, null )"
`);
});

test('wrap JSX in Fragment', () => {
const result = compileCode(
`<div>
<button>Click</button>
</div>`,
compilerConfig
test('wrap JSX in Fragment if adjacent on line 1', () => {
const result = compileCode(`<span /><span />`, compilerConfig);
expect(result).toMatchInlineSnapshot(
`"React.createElement( React.Fragment, null, React.createElement( 'span', null ), React.createElement( 'span', null ) );"`
);
expect(result).toMatchInlineSnapshot(`
"React.createElement( React.Fragment, null, React.createElement( 'div', null,
React.createElement( 'button', null, \\"Click\\" )
) );"
`);
});

test('don’t wrap JSX in Fragment if there is only one statement', () => {
const result = compileCode(`<Button />;`, compilerConfig);
expect(result).toMatchInlineSnapshot(`"React.createElement( Button, null );"`);
});

test('don’t wrap JSX in Fragment if it’s in the middle', () => {
Expand Down
20 changes: 17 additions & 3 deletions src/client/utils/compileCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,23 @@ export default function compileCode(
onError?: (err: Error) => void
): string {
try {
const wrappedCode = startsWithJsx(code) ? wrapCodeInFragment(code) : code;
const compiledCode = compile(wrappedCode, compilerConfig);
return transpileImports(compiledCode);
let compiledCode;

try {
compiledCode = compile(code, compilerConfig);
} catch (err) {
if (
err instanceof SyntaxError &&
err.message.startsWith('Adjacent JSX elements must be wrapped in an enclosing tag')
) {
const wrappedCode = startsWithJsx(code) ? wrapCodeInFragment(code) : code;
compiledCode = compile(wrappedCode, compilerConfig);
} else if (onError && err instanceof Error) {
onError(err);
}
}

return compiledCode ? transpileImports(compiledCode) : '';
} catch (err) {
if (onError && err instanceof Error) {
onError(err);
Expand Down

0 comments on commit c223f9a

Please sign in to comment.