
프레임워크 없이 HTML+JS로 만든 '노후 자금 시뮬레이터'를 공개, GA4 측정, OGP, 공유, 확산까지 한 번에 해본 이야기
요약
프레임워크 없이 HTML과 JavaScript만으로 노후 자금 시뮬레이터를 제작하고, 배포부터 데이터 분석까지의 전 과정을 다룬 기술 기록입니다. 정적 사이트의 장점을 극대화하여 데이터 임베딩, URL 파라미터를 통한 상태 공유, GA4를 활용한 정교한 이벤트 측정 방법을 설명합니다.
핵심 포인트
- 프레임워크 없이 정적 사이트(HTML+JS)로 빠른 개발 및 배포 구현
- URL 파라미터를 활용하여 사용자의 입력 상태를 공유 가능한 링크로 변환
- GA4 커스텀 이벤트 설계 시 노이즈를 줄이는 효율적인 측정 팁
- 데이터를 JS 파일에 직접 임베딩하여 CORS 문제 해결 및 성능 최적화
- GitHub Pages를 활용한 비용 제로의 간편한 서비스 공개
「만들었다」에서 멈추기 쉬운 개인 개발을, 공개하고・측정하고・확산하는 것까지 한 바퀴 돌린 기록입니다. 프레임워크 없이, 서버 없이의 **정적 사이트 (Static Site, HTML+JS)**로 어디까지 할 수 있는지에 대한 실례로서 작성합니다.
- 정적 사이트에 데이터를 싣기 / 상태를 URL로 공유하기
- GA4의 커스텀 이벤트 설계 (노이즈를 발생시키지 않는 팁)
- OGP/Twitter 카드・캐시 버스팅 (Cache Busting)
- GitHub Pages로
gh
CLI로 한 번에 공개 - 공개 직후의 “해외 봇” 등, 측정 시 빠지기 쉬운 함정
만든 것
👉 당신의 노후 자금, HOW MUCH?
「노후 자금 2,000만 엔」을 47개 도도부현의 실제 데이터로 다시 계산하는 도구입니다. 동기에 관한 이야기는 note 기사에 썼습니다. 본 기사는
기술 편입니다.
app_life_numbers/
├─ index.html 화면
├─ style.css 디자인
...
- 프레임워크 미사용.
- 데이터를
data.js에 직접 임베딩(Embedding) 함으로써, fetch도 CORS도 불필요. 더블 클릭만으로 작동. - 그대로 GitHub Pages에 올릴 수 있어 무료이며 고속. 개인 개발의 “공개까지”의 마찰이 최소.
e-Stat(가계 조사 등)를 가공한 현별 데이터를 오브젝트(Object)로서 JS에 직접 작성. 런타임(Runtime)에서 외부 요청이 발생하지 않으므로, GitHub Pages에서도 안정적입니다.
const PREF_DATA = [
{ name: "東京都", cons: 300000, pensionReg: 230000, cat: [/* 10대 비용 항목 */] },
// ... 47개 도도부현
...
「나는 이만큼이었다」를 공유하게 만드는 것이 바이럴(Viral)의 기점. 입력 조건과 비용 항목을 **URL 파라미터 (URL Parameter)**로 만들어, 열었을 때 상태를 복원합니다. 비용 항목은 천 엔 단위로 압축하여 URL을 짧게 만듭니다.
function buildShareUrl() {
const opts = currentOpts();
const cats = CATEGORIES.map((c) => Math.round((+$(`cat_${c.key}`).value || 0) / 1000)).join("-");
...
초기화 시에 「URL 파라미터가 있으면 복원, 없으면 기본값」으로 분기:
renderSpread();
if (!applyStateFromUrl()) resetCategories();
render();
「어느 현·어떤 조건이 선택되었는가」를 취할 수 있도록 이벤트를 설계. 포인트는 슬라이더를 input으로 보내지 않는 것 (1회 조작 시 대량 전송이 발생함). 묘사는 input으로, 측정은 확정 시의 change로 1회만.
function track(name, params) {
if (typeof window.gtag === "function" &&
window.GA_MEASUREMENT_ID && window.GA_MEASUREMENT_ID.indexOf("XXXX") === -1) {
...
전송 이벤트: select_pref / change_tenure / change_style / change_household / share 등.
나아가, 후술할 공유에서 붙는 쿼리(Query)로 인해 리포트가 분열되지 않도록, page_location에서 쿼리를 제거하여 전송:
<script>
window.GA_MEASUREMENT_ID = "G-XXXXXXXXXX"; // ← 자신의 ID로
window.dataLayer = window.dataLayer || [];
...
측정 ID를 한 곳에서 교체할 수 있게 만들고, 미설정 상태일 때는 일절 전송하지 않도록 해두면 개발 중의 오측정을 방지할 수 있습니다.
SNS에서 카드가 표시되게 하면 클릭률이 올라갑니다. og:image는 **절대 URL (Absolute URL)**로 설정하세요.
index.html을 업데이트해도, app.js가 브라우저 캐시(Browser Cache) 상태라면 새로운 기능이 작동하지 않습니다 (실제로 공유 버튼이 반응하지 않아 고생했습니다). 에셋(Asset)에 버전을 붙여 확실하게 업데이트하세요:
<link rel="stylesheet" href="style.css?v=2" />
<script src="data.js?v=2"></script>
<script src="app.js?v=2"></script>
업데이트할 때마다 번호를 올리면, 모든 사용자의 캐시를 확실하게 전환할 수 있습니다.
데스크톱 하위 디렉토리가 다른 Git 리포지토리(Repository)에 포함되어 있었기에, 앱 전용 독립 리포지토리를 생성했습니다. 전략 메모나 원본 데이터는 .gitignore로 제외하고, 공개에 필요한 4개의 파일만 올립니다.
# 공개하고 싶지 않은 항목 제외
printf "PROJECT.md\n仕様書.md\ndata/\n" > .gitignore
git init -b main
...
수십 초 만에 https://<user>.github.io/rougo-howmuch/가 구동됩니다. 업데이트는 git add . && git commit && git push만 하면 됩니다.
공개 직후, 해외에서의 접속 발생: 미국, 유럽, 인도 등. 대부분은 SNS의 링크 프리뷰 크롤러(Crawler)나 검색 봇(Bot), GA4를 노린 스팸입니다. GA4는 알려진 봇을 기본적으로 제외하므로, "실적"은 실시간(Real-time)이 아닌 표준 보고서 + 조작 이벤트가 포함된 세션으로 확인하는 것이 정답입니다. -
GA의 데이터 스트림(Data Stream) URL 설정은 측정 조건이 아님: 측정은 측정 ID(Measurement ID)에 종속됩니다. URL은 메타 정보일 뿐이며, 잘못 설정되어 있어도 데이터는 전달됩니다. -
캐시(Cache): HTML은 업데이트되는데 app.js가 옛날 버전 그대로라 기능이 작동하지 않는 사고. ?v=로 회피합니다. -
자신의 접속 제외: GA4 관리 → 내부 트래픽 제외(자신의 IP) + 데이터 필터를 "활성화"로 설정.
정적 사이트(Static Site)라도 공개, 측정, 확산, 상태 공유까지 한 번에 할 수 있습니다. 특히 "결과를 URL로 공유할 수 있는" 설계는 개인 개발의 확산에 효과적이었습니다. 마찬가지로 "만들고 끝"인 단계에서 벗어나고 싶은 분들에게 참고가 되길 바랍니다.
직접 써보시고 소감을 들려주시면 기쁘겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기