Files
sam-docs/dev/standards/blade-react-policy.md
김보곤 64f1262d51 docs: [standards] Blade + React(JSX) 혼용 정책 문서 추가
- 이중 중괄호 충돌 방지 규칙, 허용/금지 패턴, 체크리스트 포함
- INDEX.md에 등록
2026-03-12 17:08:15 +09:00

5.6 KiB

Blade + React(JSX) 혼용 정책

작성일: 2026-03-12 상태: 설계 확정


1. 개요

1.1 목적

MNG 프로젝트에서 Blade 템플릿 안에 React(JSX) 코드를 직접 작성할 때 발생하는 문법 충돌을 방지한다.

1.2 배경

MNG는 Blade + HTMX 기반이지만, 일부 복잡한 UI(모달, 인터랙티브 폼)에는 React 컴포넌트를 Babel 브라우저 트랜스파일링 방식으로 사용한다. React JSX 코드가 @push('scripts') 블록 안에 직접 작성되며, Blade 엔진이 이를 먼저 처리하기 때문에 문법 충돌이 발생할 수 있다.

1.3 핵심 원칙

Blade 엔진은 @verbatim 블록 외부의 모든 이중 중괄호({{ }})를 PHP echo 구문으로 변환한다. JSX의 inline style 문법 style={{ key: 'value' }}는 Blade의 이중 중괄호와 동일한 패턴이므로 PHP ParseError를 유발한다.


2. 문제 상세

2.1 충돌 원인

Blade 컴파일 과정:

Blade 소스                           → 컴파일된 PHP
style={{ tableLayout: 'fixed' }}     → style=<?php echo e( tableLayout: 'fixed' ); ?>

{{ }} 안의 내용이 PHP 코드로 해석되어 Unclosed '(' does not match '}' 등의 ParseError 발생.

2.2 영향 범위

@verbatim으로 감싸지 않은 Blade 파일 내 모든 JavaScript/JSX 코드에 해당한다.

패턴 위치 영향
style={{ key: 'value' }} JSX inline style 🔴 ParseError
{{ }} 텍스트가 포함된 JS 주석 // 주석에 {{ }} 포함 🔴 ParseError
${{ variable }} 템플릿 리터럴 🔴 ParseError
className="..." JSX className 정상 (이중 중괄호 없음)
`${variable}` JS 템플릿 리터럴 정상 (단일 중괄호)
{ key: value } JS 객체 리터럴 정상 (단일 중괄호)

2.3 실제 사고 사례

2026-03-12: barobill/ecard/index.blade.php에서 테이블 레이아웃 수정 시 style={{ tableLayout: 'fixed' }} 추가 → 운영서버 500 에러 발생. 주석의 {{ }} 텍스트도 동일 에러 유발.


3. 필수 규칙

R1. @verbatim 사용 여부 확인

React/JSX 코드를 포함하는 Blade 파일을 수정하기 전에, 해당 코드 블록이 @verbatim ~ @endverbatim으로 감싸져 있는지 반드시 확인한다.

# 확인 방법
grep -n '@verbatim\|@endverbatim' resources/views/파일.blade.php

R2. @verbatim 블록 내부 (안전)

@verbatim 안에서는 Blade가 이중 중괄호를 처리하지 않으므로 JSX 문법을 자유롭게 사용할 수 있다.

@push('scripts')
<script>
    const API = {
        store: '{{ route("some.route") }}',  // Blade 처리 필요 → @verbatim 밖
    };
</script>

@verbatim
<script type="text/babel">
    // 여기서는 JSX 자유 사용 가능
    <table style={{ tableLayout: 'fixed' }}>
        <col style={{ width: '20%' }} />
    </table>
</script>
@endverbatim
@endpush

R3. @verbatim 없는 블록 (주의 필요)

@verbatim이 없는 파일에서는 이중 중괄호를 절대 사용하지 않는다.

금지 패턴

❌ style={{ tableLayout: 'fixed' }}
❌ style={{ width: '20%' }}
❌ // 이 주석에 {{ }} 가 있으면 안됨
❌ const obj = {{ key: 'value' }}

허용 패턴: 스타일 객체 변수 분리

// 스타일 객체를 변수로 선언
const tableFixedStyle = { tableLayout: 'fixed' };
const colStyles = [
    { width: '10%' }, { width: '22%' }, { width: '28%' },
    { width: '17%' }, { width: '17%' }, { width: '6%' }
];

// 단일 중괄호로 참조 (Blade 충돌 없음)
<table style={tableFixedStyle}>
    <colgroup>
        <col style={colStyles[0]} />
        <col style={colStyles[1]} />
    </colgroup>
</table>

R4. JS 주석에도 이중 중괄호 금지

Blade는 주석 내부의 이중 중괄호도 처리한다. 주석에서도 {{ }}를 사용하지 않는다.

❌ // Blade {{ }} 충돌 방지
✅ // Blade 이중중괄호 충돌 방지

R5. {{ route() }} 등 Blade 디렉티브 분리

@verbatim 없이 Blade와 JSX를 혼용할 경우, Blade 디렉티브({{ route() }}, {{ csrf_token() }} 등)는 JSX 코드와 분리하여 스크립트 상단에 배치한다.

@push('scripts')
<script>
    // Blade 처리 영역 — 여기서만 {{ }} 사용
    const API = {
        cards: '{{ route("barobill.ecard.cards") }}',
        store: '{{ route("finance.journal-entries.store") }}',
    };
</script>
<script type="text/babel">
    // React/JSX 영역 — {{ }} 사용 금지
    // API 상수는 위 스크립트에서 선언된 것을 참조
</script>
@endpush

4. 현재 파일 현황

파일 @verbatim 주의 수준
finance/journal-entries.blade.php 사용 🟢 안전
barobill/ecard/index.blade.php 미사용 🔴 주의 필요

새로운 Blade + React 파일 작성 시 @verbatim 사용을 권장한다.


5. 체크리스트

Blade 파일에서 React/JSX 코드를 수정할 때:

  • @verbatim 사용 여부 확인 (grep -n @verbatim 파일명)
  • @verbatim 없는 파일에서 style={{ }} 미사용 확인
  • JS 주석에 이중 중괄호 미포함 확인
  • Blade 디렉티브({{ route() }} 등)와 JSX 코드 분리 확인
  • 인라인 스타일은 JS 변수로 선언 후 단일 중괄호 참조

관련 문서


최종 업데이트: 2026-03-12