Skip to content

Repository files navigation

1up.md

1up.md 블로그 소스 코드.

스택

  • Astro v7 — 정적 사이트 빌드
  • MDX — 포스트 본문(데모 컴포넌트를 인라인)
  • Sass (@use 모듈 방식)
  • Cloudflare Pages — 배포
  • Node.js ≥ 22.12.0 (빌드 Node 는 .nvmrc = 22 고정)
  • pnpm — 패키지 매니저. packageManager 필드로 버전 고정. npm 을 쓰지 말 것 (이유는 AGENTS.md 참조)

명령어

pnpm run dev                 # astro dev — http://localhost:4321
pnpm run build               # astro build — /dist 정적 빌드
pnpm run preview             # 빌드 결과 미리보기
pnpm run update:browserslist # caniuse-lite 통계 갱신 (CSS 타깃 산출용)

경로 별칭

~/src/. astro.config.mjsjsconfig.json 양쪽에 정의되어 있다.

import site from '~/data/site.config.yml';
import DefaultLayout from '~/layouts/DefaultLayout.astro';

디렉토리

src/
├── content/posts/                 포스트 (디렉토리 단위)
├── pages/                         라우트
├── layouts/
├── components/
├── data/                          site.config.yml, navigation.json
├── styles/                        Sass (global.scss 진입점)
├── plugins/                       빌드 시 마크다운 변환 플러그인
└── utils/

포스트

포스트는 단일 파일이 아니라 디렉토리 단위로 존재하며, 본문은 index.mdx(전 포스트 MDX — 데모 컴포넌트를 인라인하기 위함)다. 폴더명은 YYYY-MM-DD.<slug> 형식이며, 날짜 뒷부분이 URL 슬러그가 된다.

src/content/posts/
└── 2026-04-20.some-post-name/
    ├── index.mdx
    ├── images/
    │   └── cover.png              (선택) 인덱스 카드 커버 이미지
    └── demos/                     (선택) 인라인 데모 컴포넌트 — 아래 참고
        └── ...

