D2 렌더링 응용

D2 렌더링 응용

스크립트를 통한 서버 실행 및 종료 자동화

Hugo 빌드 과정에서 서버를 자동으로 실행하고, 빌드가 완료되면 서버를 종료하도록 스크립트를 작성할 수 있습니다. 다음은 Windows Batch 스크립트 예시입니다.

build.bat

@echo off
:: Go HTTP 서버 실행
start "" "%~dp0\d2server.exe"
for /f "tokens=2" %%a in ('tasklist ^| findstr /i "d2server.exe"') do set PID=%%a
:: Hugo 빌드 실행
hugo --gc --minify
:: Go HTTP 서버 종료
taskkill /PID %PID% /F
echo Build completed and server stopped.
  • 서버 실행: start "" "%~dp0\d2server.exe" 명령으로 Go 서버를 백그라운드에서 실행합니다.
  • PID 저장: tasklistfindstr을 사용하여 실행된 서버의 프로세스 ID(PID)를 찾아 저장합니다.
  • Hugo 빌드 실행: hugo --gc --minify 명령어로 Hugo 사이트를 빌드합니다.
  • 서버 종료: 빌드가 완료된 후, 저장된 PID를 사용하여 taskkill 명령어로 서버를 종료합니다.

Dark 모드 설정

Go 서버 코드 수정

Go 서버에서 D2 다이어그램을 렌더링할 때 Dark Mauve (테마 ID: 200) 또는 Dark Flagship Terrastruct (테마 ID: 201)을 적용합니다. 서버 소스에서 renderText 부분을 수정합니다.:

func renderText(content string) (string, error) {
	// D2 명령어 실행에 다크 테마 적용
	command := exec.Command("d2", "--theme=200", "-")  // 다크 모드 적용 (Dark Mauve)
	command.Stdin = bytes.NewBuffer([]byte(content))
	// 명령어 실행 및 에러 처리
	output, err := command.CombinedOutput()
	if err != nil {
		return "", err
	}
	return string(output), nil
}
  • 수정 후에는 go 서버를 다시 빌드 합니다.
go build -o d2server.exe d2server.go

불필요한 메세지 제거

Go 서버에서 렌더링 시, D2 다이어그램 밑에 다음과 같은 메세지가 추가될 수 있습니다.

success: successfully compiled - to - in 77.7552ms

output을 로깅해 보면, 다음과 같이 마지막에 해당 메시지가 추가되어 있습니다.

...
<rect x="-100" y="-121" width="970" height="614" fill="white"></rect>
<rect x="362.000000" y="-21.000000" width="46" height="36" fill="rgba(0,0,0,0.75)"></rect>
<rect x="62.500000" y="72.500000" width="82" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="363.000000" y="200.000000" width="44" height="31" fill="rgba(0,0,0,0.75)"></rect>
<rect x="249.500000" y="72.500000" width="82" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="436.500000" y="72.500000" width="82" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="623.500000" y="72.500000" width="83" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="83.500000" y="288.500000" width="41" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="270.500000" y="288.500000" width="41" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="457.500000" y="288.500000" width="41" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="644.500000" y="288.500000" width="42" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></svg></svg>
success: successfully compiled - to - in 77.7552ms

이를 그대로 출력하면 의도하지 않는 success 메세지도 함께 출력되므로, Regex 를 이용해 svg 태그만 출력하도록 수정할 수 있습니다.

package main
import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"os/exec"
	"regexp"
)
func handleRenderRequest(w http.ResponseWriter, r *http.Request) {
	requestBody, err := io.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	defer r.Body.Close()
	output, err := renderText(string(requestBody))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, output)
}
func renderText(content string) (string, error) {
	// D2 명령어 실행에 다크 테마 적용
	command := exec.Command("d2", "--theme=200", "-")
	command.Stdin = bytes.NewBuffer([]byte(content))
	// 명령어 실행 및 에러 처리
	output, err := command.CombinedOutput()
	if err != nil {
		log.Printf("Command failed: %s", err)
		return "", err
	}
	// 출력 결과에서 <svg> 태그만 추출
	outputStr := string(output)
	re := regexp.MustCompile(`(?s)<svg.*</svg>`)  // 전체 SVG 태그를 찾는 정규 표현식
	svgOnly := re.FindString(outputStr)           // <svg> 태그만 추출
	return svgOnly, nil
}
func main() {
	http.HandleFunc("/render", handleRenderRequest)
	http.ListenAndServe(":8080", nil)
}

디버깅

만약 D2 다이어그램이 정상적으로 렌더링되지 않거나 에러가 발생한다면, 명령어 실행 상태를 확인해야 할 수 있습니다. 이때 콘솔 로그를 추가하여 디버깅할 수 있습니다. 다음은 콘솔 로그를 추가하여 디버깅하는 방법입니다:

콘솔 로그 추가 코드

func renderText(content string) (string, error) {
	// D2 명령어 실행에 다크 테마 적용
	command := exec.Command("d2", "--theme=200", "-")
	command.Stdin = bytes.NewBuffer([]byte(content))
	// 명령어를 문자열로 변환하여 로그에 기록
	fullCommand := strings.Join(command.Args, " ")
	log.Printf("Executing command: %s", fullCommand)
	// 명령어 실행 및 에러 처리
	output, err := command.CombinedOutput()
	if err != nil {
		log.Printf("Command failed: %s", err)
		return "", err
	}
	// 결과에서 성공 메시지 필터링
	outputStr := string(output)
	if strings.Contains(outputStr, "success: successfully compiled") {
		outputStr = strings.Split(outputStr, "\n")[0] // 성공 메시지를 제외한 첫 번째 라인만 가져오기
	}
	// 명령어가 성공적으로 실행되었음을 기록
	log.Println("Command executed successfully.")
	return outputStr, nil
}

디버깅 절차:

  • 콘솔 로그 확인: 명령어가 정확하게 실행되는지 확인하려면, 콘솔에 출력되는 실제 실행된 명령어에러 메시지를 확인합니다.
  • 명령어 문제 해결: 실행된 명령어에서 문제가 발생하면, D2 CLI의 인자 또는 경로 등을 확인하여 문제를 해결합니다.