정보실

웹학교

정보실

javascript HTML, CSS 및 JavaScript를 사용하여 처음부터 PWA를 작성하는 방법

본문

How to build a PWA from scratch with HTML, CSS, and JavaScript 


프로그레시브 웹 앱은 기본 앱 느낌을 전통적인 웹 앱으로 가져 오는 방법입니다. 

PWA를 통해 유용성을 높이고 훌륭한 사용자 경험을 제공하는 모바일 앱 기능으로 웹 사이트를 향상 시킬 수 있습니다.


https://www.freecodecamp.org/news/build-a-pwa-from-scratch-with-html-css-and-javascript/ 


이 기사에서는 HTML, CSS 및 JavaScript로 PWA를 처음부터 작성합니다. 우리가 다룰 주제는 다음과 같습니다.


프로그레시브 웹 앱이란 무엇입니까? 


프로그레시브 웹 앱은 최신 웹 기능을 사용하여 사용자에게 앱과 유사한 경험을 제공하는 웹 앱입니다. 

결국, 일부 향상된 기능을 갖춘 브라우저에서 실행되는 것은 일반 웹 사이트일 뿐입니다. 

그것은 당신에게 능력을 제공합니다 :

  • 모바일 홈 화면에 설치하려면
  • 오프라인 일 때 액세스하려면
  • 카메라에 액세스하려면
  • 푸시 알림을 받으려면
  • 백그라운드 동기화를 수행하려면

그리고 훨씬 더.


그러나 기존 웹 앱을 PWA로 변환하려면 웹 앱 매니페스트 파일과 서비스 워커를 추가하여 조금씩 조정해야 합니다.


이 새로운 용어에 대해 걱정하지 마십시오. 아래에서 다룰 것입니다.


먼저 전통적인 웹 앱을 만들어야 합니다. 마크 업부터 시작하겠습니다.


마크 업 


HTML 파일은 비교적 간단합니다. 우리는 기본 태그에 모든 것을 포장합니다.


  • index.html에서
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link rel="stylesheet" href="css/style.css" />
    <title>Dev'Coffee PWA</title>
  </head>
  <body>
    <main>
      <nav>
        <h1>Dev'Coffee</h1>
        <ul>
          <li>Home</li>
          <li>About</li>
          <li>Blog</li>
        </ul>
      </nav>
      <div class="container"></div>
    </main>
    <script src="js/app.js"></script>
  </body>
</html>

탐색 태그가 있는 탐색 모음을 만듭니다. 

그런 다음 클래스 .container가있는 div는 나중에 JavaScript로 추가 한 카드를 보유합니다.


이제 우리는 그것을 벗어 났으므로 CSS로 스타일을 지정합시다.


Styling 


여기에서 평소와 같이 필요한 글꼴을 가져옵니다. 그런 다음 기본 동작을 방지하기 위해 재설정을 수행합니다.


  • css/style.css에서
@import url("https://fonts.googleapis.com/css?family=Nunito:400,700&display=swap");
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background: #fdfdfd;
  font-family: "Nunito", sans-serif;
  font-size: 1rem;
}
main {
  max-width: 900px;
  margin: auto;
  padding: 0.5rem;
  text-align: center;
}
nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
ul {
  list-style: none;
  display: flex;
}

li {
  margin-right: 1rem;
}
h1 {
  color: #e74c3c;
  margin-bottom: 0.5rem;
}

그런 다음 주요 요소의 최대 너비를 900px로 제한하여 큰 화면에서 보기 좋게 만듭니다.


탐색 표시 줄의 경우 로고가 왼쪽에 있고 링크가 오른쪽에 있기를 원합니다. 

따라서 nav 태그를 플렉스 컨테이너로 만든 후 justify-content : space-between; 그들을 정렬합니다.

  • css/style.css에서


.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  grid-gap: 1rem;
  justify-content: center;
  align-items: center;
  margin: auto;
  padding: 1rem 0;
}
.card {
  display: flex;
  align-items: center;
  flex-direction: column;
  width: 15rem auto;
  height: 15rem;
  background: #fff;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
  border-radius: 10px;
  margin: auto;
  overflow: hidden;
}
.card--avatar {
  width: 100%;
  height: 10rem;
  object-fit: cover;
}
.card--title {
  color: #222;
  font-weight: 700;
  text-transform: capitalize;
  font-size: 1.1rem;
  margin-top: 0.5rem;
}
.card--link {
  text-decoration: none;
  background: #db4938;
  color: #fff;
  padding: 0.3rem 1rem;
  border-radius: 20px;
}

여러 개의 카드가 있으므로 컨테이너 요소의 경우 그리드로 표시됩니다. 

