TrendShift · Web Scraping & Backup

wechat-article-exporter — 브라우저에서
돌아가는 콘텐츠 일괄 다운로더

위챗 공식계정(공중호) 글을 HTML·MD·DOCX·Excel로 100% 원본 그대로 백업하는 오픈소스 도구. Nuxt 3 SPA + Nitro 프록시 + Cloudflare/Docker 배포까지 한 번에 배운다.

wechat-article/wechat-article-exporter · TypeScript+Vue · MIT · 8.1k★ 2026-05-20 · TrendShift 19위
00 — 들어가며Context

먼저, "위챗 공중호"가 뭐고 왜 백업이 필요한가

왜 이런 도구가 중국 개발자 커뮤니티를 점령했나.

위챗(WeChat·微信)에는 한국의 네이버 블로그 + 카카오 채널과 비슷한 "공중호(公众号)"가 있다. 중국에서 가장 큰 콘텐츠 플랫폼 중 하나다. 하지만 위챗은 모든 글이 위챗 앱 안에 갇혀 있어서, 밖에서 검색하거나 백업하기가 거의 불가능하다. 이 레포는 그 벽을 우회해 글을 통째로 내려받게 해주는 도구다.

2024~2026년 사이 중국에서 공식계정 콘텐츠의 법적 보존, 아카이빙, 마이그레이션 수요가 폭증했다. 정부 규제 변경·플랫폼 삭제 사고가 잦아지면서 "내가 쓴 글을 내 손으로 보관"하려는 흐름이 일반화됐다. 이 레포는 그 정확한 timing을 잡았다.

Term · 용어
공중호 (公众号, Official Account)
위챗 안에서 운영되는 공식계정 채널. 기업·미디어·개인이 운영하며 위챗 사용자가 구독한다. 글 작성·수정은 mp.weixin.qq.com(웹 백엔드)에서 한다. 이 백엔드 로그인 권한이 있어야 본 도구를 쓸 수 있다.
Term · 용어
SPA (Single Page Application)
페이지 이동 없이 자바스크립트로 화면을 갈아 끼우는 웹앱. Gmail이 대표 예시. 이 프로젝트는 Nuxt 3로 만들었지만 SSR을 끄고 SPA로만 동작한다. 사용자 로그인 쿠키가 있어야 위챗 데이터를 가져올 수 있어서 서버가 미리 그릴 수 있는 콘텐츠가 없기 때문.
Term · 용어
Nitro (Nuxt의 서버 엔진)
같은 서버 코드를 Node·Cloudflare Pages·Deno·Vercel·Netlify까지 한 번에 빌드해주는 추상화 레이어. unstorage로 키-값 저장소도 환경별로 갈아 끼울 수 있다. 이 레포가 어디서든 돌아가는 비결.
01 — 한 줄 요약TL;DR

이 프로젝트의 핵심 메시지

한 문장으로 줄이면.

Core Message

"위챗 공식계정에 올라온 글을 일괄로 긁어다 HTML/Markdown/Excel/DOCX로 백업하는, 브라우저만 있으면 끝나는 오픈소스 다운로더."

위챗 공중호는 마치 "메뉴판은 보여주는데 음식 포장은 안 해주는 식당"과 같다. 이 도구는 그 식당의 메뉴판(공식 글 검색 기능)을 활용해, 글 하나하나를 도시락 통(HTML/Excel/DOCX)에 담아 집까지 가져갈 수 있게 해주는 "포장 도우미"다.

설치 없이 사이트만 방문하면 된다. 서버가 아니라 사용자 자신의 브라우저가 직접 위챗에 요청한다는 설계 덕에, 운영자가 사용자 계정을 풀에 넣어 공용 크롤링하는 윤리·법적 리스크가 원천 차단된다.

02 — 왜 주목받는가Why now

8.1k 별, 1.4k 포크의 비결

트렌딩 이유 + 경쟁 우위.

트렌딩 이유 — 정확한 timing + 100% 원본 재현

중국 개발자 커뮤니티에서 폭발적으로 입소문이 났다. 위챗 백업 수요(법적 보존, 콘텐츠 아카이빙, 플랫폼 이전)가 워낙 커서 빠르게 확산. 무엇보다 HTML 스타일 재현률 100% — 이미지·CSS·외부 자원까지 함께 묶어 오프라인에서도 완벽히 원본 그대로 보이게 만든다. 단순 텍스트 추출과는 다른 차원이다.

