monorepo 구조와 3-column 레이아웃을 구현하고 Vercel에 첫 배포를 시도했다. workspace 프로토콜 문제, Turbopack의 worker_threads 충돌로 webpack 전환, D3 graph view 노드 좌표 버그, KaTeX CSS 누락, 한국어 FlexSearch 토크나이저 구현까지 — 배포하면서 만난 것들을 전부 기록했다.
bun workspace에서 CSS 패키지 hoisting 이슈가 있었다. tw-animate-css 같은 third-party 패키지가 root node_modules/로 hoist되는데, Turbopack의 CSS @import resolver가 앱 디렉토리 위로 올라가지 못해서 Module not found 에러가 발생했다. next.config.ts에 turbopack.root를 monorepo 루트로 설정해서 해결했다.
또 postcss.config.mjs가 없어서 @tailwindcss/postcss가 전혀 실행되지 않았다. Tailwind utility 클래스(flex, border, bg-muted 등)가 CSS에 생성되지 않아 화면에 스타일이 아예 적용되지 않는 문제였다. postcss 설정 파일 하나로 해결됐다.
Vercel 배포
workspace 프로토콜 문제
첫 Vercel 배포를 시도하자마자 빌드가 터졌다.
Module not found: Can't resolve 'nuartz'
원인은 간단했다. Vercel은 기본적으로 apps/web 디렉토리 기준으로 bun install을 실행한다. 그런데 package.json에 "nuartz": "workspace:*"로 선언되어 있고, workspace:* 프로토콜은 monorepo 루트에서 설치해야만 올바르게 resolve된다.
해결책: apps/web/vercel.json에 install/build 커맨드를 직접 지정했다.
{ "installCommand": "cd ../.. && bun install --frozen-lockfile", "buildCommand": "cd ../.. && bun run build:pkg && cd apps/web && next build"}
monorepo 루트로 올라가서 설치하고, 먼저 packages/nuartz를 빌드한 뒤 Next.js 앱을 빌드하는 순서다.
Turbopack은 개발(bun dev)에서만 쓰고, 프로덕션 빌드는 webpack을 쓰는 게 현재로선 안전하다.
버그 수정
Graph View - 노드가 전부 (0,0)에 몰리는 버그
그래프 뷰를 열면 모든 노드가 왼쪽 상단 한 점에 겹쳐서 나타났다.
// 문제가 있던 코드sim.stop()for (let i = 0; i < 300; i++) sim.tick() // 시뮬레이션 미리 실행sim.on("tick", () => { node.attr("transform", d => `translate(${d.x},${d.y})`)})
원인: D3 force simulation에서 sim.stop() 후 sim.tick()을 수동으로 호출하면 sim.on("tick", callback)은 절대 실행되지 않는다. tick 이벤트는 sim.restart() 이후 비동기로 실행될 때만 발생한다.
// 수정된 코드const updatePositions = () => { link .attr("x1", d => (d.source as SimNode).x!) .attr("y1", d => (d.source as SimNode).y!) .attr("x2", d => (d.target as SimNode).x!) .attr("y2", d => (d.target as SimNode).y!) node.attr("transform", d => `translate(${d.x},${d.y})`)}sim.on("tick", updatePositions)updatePositions() // ← 즉시 호출 — 정지된 상태에서도 좌표 적용
pre-run된 시뮬레이션 결과가 노드 객체 (d.x, d.y)에는 이미 저장되어 있다. DOM에 적용하는 함수를 한 번만 직접 호출하면 됐다.
KaTeX - 수식이 깨져서 출력되는 문제
LaTeX 문서를 열면 \frac, \sum 같은 수식이 HTML 태그가 그대로 보이는 상태였다.
원인은 CSS 미임포트였다. rehype-katex는 HTML 구조만 생성하고, 실제 수식처럼 보이게 하는 스타일은 katex/dist/katex.min.css를 별도로 로드해야 한다.
“있으면 좋겠다”고 생각한 기능을 문서에 먼저 써두면, 나중에 구현하지 않았는데도 구현된 것처럼 보이는 상태가 된다. 기능이 없다면 “Planned” 섹션에 넣는 게 맞다.
마치며
nuartz를 기획하면서 가장 크게 깨달은 것은, Quartz는 라이브러리가 아니라는 것이다.
Quartz는 완성도 높은 정적 사이트 생성기다. 내부를 뜯어서 다른 프레임워크에 끼워 맞추려는 시도는 처음부터 설계 불일치를 안고 가는 것이었다.
반면 OFM 플러그인 하나는 진짜 재사용 가능한 자산이다. wikilink와 callout 파싱 로직은 Quartz 개발자들이 공들여 만든 것이고, markdownPlugins / htmlPlugins 인터페이스 덕분에 unified 파이프라인에 깔끔하게 꽂을 수 있다.
결국 “Quartz를 통째로 가져오려는 욕심”을 내려놓고 “필요한 것만 가져오는 현실적인 전략”으로 방향을 바꿨다. 나머지는 npm 생태계가 이미 잘 해결해두었다.