FastAPI로 Docusaurus와 유사한 사이트 구축하기: 3단계 - 코드 하이라이팅
Olivia Novak
Dev Intern · Leapcell

이전 이전 아티클에서는 .md 파일에서 동적으로 HTML을 렌더링하는 지원을 추가했습니다.
하지만 보셨듯이 docs/hello.md의 Python 코드 블록은 렌더링되었지만, 평범해 보이고 색상 하이라이팅이 없어 읽기 어려웠습니다.
이 아티클에서는 이 문제를 해결해 보겠습니다: Pygments와 python-markdown 확장을 사용하여 Markdown 코드 블록에 구문 하이라이팅을 추가합니다.
1단계: 하이라이팅 종속성 설치
python-markdown 라이브러리는 "확장"을 통해 추가 기능을 지원합니다. 코드 하이라이팅을 구현하려면 codehilite 확장이 필요하며, 이는 다시 다른 라이브러리인 Pygments에 의존합니다.
Pygments를 설치하려면 다음 명령을 실행하세요:
pip install Pygments
2단계: 정적 파일 디렉토리 및 CSS 구성
구문 하이라이팅은 두 단계로 작동합니다:
python-markdown의codehilite확장은 코드 블록(예:```python ... ```)을 특정 CSS 클래스(예: 키워드는.k, 문자열은.s)를 가진 HTML 태그로 변환합니다.- CSS 파일을 사용하여 브라우저에 이러한 CSS 클래스가 어떤 색상을 표시해야 하는지 알려줍니다.
Pygments 라이브러리는 이 CSS를 생성하는 편리한 명령줄 도구를 제공합니다.
먼저 프로젝트 루트 디렉토리에 static/css 폴더를 만들어 이 CSS 파일을 저장하겠습니다.
fastapi-docs-site/
├── docs/
│ └── hello.md
├── main.py
├── static/
│ └── css/ <-- 새로 추가
└── templates/
3단계: 하이라이팅 CSS 파일 생성
터미널을 열고 다음 명령을 실행하세요:
pygmentize -S monokai -f html -a .codehilite > static/css/highlight.css
pygmentize 매개변수에 대한 설명입니다:
-S monokai:monokai를 하이라이팅 테마로 지정합니다 (default,github-dark,solarized-light등도 시도할 수 있습니다).-f html:-f는 HTML용 CSS를 생성하기를 원한다는 것을 나타냅니다.-a .codehilite:-a는 모든 CSS 규칙이.codehiliteCSS 클래스(python-markdown에서 사용되는 기본 클래스) 아래에 중첩되어야 함을 의미합니다.
완료 후 static/css/highlight.css를 열면 monokai 테마에 대한 CSS 규칙이 내부에 생성된 것을 볼 수 있습니다.
4단계: FastAPI에서 정적 디렉토리 마운트
이제 CSS 파일은 있지만 FastAPI는 아직 그것을 알지 못합니다. 이 문제를 해결하기 위해 main.py에서 static 디렉토리를 "마운트"해야 합니다.
main.py를 열고 다음과 같이 수정하세요:
# main.py from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templates from fastapi.responses import HTMLResponse import markdown from fastapi.staticfiles import StaticFiles # 1. StaticFiles 가져오기 app = FastAPI() # 2. 정적 디렉토리 마운트 # 이는 `/static`으로 시작하는 모든 요청이 "static" 폴더에서 파일을 찾도록 FastAPI에 지시합니다. app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") # --- 홈 라우트 (변경 없음) --- @app.get("/", response_class=HTMLResponse) async def root(request: Request): context = { "request": request, "page_title": "Hello, Jinja2!" } return templates.TemplateResponse("index.html", context) # --- 문서 라우트 (다음으로 수정 예정) --- @app.get("/docs/hello", response_class=HTMLResponse) async def get_hello_doc(request: Request): md_file_path = "docs/hello.md" try: with open(md_file_path, "r", encoding="utf-8") as f: md_content = f.read() except FileNotFoundError: return HTMLResponse(content="<h1>404 - Document Not Found</h1>", status_code=404) # 현재로서는 변경되지 않았으며, 다음 단계에서 수정할 것입니다. html_content = markdown.markdown(md_content) context = { "request": request, "page_title": "Hello, Markdown!", "content": html_content } return templates.TemplateResponse("doc.html", context)
5단계: HTML 템플릿에 CSS 포함
templates/doc.html을 수정하고 <head>에 <link> 태그를 추가하여 HTML 페이지가 코드 하이라이팅 CSS를 로드할 수 있도록 합니다:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{{ page_title }} - My Docs Site</title> <link rel="stylesheet" href="{{ url_for('static', path='css/highlight.css') }}" /> </head> <body> <h1>{{ page_title }}</h1> <hr /> <div class="doc-content">{{ content | safe }}</div> </body> </html>
6단계: Markdown 확장 활성화
마지막 단계로 main.py로 돌아가서 python-markdown 라이브러리가 변환 중에 codehilite 확장을 사용하도록 알려주겠습니다.
또한 fenced_code 확장도 필요한데, 이는 삼중 백틱(```) 내의 내용을 코드 블록으로 렌더링하는 데 사용되며, 구문 하이라이팅을 표시하는 데 필요한 조건입니다.
main.py에서 get_hello_doc 라우트 함수를 수정하세요:
# main.py # ... (다른 가져오기 및 앱 인스턴스는 변경되지 않음) ... # ... (app.mount 및 templates 인스턴스는 변경되지 않음) ... # ... (root 홈 라우트는 변경되지 않음) ... @app.get("/docs/hello", response_class=HTMLResponse) def get_hello_doc(request: Request): """ hello.md 문서를 읽고, 파싱하고, 렌더링합니다 (구문 하이라이팅 포함) """ md_file_path = "docs/hello.md" try: with open(md_file_path, "r", encoding="utf-8") as f: md_content = f.read() except FileNotFoundError: return HTMLResponse(content="<h1>404 - Document Not Found</h1>", status_code=404) # 주요 변경 사항: 마크다운 확장 활성화 # 1. fenced_code: ``` 구문 지원 # 2. codehilite: 구문 하이라이팅 활성화 (Pygments를 자동으로 사용) extensions = ['fenced_code', 'codehilite'] html_content = markdown.markdown(md_content, extensions=extensions) context = { "request": request, "page_title": "Hello, Markdown!", "content": html_content } return templates.TemplateResponse("doc.html", context)
7단계: 실행 및 테스트
uvicorn main:app --reload를 실행하여 서버를 시작하세요.
이제 http://127.0.0.1:8000/docs/hello를 다시 방문하세요.
hello.md의 Python 코드 블록에 이제 monokai 테마 구문 하이라이팅이 적용된 것을 볼 수 있습니다. CSS를 생성할 때 매개변수를 변경하여 다른 하이라이팅 테마의 효과를 볼 수도 있습니다.

프로젝트 온라인 배포
문서 사이트는 모든 사람이 방문하기 위한 것이므로 로컬에서 실행하는 것으로는 충분하지 않습니다. 다음으로 온라인으로 배포할 수 있습니다.
A simple deployment option is to use Leapcell. It's a web app hosting platform that can host projects in various languages and frameworks, including FastAPI, of course.
다음 단계를 따르세요:
-
웹사이트에서 계정을 등록하세요.
-
프로젝트를 GitHub에 커밋하세요. GitHub 공식 문서(GitHub의 공식 문서)를 참조하여 단계를 따르세요. Leapcell은 나중에 GitHub 리포지토리에서 코드를 가져옵니다.
-
Leapcell 페이지에서 "Create Service"를 클릭합니다.

- FastAPI 리포를 선택하면 Leapcell이 필요한 구성을 자동 완성하는 것을 볼 수 있습니다.

- 하단의 "Submit"을 클릭하여 배포합니다. 배포는 빠르게 완료되고 배포 홈페이지로 다시 이동합니다. 여기서 Leapcell이 도메인을 제공했음을 확인할 수 있습니다. 이것이 블로그의 온라인 주소입니다.

결론 및 다음 단계
구문 하이라이팅을 통해 문서 사이트가 훨씬 더 전문적으로 보입니다.
하지만 아직 한 가지 문제가 남아 있습니다: doc.html 템플릿의 페이지 제목({{ page_title }})이 main.py의 라우트 함수("page_title": "Hello, Markdown!")에서 여전히 하드코딩되어 있으며 Markdown 파일에서 검색되지 않습니다.
이것은 매우 유연하지 못합니다. 올바른 접근 방식은 이 제목을 hello.md 파일 자체에서 읽어오는 것입니다.
다음 아티클에서는 Markdown 파일에 Frontmatter( title, date 등과 같은 아티클 메타데이터를 정의하는 데 사용됨)를 소개하고 프로젝트에서 Frontmatter 파싱 및 읽기를 구현하여 코드에서 하드코딩하는 것을 피할 것입니다.
