UX Engineer 이야기
네이티브 앱과 같은 사용자 경험 - PWA (feat. 웹 크롤링 cheerio)
Seulbi Lee
2024. 11. 11. 07:50
들어가며
어머니께서 매주 듣는 콘텐츠가 있는데 해당 사이트에서는 아이폰에서 바로 재생 지원을 하지 않고 있었습니다.
안드로이드에서 아이폰으로 기기변경을 하신 후 해당 콘텐츠를 듣지 못하게 되어 제가 xml을 이용해 구글 시트에서 해당 콘텐츠의 URL을 가져와서 노션에 사용하시기 편하게 오디오로 올려주는 것을 거의 2년 동안 했었는데요.
바쁘거나 잊어버려서 놓치게 되면 길게는 몇 달까지도 딸한테 차마 올려달라고 말은 못 하고 못 듣고 계셨던 게 마음에 걸려 저걸 어떻게든 자동화 시켜야겠다! 라는 마음을 먹고 이번에 만들게 되었습니다.
기존 사이트 콘텐츠 크롤링 하기
요 문제는 기존에 영민 선임님이 포스팅 한 cheerio로 쉽게 해결할 수 있었습니다.
다만 타 사이트의 자료를 가져오는 것이라 CORS 문제를 만나게 되었는데요,
일단 저는 react 환경에서 작업을 하였고 vite로 세팅한 환경이였습니다.
그래서 간단하게 vite.config.ts 파일에서 server proxy 설정 변경으로 CORS 문제를 해결할 수 있었습니다.
server: {
proxy: {
// 브라우저에서 /api로 요청이 들어오면,
"/api": {
target: "http://www.sample.or.kr/", // target url을 sample 사이트로 변경하고,
changeOrigin: true, // target과 같은 도메인의 요청인 것처럼
rewrite: (path: string) => path.replace(/^\/api/, ""), // target url로 요청시 /api 문자열은 제거
},
},
},
크롤링 해온 데이터로 화면은 잘 만들어졌고, netlify로 배포를 시도했는데, CORS 오류가 또 나네?
배포 시 proxy 설정을 또 해줘야 하더라고요.
저는 netlify에 github을 연결해 main 브랜치로 push 시 자동 배포가 일어나게 작업을 해놓았기 때문에 netlify 설정만 조금 바꿔주면 되었습니다.
netlify.toml라는 파일명의 파일을 만들어 root 경로에 넣어주면 되는데, 내용은 아래와 같이 작성해 주면 되었습니다.
[[redirects]]
from = "/api/*"
to = "http://www.sample.or.kr/:splat"
status = 200
force = true
vite.config.ts에서 작성한 내용과 형태만 조금 다를 뿐 같은 내용이었습니다.
코드에서 /api로 시작하는 경로는 모두 제가 크롤링 해오는 사이트 URL로 변경해서 인식하게 해둔 거죠.
해당 파일을 올린 후 빌드 하니 CORS 오류 없이 모든 게 완벽!
그런데, 어머니가 URL 접속 시 계속 사파리에서 탭이 생성될 거고, 해당 탭들이 쌓이는 게 별로 마음에 들지 않았습니다. (물론 정기적으로 탭이 삭제하게 설정해두는 것도 있었지만 좀 더 앱의 사용성으로 편하게 사용하게 해드리고 싶었음)
그래서 생각난 PWA !!
웹 사이트를 PWA로 만들기
PWA란?
프로그레시브 웹 앱(Progressive Web Apps)의 줄임말로, 모바일 기기에서 네이티브 앱(Native App)과 같은 사용자 경험을 제공하는 웹 앱입니다. 이는 기존의 모바일 웹 앱과는 달리 네이티브 앱과 유사한 기능을 제공할 수 있다는 것이 가장 큰 특징입니다. 예를 들면 네이티브 앱으로만 구현이 가능했던 알림 기능을 PWA로도 구현이 가능하게 되고, Service Worker를 통한 오프라인 접속을 대응할 수 있습니다.
PWA를 사용하면 사용자가 앱을 다운로드하거나, 업데이트할 필요 없이 웹 브라우저를 통해 앱을 바로 사용할 수 있습니다.
이는 PWA의 장점이자, 가장 큰 단점이기도 한데, 사용자가 쉽게 웹 브라우저를 통해 홈 화면 바로 가기를 생성하면 앱과 같은 사용성을 제공받을 수 있지만, 반대로 사용자가 웹 브라우저를 통해 홈 화면 바로 가기를 생성하지 않는다면 (아이폰의 경우는 반드시 사파리 브라우저를 통해 홈 화면 바로 가기를 생성해야 함) PWA에서 제공하는 서비스를 이용할 수 없습니다.
다시 본론으로 돌아와서 브라우저로 접속 후 홈 화면 바로 가기로 추가만 해두면 앱 사용자 경험과 동일한 경험으로 웹 사이트를 이용하게 해주니 제가 생각한 것과 딱 들어맞아 PWA 세팅을 시작했습니다.
PWA는 이전 내부 프로젝트 할 때 다른 작업자가 작업하는 것을 봐서 생각보다 간단하게 할 수 있다는 것을 알고 있었는데요,
PWA를 만들기 위해 저는 Manifest를 이용하는 방법을 사용했습니다.
Manifest
{
"short_name": "MDN", // 앱 단축 이름
"name": "MDN Web Docs", // 앱 이름
"icons": [ // 아이콘 정보, 다양한 해상도 이미지 추가 시 알아서 필요한 이미지 사용
{
"src": "/favicon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": ".", // 아이콘 클릭 시 로딩 할 페이지
"display": "standalone", // 앱의 화면 모드 (browser, fullscreen, standalone)
"theme_color": "#000000", // 앱의 테마 색으로 상태 표시 줄이나 상단 바 등에 적용 됨
"background_color": "#ffffff", // 배경 색상으로 stylesheet 불러오기 전에 표시되는 배경 색
"scope": "/", // PWA에 포함될 페이지 .은 모든 페이지 포함 의미
"orientation": "portrait", // 앱 실행 시 화면 방향에 대한 설정 (any, landscape, portrait 등이 있음)
}
위 예시는 mdn 문서에서 가져온 건데, 해당 설정들로 간단하게 mainifest.json 파일을 만든 후 root 경로에 추가해 주시면 됩니다.
여기에 사이트 주소를 적고 start 하면 현재 내 사이트가 PWA 설정을 잘 해놨는지 평가받을 수 있는데,
여기서 Edit Your Mainfest를 누른 후 각 필드를 알맞게 채우고
Download Mainifest를 누르면 json 파일을 받을 수 있습니다.
Mainifest 파일 설정이 완료되면 index.html에 아래와 같이 추가해 줍니다.
<link rel="manifest" href="/manifest.json" />
그리고 iOS에서 웹 앱 관련 설정을 적용하려면 설정을 더 추가해야 하는데요,
<meta name="apple-mobile-web-app-capable" content="yes" />
apple-mobile-web-app-capable 설정을 yes로 지정해야 합니다.
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
iOS에서는 상단 바 스타일을 해당 메타 태그를 통해 별도 지정해야 하는데,
- default (흰색 상단 바에 검은색 아이콘)
- black (검은색 상단 바에 흰색 아이콘)
- black-translucent (웹페이지의 배경 색상의 상단 바와 흰색 아이콘)
으로 설정할 수 있습니다.
<link rel="apple-touch-icon" href="/vite.png" />
또 iOS에서는 Manifest에서 추가한 아이콘을 사용하지 않기 때문에 위 태그 또한 추가가 필요합니다.
그리고 스플래시 화면을 표시하려면 별도 이미지와 태그를 추가해야 하는데요, 스플래시 이미지는 기기의 화면 크기와 정확히 일치해야 한다는 조건이 있으므로, 해당 사이트를 통해 스플래시 이미지를 사이즈에 맞게 추가 하는걸 추천합니다.
위 사이트에서 이미지 추가 후 스플래시 이미지 생성 시 link 태그도 같이 만들어주는데요,
해당 link 태그를 index.html 파일에 추가해 주면 기본적인 PWA 준비가 끝납니다.
기본적인 PWA 설정을 블로그 dev에 적용 시켜보았는데요,
주소창이 없어져서 훨씬 시원하게 보이네요.
PWA에서 가장 중요한 기능인 앱 푸시와 오프라인 대응 코드까지 설명해 보려고 했는데 글이 너무 길어져서 해당 부분은 다음 편에 이어서 작성해 보도록 하겠습니다.
이 글은 pxd XE Group Blog에서도 보실 수 있습니다.