두 번째 강점은 "브라우저에서 직접 돈다"는 점. 일반 크롤러는 서버에서 돌아가서 운영자가 모든 사용자 쿠키를 보관해야 하고, 한 IP에서 들어오는 요청이라 위챗이 쉽게 차단한다. 이 레포는 그 모든 윤리·기술 리스크를 우회한다.

경쟁 비교 — 일반 크롤러 vs 이 레포

비교 항목일반 크롤러wechat-article-exporter
설치Python·Node + 환경 셋업웹사이트 방문만 (SPA)
실행 위치서버 → 계정 풀링·차단 위험유저 브라우저 → 차단 위험 없음
출력 포맷대부분 텍스트·JSONHTML·JSON·Excel·TXT·MD·DOCX
HTML 재현률이미지 깨짐·스타일 손실100% — 이미지·폰트·CSS 패키징
배포 옵션로컬 실행 중심온라인 / Docker / Cloudflare
댓글·조회수거의 불가능credentials 추출 시 가능
Win · 핵심 차별점
서버가 아니라 사용자 브라우저가 직접 위챗에 요청한다

이 설계 덕분에 운영자가 사용자 계정을 풀에 넣어 공용 크롤링하는 윤리·법적 리스크가 원천 차단된다. README의 "声明(선언)" 섹션에 명시되어 있다. 서버는 단지 CORS만 뚫어주는 얇은 프록시일 뿐.

03 — 기술 스택Stack

전체 기술 지도

프론트엔드 · 백엔드 · 라이브러리 · 인프라.

프론트엔드 — Nuxt 3 SPA

핵심 프레임워크

  • Nuxt 3.12 — SSR off, SPA 모드로만 동작
  • Vue 3.5 Composition APIsetup()·ref·computed 기반
  • TypeScript 5.5 — 전체 코드 타입 안정성
  • Tailwind CSS + @nuxt/ui v2 — 유틸리티 우선 + 컴포넌트 라이브러리

UI · 인터랙션

  • AG Grid Enterprise — 대규모 글 목록 테이블 (정렬·필터·페이지)
  • Monaco Editor — VS Code 에디터를 웹에 임베드 (디버그 뷰)
  • VueUse — Vue 컴포저블 유틸 모음
  • Lucide Icons · v-calendar — 아이콘·달력

백엔드 — Nitro 서버 엔진

  • Nitro (Nuxt의 서버) — ~25개 API 엔드포인트
  • Cookie 프록시 전달 + CORS 우회
  • NITRO_KV — Key-Value 저장 (메모리·FS·Cloudflare KV 환경별 자동)
  • Puppeteer + Chromium — 헤드리스 브라우저 자동화 (일부 고급 기능)
Analogy · 백엔드는 왜 필요한가

브라우저는 보안상 다른 도메인의 API를 직접 호출하지 못한다 (CORS 정책). 그래서 Nitro 서버가 "중간 전령"을 한다 — 사용자 요청을 받아 위챗 서버에 대신 보내고, 응답을 다시 사용자에게 전달. 이게 리버스 프록시(reverse proxy)다.

데이터 처리 라이브러리

  • Cheerio — HTML 파싱, 서버용 jQuery
  • Turndown — HTML → Markdown 변환
  • ExcelJS — .xlsx 생성
  • JSZip — zip 패키징 (이미지+HTML+CSS 묶기)
  • html2pdf.js — PDF 출력
  • DOMPurify — XSS 방지 (위챗에서 받은 HTML 살균)
  • file-saver — 다운로드 트리거 (브라우저에서 파일 저장)
  • date-fns / dayjs — 시간 처리

클라이언트 측 저장소

  • Dexie — IndexedDB 래퍼 (SQL 비슷한 문법)
  • store/v2 — 10개 테이블 구조 (article, asset, comment, comment_reply, debug, html, info, metadata, resource, resource-map)
  • p-queue — 동시 다운로드 큐 (rate limit 우회)