그리고 그리드 템플릿 열을 사용하여 repeat (auto-fit, minmax (15rem, 1fr))을 사용하면 공간이 충분한 경우 최소 15rem 너비를 사용할 수 있도록 카드를 반응 형으로 만들 수 있습니다 (없으면 1fr).


멋지게 보이기 위해 .card 클래스의 그림자 효과를 두 배로 늘리고 object-fit : cover on .card--avatar를 사용하여 이미지가 늘어나지 않도록 합니다.


이제 훨씬 나아 보이지만 여전히 표시 할 데이터가 없습니다.


다음 섹션에서 수정하겠습니다.


JavaScript로 데이터 표시 


로드 하는 데 시간이 걸리는 큰 이미지를 사용했습니다. 이것은 서비스 근로자의 힘을 가장 잘 보여줄 것입니다.


앞서 말했 듯이 .container 클래스는 카드를 보유합니다. 따라서 선택해야 합니다.


  • js/app.js에서
const container = document.querySelector(".container")
const coffees = [
  { name: "Perspiciatis", image: "images/coffee1.jpg" },
  { name: "Voluptatem", image: "images/coffee2.jpg" },
  { name: "Explicabo", image: "images/coffee3.jpg" },
  { name: "Rchitecto", image: "images/coffee4.jpg" },
  { name: " Beatae", image: "images/coffee5.jpg" },
  { name: " Vitae", image: "images/coffee6.jpg" },
  { name: "Inventore", image: "images/coffee7.jpg" },
  { name: "Veritatis", image: "images/coffee8.jpg" },
  { name: "Accusantium", image: "images/coffee9.jpg" },
]

그런 다음 이름과 이미지가 포함 된 카드 배열을 만듭니다.


  • js/app.js에서
const showCoffees = () => {
  let output = ""
  coffees.forEach(
    ({ name, image }) =>
      (output += `
              <div class="card">
                <img class="card--avatar" src=${image} />
                <h1 class="card--title">${name}</h1>
                <a class="card--link" href="#">Taste</a>
              </div>
              `)
  )
  container.innerHTML = output
}

document.addEventListener("DOMContentLoaded", showCoffees)

위의 이 코드를 사용하면 이제 배열을 반복하여 HTML 파일에 표시 할 수 있습니다. 

모든 것이 작동 하도록 하기 위해, DOM (Document Object Model) 컨텐츠가 showCoffees 메소드를 실행하기 위해 로딩을 마칠 때까지 기다립니다.


우리는 많은 것을 해왔지만 지금은 전통적인 웹 앱을 가지고 있습니다. PWA 기능을 소개하여 다음 섹션에서 변경해 보겠습니다.


웹앱 매니페스트 (Web App Manifest) 


웹앱 매니페스트는 브라우저에 웹앱에 대해 알려주는 간단한 JSON 파일입니다. 

사용자의 모바일 장치 또는 데스크탑에 설치할 때 어떻게 작동해야 하는지 알려줍니다. 

그리고 홈 화면에 추가 프롬프트를 표시하려면 웹 앱 매니페스트가 필요합니다.


이제 웹 매니페스트가 무엇인지 알았으므로 루트 디렉토리에 manifest.json이라는 이름의 새 파일 (이와 같이 이름을 지정해야 함)을 만들어 보겠습니다. 

그런 다음 아래에 이 코드 블록을 추가하십시오.


  • manifest.json에서


{
  "name": "Dev'Coffee",
  "short_name": "DevCoffee",
  "start_url": "index.html",
  "display": "standalone",
  "background_color": "#fdfdfd",
  "theme_color": "#db4938",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/images/icons/icon-72x72.png",
      "type": "image/png", "sizes": "72x72"
    },
    {
      "src": "/images/icons/icon-96x96.png",
      "type": "image/png", "sizes": "96x96"
    },
    {
      "src": "/images/icons/icon-128x128.png",
      "type": "image/png","sizes": "128x128"
    },
    {
      "src": "/images/icons/icon-144x144.png",
      "type": "image/png", "sizes": "144x144"
    },
    {
      "src": "/images/icons/icon-152x152.png",
      "type": "image/png", "sizes": "152x152"
    },
    {
      "src": "/images/icons/icon-192x192.png",
      "type": "image/png", "sizes": "192x192"
    },
    {
      "src": "/images/icons/icon-384x384.png",
      "type": "image/png", "sizes": "384x384"
    },
    {
      "src": "/images/icons/icon-512x512.png",
      "type": "image/png", "sizes": "512x512"
    }
  ]
}

