설치한 후 가이드처럼 적용도 간단해 보입니다. rehypePlugins 에 주입할 때 선언해 놓았던 rehype-pretty-code 의 Options 타입인 객체에 설치했던 @rehype-pretty/transformers 로부터 transformerCopyButton 을 import 해서 transformers 속성에 다음과 같이 할당해 줍니다.
참고로 transformers 속성은 아래와 같이 ShikiTransformer 타입을 요소로 가지는 Array 형태의 데이터가 있어야 하는데요.
transformerCopyButton 함수의 반환 값이 ShikiTransformer 타입이기 때문에 할당이 가능한 것입니다.
transformerCopyButton 함수의 param 으로는 options 객체를 받습니다. CopyButtonOptions 타입의 이 객체는 아래와 같은 타입의 속성을 제공합니다. (자세한 명세는 여기를 확인하세요.)
여기까지 진행했다면 다음과 같이 코드 블록 우측 상단에 코드 블록 복사 버튼이 보이는 것을 확인할 수 있습니다. 하지만, 그와 함께 좌측 하단에 불안한 에러 메시지도 함께 보이네요 🤔
😢 (SSR 환경에서) 발생한 이슈
에러 메시지 확인해 봤을 때와 실제 렌더링 된 코드 블록 복사 버튼의 결과를 보면 각각 다음과 같습니다.
에러 메시지
실제 렌더링된 코드 블록 복사 버튼
일단 관련된 문제에 대한 Github issue 을 확인해 볼 수 있었으며 해당 이슈에 대한 관리자에 답변 도 확인할 수 있습니다. 결론은 Server Component 환경에서는 정상적으로 작동하지 않는 문제가 있다는 것입니다.(2024.08.27 기준)
에러 메시지가 의미하는 것은 button 에 대해 onClick 핸들러가 정의되어 있지 않으며, data 속성에 string 형태의 코드들이 삽입되어 있기 때문으로 파악했습니다. 결론적으로 해당 방법은 실패 !
✅ 직접 구현하자
스펙 파악
직접 구현하기 전에 이 버튼의 스펙을 정의해 보면 다음과 같습니다.
사용자가 버튼을 클릭하면 버튼이 포함된 코드 블록 들의 내용을 클립보드에 복사하는 기능이 있으면 된다.
이 버튼은 SEO 에 중요한 요소는 아니다.
사용자의 액션 이 필요하되, SEO 에는 중요하지 않다면 이 부분만 Client Component 로 만들어 주입해 주면 될 것 같습니다.
구현
마크다운으로 작성한 코드 블록이 렌더링 된 결과에서는 어떤 식으로 노출되는지 확인했습니다.
실제 코드 블록이 담기는 구조는 대략 pre 👉 code -> ... 구조입니다. 상세한 구조까지는 필요가 없고 코드 블록이 담기는 구조의 시작이 pre 태그가 래핑하고 있다는 것이 포인트입니다.
위 정보까지 파악한 다음에는 MDXRemote 의 Component 재정의를 활용해서 접근하면 됩니다. 첨부한 링크의 예제에서 확인할 수 있듯이 MDX 의 Component 에서 제공하는 element 에 대해 원하는 형태로 사용자의 환경에 맞게 재정의가 가능합니다. (remark-gfm 플러그인을 사용하면 기본 지원 element 외 것들도 제어가 가능합니다.)
다시 복사 버튼 기능 추가로 돌아와서, 우리는 그럼 코드 블럭이 담기는 pre 태그를 재정의해서 기존 구조에서 Client Component 로 생성한 코드 블록 복사 버튼을 주입해주면 되는 것 아닐까요 ?
먼저 코드 블록 복사 버튼 부터 정의해야겠습니다.
이제 정의한 CustomCodeBlock 컴포넌트를 MDXRemote 컴포넌트 components 속성의 pre 태그 에 매핑시켜주면 됩니다.
그러면 다음과 같이 의도한 코드 블록 복사 기능을 추가할 수 있습니다.
CustomCodeBlock 의 JSX 를 보면 pre 태그 내부에 button 태그를 배치한 것이 아닌 button 과 pre 태그를 래핑하는 div 태그가 존재하는데요. 이유는 pre 태그에 담기는 코드 블록에서 특정 line 의 내용이 길어질 경우 스크롤이 생길 수 있습니다. 이때 코드 블록 복사 버튼이 가로로 스크롤 해도 우측 상단에 fixed 하게 고정되길 바랬던 것과 달리 pre 태그 기준으로 우측 상단에 위치해 애매하게 배치되는 것을 해결하고자 한 의도입니다.
As-is
To-be
👋 마무리하며
이번 글에서는 지난 블로그 개발기 (Code-Block Customizing) 에 이어 생성된 코드 블록의 내용을 클립보드에 복사할 수 있는 버튼을 구현했던 과정을 소개했습니다. 선택 기능이긴 했으나 레퍼런스로 참고한 타 블로그에서도 많이 볼 수 있었고 구현하는 단계에서 참고할 만할 것도 많아서 생각보다 쉽게 완성할 수 있었습니다.
혹시나 비슷한 개발 환경에서 블로그 개발 중, 코드 블록 복사 기능을 추가하고 싶다면 참고해 봐도 좋습니다. 긴 글 읽어주셔서 감사합니다 😋