Term · 용어
IndexedDB + Dexie
IndexedDB는 브라우저 안에 내장된 NoSQL 데이터베이스. localStorage(5MB 한계)와 달리 수십 MB~수 GB까지 저장 가능, 인덱스·쿼리도 가능. 단 API가 매우 복잡해서 Dexie라는 래퍼를 쓴다. db.articles.where('date').above('2024-01-01').toArray()처럼 SQL 비슷한 문법이 가능해진다.

인프라 · 배포

  • Docker — node:22-slim + Chromium 멀티스테이지 빌드
  • Cloudflare Pages + KV — 엣지 서버리스 + 분산 키-값 저장
  • Deno Deploy — 헬퍼 함수용
  • GitHub Container Registry — 공식 이미지 배포
  • Sentry — 에러 모니터링 · Umami — 개인정보 보호형 분석

개발 환경 — 모던 툴체인

  • Node ≥ 22 · Yarn 1.22.22 via Corepack
  • Biome — Rust 기반, ESLint+Prettier 대체 (10~100배 빠름). 이 프로젝트는 lint 끄고 포맷터로만 사용
  • happy-dom — DOM 시뮬레이션 (테스트용)
  • prettier — CSS·MD 보조
04 — 아키텍처Design

시스템 구조와 4가지 핵심 패턴

전체 구조도 → 데이터 흐름 → 설계 패턴.

전체 시스템 구조도

┌─────────────────────────────────────────────────────────────┐
│                    사용자 브라우저 (Chrome 등)                │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  Nuxt 3 SPA (app.vue → pages/dashboard.vue)          │   │
│  │  · Vue 3 Composition API (composables/)              │   │
│  │  · AG Grid로 글 목록 표시                              │   │
│  │  · Tailwind + @nuxt/ui로 UI 구성                      │   │
│  └──────────────────────────────────────────────────────┘   │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  IndexedDB (Dexie 래퍼) — store/v2/db.ts             │   │
│  │  ├─ article    (글 메타데이터)                         │   │
│  │  ├─ asset      (에셋)                                 │   │
│  │  ├─ comment    (댓글)                                 │   │
│  │  ├─ comment_reply (댓글 답글)                         │   │
│  │  ├─ debug      (디버그)                               │   │
│  │  ├─ html       (원본 HTML)                            │   │
│  │  ├─ info       (계정 정보)                            │   │
│  │  ├─ metadata   (메타데이터)                           │   │
│  │  ├─ resource   (이미지·CSS 캐시)                      │   │
│  │  └─ resource-map (리소스 맵)                          │   │
│  └──────────────────────────────────────────────────────┘   │
└────────────┬────────────────────────────┬───────────────────┘
             │                            │
             │ ① 정적 자원 요청            │ ② 위챗 API 프록시 요청
             ▼                            ▼
