{"id":23392904,"url":"https://github.com/leegeunhyeok/paper","last_synced_at":"2025-04-11T11:41:36.723Z","repository":{"id":42737132,"uuid":"271942077","full_name":"leegeunhyeok/paper","owner":"leegeunhyeok","description":"🎉 SNS 앱 예제로 배우는 프로그레시브 웹 앱 실습코드","archived":false,"fork":false,"pushed_at":"2023-01-06T12:29:53.000Z","size":10791,"stargazers_count":9,"open_issues_count":12,"forks_count":10,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-25T08:02:29.839Z","etag":null,"topics":["progressive-web-app","pwa","pwa-example"],"latest_commit_sha":null,"homepage":"http://www.yes24.com/Product/Goods/91360603","language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leegeunhyeok.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-13T04:47:13.000Z","updated_at":"2023-07-19T11:30:15.000Z","dependencies_parsed_at":"2023-02-06T02:16:49.247Z","dependency_job_id":null,"html_url":"https://github.com/leegeunhyeok/paper","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leegeunhyeok%2Fpaper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leegeunhyeok%2Fpaper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leegeunhyeok%2Fpaper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leegeunhyeok%2Fpaper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leegeunhyeok","download_url":"https://codeload.github.com/leegeunhyeok/paper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248385508,"owners_count":21094900,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["progressive-web-app","pwa","pwa-example"],"created_at":"2024-12-22T05:16:42.198Z","updated_at":"2025-04-11T11:41:36.688Z","avatar_url":"https://github.com/leegeunhyeok.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n  \u003cimg src=\"./icon.png\" width=\"300\"\u003e\n\n  # Paper\n  🌐 PWA Example | Paper\n\n\u003c/div\u003e\n\n## 원고 오류사항\n\n발견된 내용 오류 사항들을 정리한 링크입니다. 확실하게 검토하지 못한 점 대단히 죄송합니다 😥\n\n- [8장] 백그라운드 동기화 return 누락, [확인하기](https://github.com/leegeunhyeok/paper/issues/3)\n\n## 주요 기능\n\n\u003cimg width=\"250\" src=\"./pwa.png\"\u003e\n\n기본적으로 구현되어있는 주요 기능입니다.\n\n- 게시물 조회\n- 게시물 작성\n- 게시물 삭제\n- 게시물 좋아요 표시\n\n실습을 진행하며 구현해나갈 주요 기능입니다.\n\n- 설치 가능한 Paper\n- 오프라인 지원\n  - 오프라인 게시물 조회\n  - 오프라인 게시물 작성\n  - 오프라인 게시물 삭제\n  - 오프라인 좋아요 표시\n- 백그라운드 동기화\n  - 오프라인 상태에서 수행한 작업 동기화\n- 좋아요 푸시 알림\n- 이 외의 다양한 부가 기능\n\n[Paper 미리보기](./PREVIEW.md)\n\n## 챕터\n\n각 챕터별 구현된 코드입니다.  \n실습 진행 시 참고하거나, 빠르게 진행하기 위해 제공합니다.\n\n- 챕터 1 - 시작하기\n- 챕터 2 - 실습을 위한 개발환경 준비하기\n- 챕터 3 - 프로그레시브 웹 앱이 되기 위한 준비\n- [챕터 4](https://github.com/leegeunhyeok/paper/tree/ch4) - PWA의 핵심, 서비스 워커\n- [챕터 5](https://github.com/leegeunhyeok/paper/tree/ch5) - 오프라인을 위한 캐시 스토리지 API\n- [챕터 6](https://github.com/leegeunhyeok/paper/tree/ch6) - IndexedDB 사용하기\n- [챕터 7](https://github.com/leegeunhyeok/paper/tree/ch7) - 웹 앱 매니페스트 (Web App Manifest)\n- [챕터 8](https://github.com/leegeunhyeok/paper/tree/ch8) - Sync, 백그라운드 동기화\n- [챕터 9](https://github.com/leegeunhyeok/paper/tree/ch9) - 서비스 워커와 클라이언트간 메시지 주고받기\n- [챕터 10](https://github.com/leegeunhyeok/paper/tree/ch10) - Push, 사용자에게 알림 보내기\n\n## 프로젝트 구조\n\n주요 코드는 아래와 같이 구성되어있으며, 실습 시 `(* 강조)`된 소스코드에 기능을 구현합니다.\n\n```\n.\n├── (* app.js) : Paper 서버 메인 코드\n├── config\n│   └── (* default.json) : Paper 서버 설정 파일\n├── package.json\n├── (* push.js) : Paper 푸시 알림 전송 모듈\n├── sample\n│   └── (* IndexedDB.html) : IndexedDB 기초 실습 파일 \n├── server\n│   └── Paper 서버 코드\n├── upload : 게시물 이미지 저장 경로\n└── workspace\n    ├── css\n    │   └── CSS 파일\n    ├── fonts\n    │   └── 웹 폰트 파일\n    ├── icons\n    │   └── Paper 아이콘 (앱 아이콘, 푸시 아이콘, 뱃지 등)\n    ├── images\n    │   └── Paper UI 이미지\n    ├── js\n    │   ├── app.js : Paper 기본 기능 구현 코드\n    │   ├── axios.min.js : axios 라이브러리\n    │   ├── (* common.js) : Paper 공통 코드 (메인/로그인)\n    │   ├── (* index.js) : Paper 메인 페이지 코드\n    │   ├── login.js : Paper 로그인 페이지 코드\n    │   ├── (* paper-store.js) : Paper IndexedDB 기능 코드\n    │   ├── polyfill.min.js : ES6 프로미스 폴리필\n    │   └── util.js : Paper 유틸 코드\n    ├── (* index.html) : Paper 메인 페이지\n    ├── login.html : Paper 로그인 페이지\n    ├── (* manifest.json) : 웹 앱 매니페스트\n    ├── (* service-worker.js) : 서비스 워커\n    └── splash\n        └── iOS/iPad 스플래시 이미지\n```\n\n## 코드 조각\n\n실습 중 직접 작성해야하는 단순한 타이핑 작업을 최소화할 수 있도록 코드 조각을 제공합니다.\n\n### 캐싱 리스트\n\n5. 오프라인을 위한 캐시 스토리지\n\n```javascript\nconst IMMUTABLE_APPSHELL = [\n  '/favicon.ico',\n  '/favicon-16x16.png',\n  '/favicon-32x32.png',\n  '/manifest.json',\n  '/images/no_image.png',\n  '/images/add_photo.svg',\n  '/images/clear.svg',\n  '/images/delete.svg',\n  '/images/favorite_active.svg',\n  '/images/favorite.svg',\n  '/images/menu.svg',\n  '/images/notification.svg',\n  '/images/notification_disabled.svg',\n  '/images/notification_enabled.svg'\n];\n```\n\n```javascript\nconst MUTABLE_APPSHELL = [\n  '/',\n  '/login',\n  '/js/app.js',\n  '/js/util.js',\n  '/js/common.js',\n  '/js/axios.min.js',\n  '/js/index.js',\n  '/js/login.js',\n  '/js/paper-store.js',\n  '/css/index.css',\n  '/css/login.css'\n];\n```\n\n### 웹 앱 매니페스트\n\n7. 웹 앱 매니페스트 (Web App Menifest)\n\n```json\n{\n  \"name\": \"\",\n  \"short_name\": \"\",\n  \"icons\": [\n    {\n      \"src\": \"\",\n      \"sizes\": \"\",\n      \"type\": \"\"\n    }\n  ],\n  \"theme_color\": \"\",\n  \"background_color\": \"\",\n  \"orientation\": \"\",\n  \"display\": \"\",\n  \"start_url\": \"\"\n}\n```\n\n```html\n\u003c!-- Web App Manifest 추가 --\u003e\n\u003clink rel=\"manifest\" href=\"/manifest.json\"\u003e\n\u003cmeta name=\"apple-mobile-web-app-capable\" content=\"yes\"\u003e\n\u003cmeta name=\"apple-mobile-web-app-title\" content=\"Paper\"\u003e\n\u003clink rel=\"apple-touch-icon\" href=\"/icons/apple-touch-icon.png\"\u003e\n\u003cmeta name=\"theme-color\" content=\"#ffffff\"\u003e\n\u003cmeta name=\"apple-mobile-web-app-status-bar-style\" content=\"default\"\u003e\n```\n\n```html\n\u003c!-- iOS/iPadOS 스플래시 이미지 --\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_828x1792.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n  href=\"/splash/icon_1242x2688.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n  href=\"/splash/icon_1125x2436.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n  href=\"/splash/icon_1242x2208.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_750x1334.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_2048x2732.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_1668x2224.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_640x1136.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_1668x2388.png\"\n/\u003e\n\u003clink\n  rel=\"apple-touch-startup-image\"\n  media=\"screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n  href=\"/splash/icon_1536x2048.png\"\n/\u003e\n```\n\n## 고급\n\n```bash\n# SCSS 파일 수정 시 감지하여 CSS로 즉시 변환\nnpm run sass\n\n# SCSS 파일 빌드하여 CSS 파일로 변환\nnpm run build-style\n```\n\n`node-sass` 모듈 설치 필요 (package.json 참고)\n\n## 이미지 출처\n\n- App Icon: [import_contacts](https://www.material.io/resources/icons/?icon=import_contacts) icon edited by `Geunhyeok LEE`\n- Icon images: [Material icons](https://www.material.io/resources/icons)\n- Sample images: [Pexels](https://www.pexels.com) - CC0 Images\n  - cat_1.jpg\n  - cat_2.jpg\n  - puppy.jpg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleegeunhyeok%2Fpaper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleegeunhyeok%2Fpaper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleegeunhyeok%2Fpaper/lists"}