Repository: styleguidist/react-styleguidist
Pull request #2183 (2025-01-07 10:38:34)

fix: prevent unnecessary wrapping of single line jsx elements
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: https://github.com/styleguidist/react-styleguidist/pull/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.


Patch:
diff --git a/src/client/utils/compileCode.ts b/src/client/utils/compileCode.ts
index 083b0206..236f13f1 100644
--- a/src/client/utils/compileCode.ts
+++ b/src/client/utils/compileCode.ts
@@ -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);


Test patch:
diff --git a/src/client/utils/__tests__/compileCode.spec.ts b/src/client/utils/__tests__/compileCode.spec.ts
index 84c2f64a..d6a19df9 100644
--- a/src/client/utils/__tests__/compileCode.spec.ts
+++ b/src/client/utils/__tests__/compileCode.spec.ts
@@ -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', () => {