아직도 블로그 버전을 하드코딩하니?
처음에는 개인 블로그라서 굳이 버전을 표시할 필요가 없다고 생각했습니다. 그런데 어느 순간부터 블로그가 점점 발전하고, 방문해주시는 분들도 늘어나니 “새로 추가된 기능이나 변경된 사항을 좀 더 명확하게 안내해 드리고 싶다”라는 마음이 들었습니다.
그렇게 릴리즈 노트 형식으로 업데이트 내역을 정리해보자는 결심을 하게 되었고, 이미 다른 프로젝트에서 익숙하게 사용해왔던 Semantic Versioning 을 적용하면 좋겠다고 생각했습니다. 버전이 올라갈 때마다 무엇이 바뀌었는지 기록하고, 블로그 하단(Footer)에도 표시해 두면 방문하시는 분들도 쉽게 확인하실 수 있을 테니까요.
기대와는 달랐던 Vercel 배포 환경
처음에는 package.json에 명시된 버전을 자동으로 올려주는 npm version patch
와 같은 명령어를 사용하면, 굳이 수작업으로 버전을 수정할 필요 없이 깔끔하게 관리할 수 있을 것 같았습니다. 예를 들어, 아래처럼 빌드 스크립트를 작성해두면 로컬 환경에서는 무리 없이 동작하리라 기대했지요.
// package.json
{
"scripts": {
"build": "BLOG_VERSION=$npm_package_version next build"
}
}
이 방식이라면 빌드 과정에서 $npm_package_version을 BLOG_VERSION
이라는 환경 변수로 주입해주고, 이후 코드 내에서 process.env.BLOG_VERSION
을 참조하기만 하면 버전을 표시할 수 있을 듯했습니다.
하지만 막상 Vercel에 배포했을 때, 예상치 못한 문제가 발생했습니다. Vercel 측의 빌드 환경이 로컬과 다르게 구성되어 있어, $npm_package_version이 전혀 전달되지 않았던 것입니다.
왜 그럴까?
클라우드 네이티브하게 블로그를 운영하면서 “각종 배포 플랫폼에 종속되지 않고, 유연하게 버전을 관리할 방법이 없을까?”라는 고민이 깊어졌습니다. 그래서 package.json에 직접 접근하거나, 로컬에서 사용하던 npm 전용 변수에 의존하지 않고도 버전을 활용할 수 있는 대안을 찾아야 했습니다.
새로운 아이디어와 구현 방법
처음에는 package.json 내부의 version
필드를 읽어서 사용하는 간단한 방안을 떠올렸습니다. 그러나 여러 서버리스 환경에서 package.json 을 반드시 배포 대상으로 포함하지 않을 수도 있다는 우려가 생겼습니다. 그래서 더 안전하고 확장적인 방법인 version.json 파일을 생성하는 방법을 적용했습니다.
(역시 엔지니어링의 핵심은 엔지니어의 창의성!)
- 1
빌드 전 스크립트로 version.json 생성
- a
추가적인 메타데이터를 작성할 수 있도록 다음과 같은 방법을 시도했습니다.
- i
package.json 을 읽어서
version
필드를 파싱합니다.
- ii
public/version.json
이라는 파일에 현재 버전 데이터를 json 형태로 저장합니다.(필요하다면 빌드 시간, 배포자 정보 등 추가할 수 있습니다.)
// scripts/generate-version.js const fs = require("fs"); const path = require("path"); const packageJson = require("../package.json"); const versionData = { version: packageJson.version, buildTime: new Date().toISOString(), }; fs.writeFileSync( path.join(__dirname, "../public/version.json"), JSON.stringify(versionData, null, 2) );
- 2
Server Component 에서 version.json 읽어오기
- a
next.js 서버 컴포넌트에서는 Node.js 의 fs 모듈을 사용해 손쉽게
public/version.json
을 읽어 올 수 있습니다. 이렇게 하면 배포 플랫폼이 바뀌어도, 우리가 만든version.json
파일만 있으면 버전 정보를 어디서든 일관성 있게 가져올 수 있습니다.
- b
예를 들어 Footer 컴포넌트 내에서 아래처럼 파일 시스템을 활용할 수 있습니다.
import fs from 'fs'; import path from 'path'; function getVersionData() { try { const filePath = path.join(process.cwd(), 'public/version.json'); const content = fs.readFileSync(filePath, 'utf-8'); return JSON.parse(content); } catch { return { version: 'unknown' }; } } export default function Footer() { const { version } = getVersionData(); return ( <footer className="text-sm text-gray-500 text-center py-4"> 블로그 버전: v{version} </footer> ); }
기본적으로 package.json 접근이 가능한 환경이라면 바로 가져오는 편이 간단합니다. 하지만 배포 플랫폼에 따라 package.json 이 포함되지 않을 수 있고, 나중에 빌드 시간이나 Git 커밋 해시 같은 추가 메타데이터를 함께 넣고 싶을 때는 version.json 을 통해 함께 관리하는 편이 더 편리하다고 판단했습니다.
또한 이 방식은 여러 환경에서 같은 로직을 일관성 있게 적용할 있다는 장점이 있습니다. “어떤 서버리스 환경이든, 배포 시점에 생성된 version.json 만 있으면 버전 정보를 쉽게 확인할 수 있다”라는 점이 가장 큰 이점입니다.
버전 정보 제대로 관리하고 공유하기
최종적으로 빌드 시점에 스크립트를 통해 “public/version.json” 파일을 생성해 블로그 버전을 표시하는 방법을 선택했습니다. https://github.com/mg5566/MikeBlog/commit/852f49298764820263bdc80abc7a3699b3685279
이 방식은 서버리스 환경이나 CI/CD 파이프라인에서 package.json을 직접 참조하기 어려운 상황에도 안정적으로 동작하며, 버전뿐만 아니라 빌드 시간이나 Git 커밋 해시 같은 추가 메타데이터도 함께 담아둘 수 있습니다.
버전을 표시하는 작은 시도가 결과적으로 개발 기록을 체계화하고, 사용자와의 소통을 한층 더 강화해 줄 수 있다고 생각합니다. 작은 기능 하나라도 버전업을 할 때마다 릴리즈 노트를 통해 알리고, 쌓여가는 버전 히스토리를 공유하면서 블로그를 “하나의 제품”으로 점차 성장시켜 나가려고합니다.
앞으로도 버전을 효율적으로 관리하고, 플랫폼의 제약을 최소화할 수 있는 방안을 계속 탐색해보려고 합니다. 이 글이 비슷한 고민을 하고 계신 분들께 작은 힌트가 되길 바랍니다.
향후, 릴리즈 노트로 찾아뵙겠습니다.