TypeScript 4.1 이상부터는 JSX 코드를 트랜스파일링하기 위한 다양한 옵션을 제공합니다. 이러한 옵션은 React의 다양한 환경(예: React 16, React 17+, React Native)에 맞춰 JSX를 효율적으로 처리하는 데 사용됩니다. 이번 글에서는 TypeScript가 JSX를 처리하는 방식과 React 17에서 도입된 새로운 JSX Transform의 이점을 설명합니다.
이 옵션들은 tsconfig.json 파일의 compilerOptions에 설정하는 jsx 속성에서 사용할 수 있습니다. 설정에 따라 TypeScript가 JSX 코드를 변환하거나 유지하는 방식이 달라집니다.
아래는 옵션별 TypeScript 스펙 추가 시점과 간략한 설명입니다.
옵션 | 추가 시점 | 설명 |
---|---|---|
preserve | 초기부터 존재 | JSX를 변환하지 않고 그대로 유지. |
react | 초기부터 존재 | JSX를 React.createElement 로 변환. |
react-jsx | TypeScript 4.1 | React 17+의 새로운 JSX Transform을 사용하여 jsx 함수 호출로 변환. |
react-jsxdev | TypeScript 4.1 | 개발 환경에서 디버깅 정보를 추가한 JSX Transform을 사용. |
react-native | TypeScript 4.0 | React Native 프로젝트에서 사용. |
// 입력
const element = <div>안녕하세요?</div>;
// 출력
const element = <div>안녕하세요?</div>;
Next.js에서 tsconfig.json의 ‘jsx’ 옵션을 ‘preserve’로 설정하지 않으면 자동으로 ‘preserve’로 바꿔줍니다.
그 이유는 Next.js에서 자체 구현한 JSX transform을 제공하기 때문입니다.
// 입력
import React from 'react';
const element = <div>안녕하세요?</div>;
// 출력
import React from 'react';
const element = React.createElement("div", null, "안녕하세요?");
// 입력
const element = <div>안녕하세요?</div>;
// 출력
import { jsx as _jsx } from 'react/jsx-runtime';
const element = _jsx('div', { children: '안녕하세요?' });
React 17+의 새로운 JSX Transform을 사용하면서 디버깅 정보를 추가하기 위해 사용합니다.
// 입력
const element = <div>Hello, world!</div>;
// 출력
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
const element = _jsxDEV("div", { children: "Hello, world!" }, undefined, false, {
fileName: "src/App.js",
lineNumber: 2,
columnNumber: 17
}, this);
React Native 프로젝트에서 JSX를 처리하기 위한 옵션입니다.
JSX Transform 도입 이전에는 JSX를 사용하기 위해 React를 반드시 import해야 했습니다. 그러나 React 17부터는 React Import 없이 JSX를 사용할 수 있도록 변경되었습니다.
1-1. 이전 방식 (React 16 이하)
JSX는 React.createElement로 변환되었기 때문에 React를 반드시 import해야 했습니다:
import React from 'react';
const App = () => <div>Hello, world!</div>;
1-2. JSX Transform 도입 이후 (React 17 이상)
React Import 없이도 JSX가 동작합니다:
const App = () => <div>Hello, world!</div>;
JSX Transform은 기존 React.createElement 방식보다 더 효율적으로 동작하도록 설계되었습니다.
2-1. 기존 방식 (React.createElement)
JSX를 사용할 때마다 React는 다음과 같이 동작했습니다:
import React from 'react';
const element = <div>Hello, world!</div>;
// 컴파일 후
const element = React.createElement('div', null, 'Hello, world!');
이 방식은 런타임에서 React.createElement를 호출하여 객체를 생성하므로 추가적인 오버헤드가 있었습니다.
여기서 말하는 오버헤드란 아래와 같습니다.
2-2. 새로운 방식 (JSX Transform)
React 17의 JSX Transform은 런타임 오버헤드를 줄이기 위해 더 효율적인 코드를 생성합니다:
const element = <div>Hello, world!</div>;
// 컴파일 후
import { jsx as _jsx } from 'react/jsx-runtime'; // 컴파일러가 자동으로 런타임에서 넣어주는 import문
const element = _jsx('div', { children: 'Hello, world!' });
이로써 React 자체의 오버헤드를 줄이고, JSX 변환 과정을 더 최적화하며, 코드 크기를 줄이고 실행 속도를 개선합니다.
2-3. React 17 이후의 새로운 기능 지원
React 17은 JSX Transform을 통해 향후 추가될 React 기능 및 변경사항에 대한 더 나은 지원을 제공합니다.
2-4. 타사 도구 및 빌드 환경과의 호환성
JSX Transform은 React 외의 다른 빌드 도구와도 더 나은 통합을 제공합니다.
React 17 이상을 사용 중이라면 react-jsx를 사용하는 것이 권장됩니다. 이는 React의 새로운 JSX 변환 방식을 활용하며, React를 명시적으로 import하지 않아도 되기 때문입니다.
React 외의 환경(Babel 기반 프로젝트 등)에서는 preserve를 사용하여 다른 도구에서 JSX를 처리하도록 위임할 수 있습니다.
옵션 | 설명 | 장점 | 제한사항 |
---|---|---|---|
preserve | JSX를 변환하지 않고 그대로 유지. | 외부 트랜스파일러와의 호환성 | TypeScript에서 JSX 처리 안함. |
react | JSX를 React.createElement 로 변환. | React 16 이하와 호환. | React Import가 필수. |
react-jsx | React 17+의 새로운 JSX Transform을 사용하여 jsx 함수 호출로 변환. | React Import 불필요, 최신 방식. | React 17 이상에서만 사용 가능. |
react-jsxdev | react-jsx 와 비슷하지만, 디버깅 정보를 추가한 JSX Transform을 사용. | 디버깅에 유용. | 프로덕션 환경에서는 사용하지 않음. |
react-native | React Native 환경에서 JSX를 변환하지 않고 그대로 유지. | React Native 환경에서 사용 가능. | 브라우저 DOM에서는 동작하지 않음. |
Wonkook Lee
Frontend Engineer
LinkedIn