본문에는 H1(# 제목)을 쓰지 않는다 — 제목의 단일 출처는 프론트매터 title 이며 본문은 ## 부터 시작한다.

index.mdx 프론트매터:

---
title: '포스트 제목'
description: '...'
pubDate: '2026-04-20T13:45:00+09:00'
tags: [tag1, tag2]
robots: 'noindex'                  # 선택
updatedDate: '2026-06-28T10:00:00+09:00'  # 선택 — 수정일. 상세 페이지 날짜 뒤 표기 + JSON-LD dateModified
---

본문 이미지는 클릭 시 PhotoSwipe 를 이용해 확대된다(휠·핀치 줌, 드래그 팬). 데모 안의 이미지도 기본 대상이므로, 확대를 원치 않으면 해당 이미지에 data-no-zoom 속성을 붙인다.

데모

포스트 본문의 인터랙티브 예제는 iframe 이 아니라 Astro 컴포넌트로 본문에 인라인한다. 데모는 포스트 폴더 안에 두고, MDX 포스트가 import 해서 렌더한다. 빌드 시 SSR 되어 첫 페인트부터 자연스러운 높이로 그려지므로 레이아웃 이동(CLS)이 없고, 별도 라우트도 만들지 않는다.

폴더 구조

src/content/posts/2026-04-20.some-post-name/
├── index.mdx
└── demos/
    └── some-demo/
        ├── index.astro           # 인라인 프래그먼트 (standalone 문서 아님)
        ├── script.js             # (선택) 클라이언트 로직
        └── images/               # (선택) 데모 자산 — 포스트가 아닌 데모 폴더에 둔다
            └── slide-1.svg

index.astro (인라인 프래그먼트)

<!doctype html>·<html>·<head>·<body> 없이 조각만 작성한다. 스타일은 <style>(Astro 가 자동 스코프하므로 포스트 스타일과 격리), 로직은 <script> 에 둔다.

---
// 외부 라이브러리는 CDN 이 아니라 pnpm 으로 설치해 번들한다.
import 'swiper/css/bundle';
import slide1 from './images/slide-1.svg?url';
---
<div class="demo">
  <!-- 데모 마크업 -->
</div>

<style lang="scss">
  .demo { /* Astro 가 자동 스코프 (data-astro-cid-*) */ }
</style>

<script>
  import './script.js';
</script>

MDX 에서 임베드

포스트 index.mdx 에서 상대 경로로 import 후 본문에 렌더한다.

import SomeDemo from './demos/some-demo/index.astro';

...본문...

<SomeDemo />

자산 / 외부 라이브러리

  • 이미지·SCSS·JS 는 같은 폴더 기준 상대 경로 import (Vite 가 번들). 데모 이미지는 데모 폴더의 images/ 에 둔다(포스트 직속 images/ 는 본문·커버용).
  • Swiper 같은 외부 라이브러리는 pnpm add 후 import 하면 Vite 가 로컬 청크로 번들하므로 런타임 CDN 요청이 없다. 해당 데모가 있는 포스트에만 로드된다.

사이트 설정

  • src/data/site.config.yml — 사이트명, 태그라인, 언어, 저자, SNS, 테마 색상 등의 단일 출처. manifest.json, robots.txt, humans.txt, rss.xml 모두 이 YAML 에서 파생됨.
  • src/data/navigation.json — 헤더 내비게이션. 항목의 label 은 body 의 page-{label} id 로도 사용된다.

브라우저 지원 (CSS 타깃)

CSS 벤더 프리픽스 주입·문법 다운레벨링은 빌드 시 Lightning CSS(Vite 기본 CSS minifier)가 처리한다. 대상 브라우저는 package.jsonbrowserslist 쿼리로 정의하며, 빌드 시 scripts/browser-css-target.mjs 가 그 결과를 브라우저별 최소 버전 esbuild 타깃 문자열(예: chrome109)로 추려 astro.config.mjs 가 이를 vite.build.cssTarget 으로 전달한다.

쿼리package.jsonbrowserslist 정의.

쿼리 의미
> 0.2% in KR 한국에서 점유율 0.2% 이상인 브라우저
last 2 versions 각 브라우저의 최신 2개 버전
not dead 24개월간 공식 지원·업데이트가 끊긴 브라우저 제외
not ios_saf < 16.4 iOS Safari 16.4 미만 제외

caniuse-lite 갱신pnpm update:browserslist(update-browserslist-db)로 브라우저 통계를 최신화한다. 빌드가 이 데이터로 browserslist 를 해석하므로 주기적 실행 필요.

지원 브라우저cssTarget 이 인식하는 브라우저만 프리픽스 대상이 되고, 나머지는 자동 제외.
식별자는 browserslist 입력 이름 기준.

브라우저 식별자 브라우저 이름 지원 비고
chrome Chrome O
edge Edge O
firefox Firefox O
safari Safari (macOS) O
ios_saf iOS Safari O esbuild 타깃 ios 로 매핑
opera Opera O
ie Internet Explorer O
and_chr Chrome for Android X
and_ff Firefox for Android X
samsung Samsung Internet X
op_mob Opera Mobile X
op_mini Opera Mini X
android Android Browser X

이름 정의: browserslist(입력 코드) · esbuild target(출력 타깃).

dev(astro dev)는 CSS 를 minify 하지 않아 prefix 가 붙지 않는다. 실제 확인은 빌드 결과에 적용됨.

폰트

본문은 Pretendard 가변폰트를 서브셋한 단일 파일 public/fonts/PretendardVariable.subset.woff2(약 365KB)를 사용한다. 원본 가변폰트(약 2MB)를 harfbuzz(hb-subset)로 다음과 같이 축소했다.

  • 글리프: Adobe-KR-9 Supplement 0(상용 현대 한글 2,780자) + 라틴·문장부호만 유지
  • 굵기 축: wght 를 400–600 으로 제한 (400 / 500 / 600 사용)

_font.scss 에서 font-weight: 400 600 한 블록으로 선언하며, 세 굵기를 이 한 파일이 모두 커버한다. 초기 렌더 속도를 위해 _headers 의 preload(Early Hints) 대상에 포함된다. 메인 포스트 순번용 숫자는 Outfit-ExtraLight 서브셋을 별도로 쓴다.

SPA 전환

src/components/Head.astro<ClientRouter /> (astro:transitions) 가 페이지 간 전환을 처리한다. 헤더 (<Logo>, <Navigation>) 는 transition:persist 로 지정되어 재마운트로 인한 플리커링이 발생하지 않는다.

추가 문서

About

Repository for 1up.md

Resources

Stars

0 stars

Watchers

1 watching

Forks

Contributors

Languages