┌─────────────────────────────┐  ┌─────────────────────────────┐
│  Cloudflare Pages /         │  │  Nitro 서버 (Edge or Node)  │
│  Docker (Nginx + Node)      │  │  server/api/web/mp/         │
│  .output/public/*           │  │  · 약 25개 엔드포인트         │
│                             │  │  · proxy-request.ts         │
│                             │  │  · Cookie 자동 전달          │
└─────────────────────────────┘  └────────────┬────────────────┘
                                              │ ③ 사용자 쿠키와 함께
                                              ▼
                                 ┌─────────────────────────────┐
                                 │  위챗 공식계정 백엔드          │
                                 │  mp.weixin.qq.com           │
                                 │  · 글쓰기 검색 API            │
                                 │  · 글 상세 API               │
                                 │  · 댓글/조회수 API            │
                                 └─────────────────────────────┘

5단계 데이터 흐름

[1] 로그인         [2] 검색           [3] 캐싱         [4] 다운로드 큐       [5] 내보내기
─────────         ────────          ────────        ──────────────        ─────────────
사용자가          apis/index.ts     Dexie가         p-queue가             Exporter가
위챗 백엔드   →   가 Nitro 프록시 →  IndexedDB에  →  동시 5개씩         →  HTML/MD/Excel
QR 로그인         호출               글 메타데이터     다운로드               /DOCX로 변환
                                    저장             (rate limit)         후 JSZip 패키징

패턴 1 — 브라우저 측 크롤링 (Client-Side Scraping)

일반 크롤러는 서버에서 돈다. 하지만 그러면 (1) 운영자가 모든 사용자 쿠키 보관, (2) 위챗이 한 IP의 요청이라 차단 쉬움, (3) 계정 공유 윤리 문제까지 셋이 한꺼번에 터진다. 이 프로젝트는 각 사용자 브라우저가 자기 자신의 쿠키로 직접 요청하게 해서 이 셋을 모두 해결한다. 서버는 그저 CORS만 뚫어주는 얇은 프록시.

패턴 2 — Composables (Vue 3의 핵심 재사용 단위)

// composables/useDownloader.ts
export function useDownloader() {
  const queue = new PQueue({ concurrency: 5 });
  const progress = ref(0);

  async function download(article) {
    await queue.add(() => Downloader.fetch(article));
    progress.value++;
  }

  return { download, progress };
}

React의 커스텀 훅과 같은 개념. UI 컴포넌트에서 const { download, progress } = useDownloader()만 부르면 다운로드 로직을 재사용할 수 있다. Nuxt 3는 composables/ 폴더 안의 함수를 자동 임포트해주기 때문에 import 문도 필요 없다.

패턴 3 — 다층 캐싱 (Multi-Layer Caching)

브라우저 메모리 (Vue ref/reactive)
       ↓ 페이지 새로고침 시 유지 X
IndexedDB (Dexie) — store/v2/db.ts
       ↓ 같은 브라우저면 영구 보관
Cloudflare KV / FileSystem KV — NITRO_KV
       ↓ 서버 측 캐싱 (인기 검색 결과)
위챗 원본 API

요청 횟수를 줄이고 위챗의 rate limit을 피하기 위한 핵심 전략. 같은 글을 또 봐도 위챗 서버까지 가지 않고 IndexedDB에서 바로 꺼낸다.

패턴 4 — 환경별 KV 어댑터 (Storage Driver Pattern)

// nuxt.config.ts
nitro: {
  storage: {
    kv: {
      driver: process.env.NITRO_KV_DRIVER || 'memory',
      base: process.env.NITRO_KV_BASE,
    }
  }
}

같은 코드가 환경 변수만 바꾸면 메모리·파일시스템·Cloudflare KV에서 모두 돈다. Nitro의 unstorage 추상화 덕분. 한 번 익혀두면 다양한 배포 환경을 쉽게 다룰 수 있다.

Trap · 함정
SSR을 켜놓고 SPA처럼 쓰려는 시도

Nuxt를 처음 쓰면 자연스럽게 SSR이 켜져 있다. 그런데 위챗 데이터는 사용자 쿠키가 있어야 가져올 수 있어 서버가 미리 그릴 콘텐츠가 없다. SSR이 켜져 있으면 로그인 전엔 빈 페이지가 서버에서 그려져 내려와 hydration 에러가 폭발한다.

Fix · 해결책
nuxt.config.ts에서 ssr: false

로그인 기반 SaaS·대시보드는 SSR을 꺼서 깔끔하게 SPA로 만드는 게 정답. 대신 SEO는 포기. 본인 프로젝트가 검색에 노출돼야 하면 SSG(Static Site Generation)나 ISR로 가야 한다.

05 — 디렉토리Repo map

레포 구조 해부

어디에 뭐가 있는지.

wechat-article-exporter/
├── app.vue                       # 최상위 Vue 컴포넌트 (라우터 진입점)
├── pages/
│   ├── index.vue                 # 진입점 라우트
│   ├── dashboard.vue             # SPA 메인 화면
│   ├── dashboard/                # dashboard 하위 라우트 디렉토리
│   └── dev/                      # 개발용 라우트 디렉토리
│
├── apis/                         # 클라이언트용 API 함수 (getArticleList 등)
├── composables/                  # useDownloader, useExporter, useBatchDownload
├── components/                   # Vue 재사용 컴포넌트 (글 카드, 다운로드 버튼)
│
├── server/
│   ├── api/web/mp/               # Nitro의 ~25개 프록시 엔드포인트
│   └── utils/proxy-request.ts    # 위챗 API 호출의 핵심 프록시 로직
│
├── utils/
│   └── download/
│       ├── Downloader.ts         # p-queue 기반 동시 다운로드 매니저
│       └── Exporter.ts           # HTML/MD/Excel/DOCX 변환·패키징
│
├── store/
│   └── v2/db.ts                  # Dexie 스키마 정의 (10개 테이블)
│
├── shared/                       # 클라이언트·서버 공용 유틸 (HTML 파싱)
├── types/                        # AppMsgEx, AccountInfo 등 TS 타입
├── config/                       # 상수, 공개 API 엔드포인트, AG Grid 설정
├── public/vendors/               # html-docx-js 같은 외부 JS (defer 로드)
│
├── nuxt.config.ts                # 모듈·런타임·Nitro·Sentry·Umami 설정
├── Dockerfile                    # node:22-alpine 빌드 → slim+Chromium 실행
├── biome.json                    # Biome 포맷터 설정 (lint 비활성, 행폭 120)
└── CLAUDE.md                     # Claude Code용 컨텍스트 가이드
경로역할
pages/dashboard.vueSPA 메인 화면. 거의 모든 UI 로직이 여기 또는 호출된 컴포넌트에 있음
server/utils/proxy-request.ts가장 중요한 파일. 사용자 쿠키를 위챗에 어떻게 전달하는지 핵심 로직
composables/useDownloader.tsp-queue로 동시 5개 다운로드 제어. 진행률 표시까지
utils/download/Exporter.tsHTML→MD·Excel·DOCX 변환. 새 포맷 추가하려면 이 파일
store/v2/db.tsDexie 10개 테이블 스키마. v1→v2 마이그레이션 흔적도 여기
nuxt.config.tsSSR off, NITRO_KV, Sentry, Umami, runtimeConfig 모두 여기
Analogy · Nuxt 컨벤션

이 레포는 Nuxt 3의 "컨벤션 over 설정" 철학을 잘 보여준다. pages/, server/api/, composables/, components/는 별도 등록 없이 폴더만 만들어두면 자동 등록된다. Next.js의 App Router와 비슷한 발상.

06 — 학습 포인트What to learn

분야별 배울 것

기술 영역마다 무엇을 가져갈지.

Nuxt 3 / Vue 3 Composition API

  • 파일 기반 라우팅pages/dashboard.vue가 자동으로 /dashboard가 됨
  • SSR off SPA 패턴ssr: false로 클라이언트 전용 앱
  • 모듈 시스템@nuxt/ui, @vueuse/nuxt, @sentry/nuxt를 한 줄로 통합
  • composables 자동 임포트useDownloader()를 import 없이 호출
  • runtimeConfig 패턴 — 환경 변수를 안전하게 클라이언트에 노출

실습: 빈 Nuxt 3 프로젝트에 composables/useCounter.ts를 추가해 자동 임포트가 동작하는지 확인

Nitro 서버 엔진

  • 다중 프리셋 빌드 — 같은 코드가 Node·Cloudflare·Deno·Vercel에서 동작
  • unstorage 추상화 — KV 드라이버를 환경 변수로 갈아끼우기
  • 이벤트 핸들러 패턴defineEventHandler로 HTTP 엔드포인트 정의
  • Rollup externalpuppeteer를 빌드 단계에서 제외하고 런타임 설치

실습: server/api/hello.ts를 만들어 /api/hello에서 JSON 반환

IndexedDB + Dexie

  • 브라우저 영구 저장 — localStorage 5MB 한계 대비 GB 단위 가능
  • 스키마 마이그레이션store/v2/의 v2는 v1에서 마이그레이션된 결과
  • 인덱스 쿼리where('publishTime').above(...).toArray()
  • Blob 저장 — 이미지·CSS 파일을 통째로 저장

실습: Dexie로 "북마크 매니저" 만들기 (URL·제목·태그·캡쳐 이미지)

Docker 멀티스테이지 빌드

  • 빌드/런타임 이미지 분리 — Alpine(빌드) → slim(실행)으로 크기 최소화
  • Chromium 같이 패키징 — Puppeteer가 시스템 Chromium을 쓰도록 환경변수 지정
  • 비루트 사용자USER node로 보안 강화
  • LABEL 메타데이터 — OCI 표준 라벨로 이미지 관리

실습: 멀티스테이지를 단일 스테이지로 바꿔봤을 때 이미지 크기가 얼마나 커지는지 비교

Cloudflare Pages / Workers KV

  • NITRO_PRESET=cloudflare_pages로 빌드 타깃 전환
  • 엣지 서버리스 — 전 세계 200+ 지점에서 자동 분산
  • Cloudflare KV 바인딩 — DB 없이도 분산 키-값 저장
  • 무료 100k req/day — 사이드 프로젝트에 최적

실습: 빈 Nuxt 3 앱을 Cloudflare Pages에 배포. wrangler loginwrangler pages deploy

동시성 제어 (p-queue)

  • Promise 큐 + 동시 실행 제한 — 위챗 rate limit 우회
  • backpressure 패턴 — 요청 100개 들어와도 5개씩만 실행
  • 실패 재시도 — 큐 패턴에 retry 로직 합치기
07 — 요구사항Setup

하드웨어 · 시스템 요구사항

배포 모드별 최소 사양.

모드최소 사양외부 의존성용도
온라인 사용최신 브라우저위챗 백엔드 로그인 권한가장 쉬움. 그냥 사이트 방문
로컬 개발Node 22 + 4GB RAMCorepack + Yarn 1.22.22개발·학습
Docker 셀프호스팅2 vCPU + 2GB RAMChromium (이미지 포함)NAS·VPS 운영
Cloudflare PagesCloudflare 계정 (무료)월 100k 요청까지 무료

Docker 셀프호스팅 상세

항목최소권장
CPU1 vCPU2 vCPU
RAM1 GB2 GB (Chromium 때문)
디스크2 GB5 GB (KV + 이미지)
OSDocker 지원 모든 OSLinux (시놀로지 NAS 포함)
네트워크mp.weixin.qq.com 접근 가능
Trap · Cloudflare Pages 제약

무료 플랜으로 월 100k 요청까지 가능하지만, Puppeteer가 Cloudflare에서 안 돈다. 일부 고급 기능(렌더링 검사 등)은 비활성화된다. 풀 기능을 원하면 Docker 셀프호스팅으로 가야 한다.

08 — 실습 과제Hands-on

직접 해볼 수 있는 6단계

난이도별 실습 — Easy → Hard.

실습 1 — 온라인 사이트 한 번 써보기Easy

1) https://down.mptext.top 접속 2) 위챗 공식계정 백엔드에 QR로 로그인 (계정 없으면 README 스크린샷만 봐도 OK) 3) 아무 공식계정 검색 → 글 5개 선택 → HTML로 다운로드 4) 받은 zip을 풀고 index.html을 브라우저에서 열어 "원본 위챗 글과 100% 일치" 확인

배우는 것: 도구의 실제 동작, HTML 패키징의 완성도

실습 2 — 레포 로컬에서 띄우기Easy

1) Node 22 이상 설치 2) corepack enable + corepack prepare yarn@1.22.22 --activate 3) 레포 클론 후 yarn · yarn dev 4) http://localhost:3000 접속

배우는 것: Nuxt 3 개발 서버, Corepack 패키지 매니저 핀

# Node 22 이상 필수
corepack enable
corepack prepare yarn@1.22.22 --activate

git clone https://github.com/wechat-article/wechat-article-exporter.git
cd wechat-article-exporter
yarn
yarn dev
# → http://localhost:3000

실습 3 — Docker로 셀프 호스팅Medium

1) Dockerfile 한 번 정독 (멀티스테이지 흐름 파악) 2) docker build --build-arg VERSION=local -t wxe:local . 3) docker run -d -p 3000:3000 -v $(pwd)/data:/app/.data --name wxe wxe:local 4) 또는 공식 이미지 ghcr.io/wechat-article/wechat-article-exporter:2.3.17

배우는 것: 멀티스테이지 빌드, Puppeteer + Chromium 패키징, 시놀로지 NAS 셀프호스팅 응용

실습 4 — 새로운 export 포맷 추가Medium

1) utils/download/Exporter.ts 정독 2) "epub 포맷" 또는 "단일 HTML로 묶기" 같은 새 포맷 추가 3) 테스트 글 5개로 검증 4) PR 보내는 것까지 도전!

힌트: epub은 사실 zip 안에 정해진 디렉토리 구조 + XML 메타데이터를 넣은 포맷. jszip으로 충분히 가능. epub-gen 라이브러리를 써도 OK.

실습 5 — Cloudflare Pages에 직접 배포Hard

1) Cloudflare 계정 만들고 wrangler login 2) yarn preview가 로컬에서 도는지 확인 3) wrangler pages deploy dist로 배포 4) 대시보드에서 KV 네임스페이스 생성 + NITRO_KV_BINDING으로 연결 5) 도메인 연결까지 끝내면 본인만의 wechat-exporter 사이트 완성

배우는 것: Wrangler CLI, Cloudflare KV 바인딩, Nitro 프리셋 전환

실습 6 — 다른 플랫폼 어댑터 만들기Hard

이 프로젝트의 구조를 모방해서 "네이버 블로그 백업 도구" 또는 "브런치 다운로더"를 만들어 보세요. 위챗 부분만 다른 API로 갈아 끼우면 됩니다. 본인 포트폴리오로 GitHub에 올릴 만한 프로젝트.

배우는 것: 어댑터 패턴, CORS 우회 일반화, 본인만의 풀스택 도구 빌드

09 — 학습 로드맵5 weeks

5주 심화 학습 로드맵

주차별로 따라가면 전체 스택 마스터.

Week 01
Vue 3 / Nuxt 3 기초

공식 튜토리얼 클리어 → Composition API 완전 이해 → composables/·useState·useFetch 직접 써보기. 이 레포의 pages/dashboard.vue를 한 줄씩 읽으면 좋다.

Week 02
Nitro / 서버리스

Nitro 공식 문서 → defineEventHandler·setHeader·readBody → CORS와 프록시 패턴 → unstorage로 메모리/FS/KV 전환. 이 레포의 server/utils/proxy-request.ts를 다른 사이트(예: 네이버 뉴스 RSS)에 적용해보기.

Week 03
브라우저 저장소 + 다운로드 UX

IndexedDB / Dexie → Blob·File·FileReader API → file-saver·jszip으로 zip 다운로드 → html2pdf.js로 PDF 변환 → turndown으로 HTML→MD. "오프라인 노트 앱"을 만드는 게 좋은 미션.

Week 04
Docker / Cloudflare 배포

Dockerfile 멀티스테이지 → 컨테이너 보안 (USER node) → docker-compose → Cloudflare Pages·Workers → KV / R2 / D1 → GitHub Actions로 자동 배포. 본인 사이드 프로젝트를 실제로 인터넷에 띄워보는 게 핵심.

Week 05
동시성 · 모니터링 · 에러 처리

p-queue·Bottleneck·async-pool → 재시도 전략 (exponential backoff) → Sentry로 에러 수집 → Umami로 사용자 분석 → AG Grid로 대규모 테이블 → Monaco Editor로 디버그 뷰. 이 레포의 useDownloader·useExporter가 종합 예제.

10 — 키워드 사전Glossary

핵심 용어 한눈에

자주 마주칠 단어들.

공중호 (公众号)
위챗 공식계정. 네이버 블로그+카카오 채널 같은 콘텐츠 채널.
SPA (Single Page Application)
페이지 이동 없이 JS로 화면을 갈아끼우는 웹앱. Gmail이 대표 예시.
SSR (Server-Side Rendering)
서버가 HTML을 먼저 만들어 보내는 방식. 초기 로딩이 빠르고 SEO에 유리.
Nitro
Nuxt 3의 서버 엔진. 같은 코드를 Node·Cloudflare·Deno 등에서 실행 가능.
unstorage
Nuxt 진영의 키-값 저장 추상화. 메모리·FS·Redis·Cloudflare KV를 같은 API로.
Composition API
Vue 3의 새로운 컴포넌트 작성 방식. setup()·ref·computed 기반.
Composable
Vue의 재사용 상태·로직 단위 함수. React의 커스텀 훅과 거의 동일.
IndexedDB
브라우저 내장 NoSQL DB. localStorage보다 훨씬 큰 데이터 저장 가능.
Dexie
IndexedDB 래퍼. SQL 비슷한 문법을 제공.
p-queue
Promise 동시 실행 개수를 제한하는 큐 라이브러리.
Cheerio
서버에서 HTML을 jQuery 문법으로 다루는 라이브러리.
Turndown
HTML → Markdown 변환기.
JSZip
브라우저에서 zip 파일을 만드는 라이브러리.
ExcelJS
JS로 .xlsx 파일을 생성/편집하는 라이브러리.
Biome
ESLint+Prettier 대체 도구. Rust 기반으로 10~100배 빠름.
Puppeteer
Node에서 Chromium을 자동화하는 라이브러리. 헤드리스 브라우저 자동화.
Corepack
Node 16부터 내장된 패키지 매니저 버전 관리 도구. yarn 1.22.22 핀.
Cloudflare Pages
정적 사이트 + 서버리스 함수를 무료로 호스팅해주는 서비스.
Cloudflare KV
Cloudflare의 분산 키-값 저장소. Edge에서 빠르게 읽기 가능.
Sentry
실시간 에러 모니터링 SaaS. 사용자가 만난 에러를 자동 수집.
Umami
오픈소스 웹 분석 도구. 구글 애널리틱스 대체.
Monaco Editor
VS Code의 에디터를 웹에서 쓸 수 있게 한 라이브러리.
AG Grid
대규모 데이터 테이블 컴포넌트. 정렬·필터·페이지네이션 제공.
CORS
Cross-Origin Resource Sharing. 브라우저의 도메인 간 요청 차단 정책.
Reverse Proxy
클라이언트 대신 다른 서버에 요청을 전달하는 중간 서버.
credentials
위챗 백엔드 API 호출에 필요한 인증 토큰. 댓글·조회수 접근에 필요.
11 — 참고 링크Refs

더 깊이 파고들 자료

공식 · 학습 리소스 · 관전 포인트.

이 레포 관련

기술별 학습 자료

인범님이 가져갈 핵심 패턴 3가지

가져갈 만한 점

· SPA + Nitro 프록시로 CORS 우회 패턴
· IndexedDB 다층 캐싱 + p-queue 동시 제어
· Docker 멀티스테이지로 Puppeteer 포함 이미지 빌드 (시놀로지 NAS 셀프호스팅에도 직접 적용 가능)
· Cloudflare KV로 서버 비용 0원 운영
· CLAUDE.md를 잘 작성해서 AI 에이전트가 코드 베이스를 이해하기 쉽게 만든 점

주의할 점

· 위챗 백엔드 API는 비공식 — 위챗이 API를 바꾸면 깨질 수 있음
· SSR 끄면 SEO·초기 로딩에 손해 — 본인 프로젝트에선 신중히
· AG Grid Enterprise는 상용 라이선스 필요
· Cloudflare Pages에선 Puppeteer 기능 일부 비활성화
· 법적 회색지대 — 콘텐츠 저작권은 원작자에게 있다는 점 README에 명시

Action · 이번 주에 해볼 것

wechat-article-exporter를 처음 만났다면 이 순서로 5단계.

  1. 온라인 데모 한 번 써보기. https://down.mptext.top 접속 → 위챗 백엔드 로그인 권한이 없어도 README 스크린샷으로 흐름 파악 → 100% HTML 재현률이 어떤 느낌인지 눈으로 확인.
  2. 레포 클론 + 로컬에서 띄우기. Node 22 + Corepack + Yarn 1.22.22로 환경 정확히 맞춘 뒤 yarn dev. pages/dashboard.vue 한 줄씩 읽으면서 Composition API 패턴 흡수.
  3. server/utils/proxy-request.ts 정독. 이 레포의 진짜 핵심. 어떻게 사용자 쿠키를 위챗에 전달하면서도 서버에 저장하지 않는지 — CORS 우회 + 리버스 프록시 패턴을 머리에 새긴다.
  4. Dexie + p-queue 코드 분석. store/v2/db.ts로 10개 테이블 스키마 파악 → useDownloader.ts로 동시성 제어 + IndexedDB 캐싱이 어떻게 합쳐지는지. 다층 캐싱이라는 발상을 본인 프로젝트에 옮기는 연습.
  5. Docker로 셀프호스팅 또는 본인 어댑터 빌드. 시놀로지 NAS가 있으면 docker run -d -p 3000:3000 ghcr.io/wechat-article/wechat-article-exporter:2.3.17로 즉시 띄우기. 한 발 더 가면 같은 구조로 "네이버 블로그 백업 도구"를 본인 손으로 만들어 포트폴리오에 올린다.
원문 · wechat-article/wechat-article-exporter (GitHub) · 2026-05-20 · TrendShift 19위