결국 필수 및 선택적 속성이 있는 JSON 파일일 뿐입니다.


short_name : 브라우저가 스플래시 화면을 시작하면 화면에 표시되는 이름이 됩니다.


start_url : 앱이 열릴 때 사용자에게 표시되는 페이지입니다.


display : 브라우저에 앱을 표시하는 방법을 알려줍니다. minimal-ui, fullscreen, browser 등과 같은 몇 가지 모드가 있습니다. 여기서는 독립형 모드를 사용하여 브라우저와 관련된 모든 것을 숨 깁니다.


background_color : 브라우저가 스플래시 화면을 시작하면 화면의 배경이 됩니다.


theme_color : 앱을 열 때 상태 표시 줄의 배경색이 됩니다.


orientation : 앱을 표시 할 때 브라우저에 방향을 알려줍니다.


icons : 브라우저가 스플래시 화면을 시작하면 화면에 표시되는 아이콘이 됩니다. 여기서는 모든 크기를 사용하여 장치의 기본 아이콘에 맞췄습니다. 그러나 한두 가지만 사용할 수 있습니다. 그것은 당신에게 달려 있습니다.


이제 웹앱 매니페스트가 있으므로 HTML 파일에 추가하겠습니다.


  • index.html (head 태그)
<link rel="manifest" href="manifest.json" />
<!-- ios support -->
<link rel="apple-touch-icon" href="images/icons/icon-72x72.png" />
<link rel="apple-touch-icon" href="images/icons/icon-96x96.png" />
<link rel="apple-touch-icon" href="images/icons/icon-128x128.png" />
<link rel="apple-touch-icon" href="images/icons/icon-144x144.png" />
<link rel="apple-touch-icon" href="images/icons/icon-152x152.png" />
<link rel="apple-touch-icon" href="images/icons/icon-192x192.png" />
<link rel="apple-touch-icon" href="images/icons/icon-384x384.png" />
<link rel="apple-touch-icon" href="images/icons/icon-512x512.png" />
<meta name="apple-mobile-web-app-status-bar" content="#db4938" />
<meta name="theme-color" content="#db4938" />

보다시피, manifest.json 파일을 head 태그에 연결했습니다. iOS 지원을 처리하는 다른 링크를 추가하여 아이콘을 표시하고 테마 색상으로 상태 표시 줄을 채색하십시오.


이를 통해 이제 마지막 부분을 살펴보고 service worker를 소개 할 수 있습니다.


서비스 워커 란 무엇입니까? 


서비스 워커는 요청에 액세스하여 처리 할 수 ​​있으므로 PWA는 https에서만 실행됩니다. 따라서 보안이 필요합니다.


서비스 워커는 브라우저가 별도의 스레드로 백그라운드에서 실행되는 스크립트입니다. 

즉, 다른 위치에서 실행되며 웹 페이지와 완전히 분리됩니다. 이것이 DOM 요소를 조작 할 수 없는 이유입니다.


그러나 매우 강력합니다. 서비스 워커는 네트워크 요청을 가로 채서 처리하고, 캐시를 관리하여 오프라인 지원을 활성화하거나 사용자에게 푸시 알림을 보낼 수 있습니다.


S0 루트 폴더에 첫 번째 서비스 워커를 만들고 이름을 serviceWorker.js로 지정하겠습니다 (이름은 사용자에게 달려 있습니다). 

그러나 범위를 하나의 폴더로 제한하지 않도록 루트에 넣어야 합니다.


자산(assets) 캐시 


  • serviceWorker.js에서
const staticDevCoffee = "dev-coffee-site-v1"
const assets = [
  "/",
  "/index.html",
  "/css/style.css",
  "/js/app.js",
  "/images/coffee1.jpg",
  "/images/coffee2.jpg",
  "/images/coffee3.jpg",
  "/images/coffee4.jpg",
  "/images/coffee5.jpg",
  "/images/coffee6.jpg",
  "/images/coffee7.jpg",
  "/images/coffee8.jpg",
  "/images/coffee9.jpg",
]

self.addEventListener("install", installEvent => {
  installEvent.waitUntil(
    caches.open(staticDevCoffee).then(cache => {
      cache.addAll(assets)
    })
  )
})

이 코드는 먼저 위협적으로 보이지만 JavaScript 일 뿐이므로 걱정하지 마십시오.


캐시 staticDevCoffee의 이름과 캐시에 저장할 자산을 선언합니다. 

그리고 그 행동을 수행하려면 청취자를 자기 자신에게 연결해야 합니다.


self는 서비스 워커 자체입니다. 수명주기 이벤트를 듣고 그 대가로 무언가를 할 수 있습니다.


서비스 워커에는 여러 수명주기가 있으며 그 중 하나가 설치 이벤트입니다. 

서비스 워커가 설치 될 때 실행됩니다. 작업자가 실행 되자마자 트리거 되며 서비스 작업 자당 한 번만 호출됩니다.


설치 이벤트가 발생하면 콜백을 실행하여 이벤트 객체에 액세스 할 수 있습니다.


브라우저에서 무언가를 캐싱하는 것은 비동기 적이기 때문에 완료하는 데 시간이 걸릴 수 있습니다.


따라서 처리하려면 waitUntil()을 사용해야 합니다. 예상대로 동작이 완료 될 때까지 기다립니다.


캐시 API가 준비되면 open() 메소드를 실행하고 이름을 caches.open (staticDevCoffee)에 인수로 전달하여 캐시를 작성할 수 있습니다.


그런 다음 promise를 반환하여 cache.addAll (assets)를 사용하여 자산을 캐시에 저장하는 데 도움이 됩니다.


image-cache 


이제 자산을 브라우저에 성공적으로 캐시했습니다. 

다음에 페이지를 로드 할 때 서비스 작업자는 요청을 처리하고 오프라인 상태 인 경우 캐시를 가져옵니다.


캐시를 가져 오겠습니다.


자산 가져 오기 (Fetch the assets) 


  • serviceWorker.js에서
self.addEventListener("fetch", fetchEvent => {
  fetchEvent.respondWith(
    caches.match(fetchEvent.request).then(res => {
      return res || fetch(fetchEvent.request)
    })
  )
})

여기서는 fetch 이벤트를 사용하여 데이터를 다시 가져옵니다. 

콜백은 fetchEvent에 대한 액세스를 제공합니다. 

그런 다음 브라우저의 기본 응답을 방지하기 위해 respondWith()를 첨부합니다. 

대신 페치 조치를 완료하는 데 시간이 걸릴 수 있으므로 약속을 리턴합니다.


캐시가 준비되면 caches.match (fetchEvent.request)를 적용합니다. 

캐시의 무언가가 fetchEvent.request와 일치하는지 확인합니다. 

그건 그렇고, fetchEvent.request는 단지 우리의 자산 배열입니다.


그런 다음 약속을 반환합니다. 마지막으로 결과가 존재하면 결과를 반환하거나 존재하지 않으면 초기 페치를 반환 할 수 있습니다.


이제 서비스 워커가 애셋을 캐싱 및 페치할 수 있으므로 이미지 로드 시간이 상당히 늘어납니다.


그리고 가장 중요한 것은 앱을 오프라인 모드에서 사용할 수 있게 만드는 것입니다.


그러나 서비스 작업자만으로는 작업을 수행 할 수 없습니다. 프로젝트에 등록해야 합니다.


서비스 워커 등록 (Register the Service Worker) 


  • js/app.js에서
if ("serviceWorker" in navigator) {
  window.addEventListener("load", function() {
    navigator.serviceWorker
      .register("/serviceWorker.js")
      .then(res => console.log("service worker registered"))
      .catch(err => console.log("service worker not registered", err))
  })
}

여기서는 serviceWorker가 현재 브라우저에서 지원되는지 확인합니다 (여전히 모든 브라우저에서 지원되지는 않음).


그런 다음 serviceWorker.js 파일의 이름을 작업자를 등록하기 위한 매개 변수로 navigator.serviceWorker.register()에 전달하여 서비스 작업자를 등록하기 위해 페이지 로드 이벤트를 수신합니다.


이번 업데이트로 일반 웹 앱이 PWA로 전환되었습니다.


마지막 생각들 


이 기사에서 우리는 PWA가 얼마나 놀라운지를 보았습니다. 

웹 앱 매니페스트 파일과 서비스 워커를 추가하면 기존 웹 앱의 사용자 경험이 실제로 향상됩니다. 

이는 PWA가 빠르고 안전하며 신뢰할 수 있으며 가장 중요한 것은 오프라인 모드를 지원하기 때문입니다.


현재 많은 프레임 워크에 서비스 작업자 파일이 이미 설정되어 있습니다. 

그러나 Vanilla JavaScript로 구현하는 방법을 알고 있으면 PWA를 이해하는 데 도움이 될 수 있습니다.


또한 자산을 동적으로 캐싱하거나 캐시 크기 등을 제한하여 서비스 작업자와 더 나아갈 수 있습니다.


여기에서 실시간으로 확인할 수 있으며 소스 코드는 여기에 있습니다.



페이지 정보

조회 43회 ]  작성일20-02-29 18:43
PWA

웹학교