aboutsummaryrefslogtreecommitdiff
path: root/files/ko/web/progressive_web_apps
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:42:17 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:42:17 -0500
commitda78a9e329e272dedb2400b79a3bdeebff387d47 (patch)
treee6ef8aa7c43556f55ddfe031a01cf0a8fa271bfe /files/ko/web/progressive_web_apps
parent1109132f09d75da9a28b649c7677bb6ce07c40c0 (diff)
downloadtranslated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.gz
translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.bz2
translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.zip
initial commit
Diffstat (limited to 'files/ko/web/progressive_web_apps')
-rw-r--r--files/ko/web/progressive_web_apps/add_to_home_screen/index.html218
-rw-r--r--files/ko/web/progressive_web_apps/app_structure/index.html283
-rw-r--r--files/ko/web/progressive_web_apps/index.html76
-rw-r--r--files/ko/web/progressive_web_apps/installable_pwas/index.html123
-rw-r--r--files/ko/web/progressive_web_apps/offline_service_workers/index.html205
-rw-r--r--files/ko/web/progressive_web_apps/re-engageable_notifications_push/index.html253
-rw-r--r--files/ko/web/progressive_web_apps/소개/index.html92
7 files changed, 1250 insertions, 0 deletions
diff --git a/files/ko/web/progressive_web_apps/add_to_home_screen/index.html b/files/ko/web/progressive_web_apps/add_to_home_screen/index.html
new file mode 100644
index 0000000000..e3c6e738d5
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/add_to_home_screen/index.html
@@ -0,0 +1,218 @@
+---
+title: Add to home screen
+slug: Web/Progressive_web_apps/Add_to_home_screen
+tags:
+ - Manifest
+ - PWA
+ - Service Worker
+ - 아이콘
+ - 프로그레시브 웹 앱
+ - 홈 화면에 추가
+translation_of: Web/Progressive_web_apps/Add_to_home_screen
+---
+<p class="summary">Add to Home screen (or A2HS for short) is a feature available in modern smartphone browsers that allows developers to easily and conveniently add a shortcut to their Home screen representing their favorite web app (or site) so they can subsequently access it with a single tap. This guide explains how A2HS is used, and what you need to do as a developer to allow your users to take advantage of it.</p>
+
+<h2 id="Why_A2HS">Why A2HS?</h2>
+
+<p>A2HS is thought to be part of the <a href="/en-US/docs/Web/Progressive_web_apps">Progressive Web App</a> philosophy — giving web apps the same user experience advantages as native apps so they can compete in today's ecosystem wars. Part of this is the simple gesture of accessing an app by tapping its icon on your Home screen, and then having it appear neatly in its own window. A2HS makes this possible.</p>
+
+<h2 id="What_browsers_support_A2HS">What browsers support A2HS?</h2>
+
+<p>A2HS is supported by Mobile Chrome/Android Webview since version 31, Opera for Android since version 32, and Firefox for Android since <a href="/en-US/docs/Mozilla/Firefox/Releases/58">version 58</a>.</p>
+
+<h2 id="How_do_you_use_it">How do you use it?</h2>
+
+<p>We've written a very simple example web site (<a href="https://mdn.github.io/pwa-examples/a2hs/">see our demo live</a>, and also <a href="https://github.com/mdn/pwa-examples/tree/master/a2hs">see the source code</a>) that doesn't do much, but was developed with the necessary code to allow it to be added to a Home screen, as well as a service worker to enable it to be used offline. The example displays a series of fox pictures.</p>
+
+<p>If you have Firefox for Android available, use it to navigate to our demo at <code>https://mdn.github.io/pwa-examples/a2hs/</code>. You'll see fox pictures, but more important, you'll see a "home" icon with a plus (+) icon inside it — this is the "Add to Home screen" icon displayed for any site that has the necessary features in place.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15762/add-to-home-screen-icon.png" style="border-style: solid; border-width: 1px; display: block; height: 64px; margin: 0px auto; width: 500px;"></p>
+
+<p>Tapping this will show a confirmation banner — pressing the big + <em>ADD TO HOME SCREEN</em> button completes the action, adding the app to the Home screen. (Note: In Android 8 and higher, a system-level "Add to Home screen" permission dialog will be shown first.)</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15772/fx-a2hs-banner.png" style="border-style: solid; border-width: 1px; display: block; height: 421px; margin: 0px auto; width: 700px;"></p>
+
+<p>If you have Mobile Chrome available, the experience is slightly different; upon loading our site, you'll see an install banner pop up asking whether you want to add this app to your Home screen.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15771/chrome-a2hs-banner.png" style="border-style: solid; border-width: 1px; display: block; height: 421px; margin: 0px auto; width: 700px;"></p>
+
+<div class="note">
+<p><strong>Note</strong>: You can find out a lot more about Chrome install banners from the article <a href="https://developers.google.com/web/fundamentals/app-install-banners/">Web App Install Banners</a>.</p>
+</div>
+
+<p>If you choose not to add it to your Home screen at this point, you can do so later using the <em>Add to Home screen</em> icon in the main Chrome menu.</p>
+
+<p>Regardless of which browser you are using, when you choose to add the app to your Home screen, you'll see it appear along with a short title, in the same way that native apps do.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15770/a2hs-on-home-screen.png" style="border-style: solid; border-width: 1px; display: block; height: 243px; margin: 0px auto; width: 400px;"></p>
+
+<p>Tapping this icon opens it up, but as a fullscreen app, you'll no longer see the browser UI around it.</p>
+
+<h2 id="How_do_you_make_an_app_A2HS-ready">How do you make an app A2HS-ready?</h2>
+
+<p>To enable your app to be added to a Home screen, it needs the following:</p>
+
+<ul>
+ <li>To be served over HTTPs — the web is increasingly being moved in a more secure direction, and many modern web technologies (A2HS included) will work only on secure contexts.</li>
+ <li>To have a manifest file with the correct fields filled in, linked from the HTML head.</li>
+ <li>To have an appropriate icon available for displaying on the Home screen.</li>
+ <li>Chrome additionally requires the app to have a service worker registered (e.g., so it can function when offline).</li>
+</ul>
+
+<h3 id="Manifest">Manifest</h3>
+
+<p>The web manifest is written in standard JSON format and should be placed somewhere inside your app directory (in the root is probably best) with the name <code><em>somefilename</em>.webmanifest</code> (we've chosen <code>manifest.webmanifest</code>). It contains multiple fields that define certain information about the web app and how it should behave.</p>
+
+<div class="note">
+<p><strong>Note</strong>: The <code>.webmanifest</code> extension is specified in the <a href="https://w3c.github.io/manifest/#media-type-registration">Media type registration</a> section of the specification, but generally browsers will support manifests with other appropriate extensions, e.g. <code>.json</code>.</p>
+</div>
+
+<p>The fields needed for A2HS are as follows:</p>
+
+<ul>
+ <li><code>background_color</code>: Specifies a background color to be used in some app contexts. The most relevant one to A2HS is the splash screen displayed when the app icon on the Home screen is tapped and it first starts to load (this currently appears only when apps have been added to the Home screen by Chrome).</li>
+ <li><code>display</code>: Specifies how the app should be displayed. To make it feel like a distinct app (and not just a web page), you should choose a value such as <code>fullscreen</code> (no UI is shown at all) or <code>standalone</code> (very similar, but system-level UI elements such as the status bar might be visible).</li>
+ <li><code>icons</code>: Specifies icons for the browser to use when representing the app in different places (such as on the task switcher, or more important, the Home screen). We've included only one in our demo.</li>
+ <li><code>name</code>/<code>short_name</code>: These fields provide an app name to be displayed when representing the app in different places. <code>name</code> provides the full app name, and <code>short_name</code> provides a shortened name to be used when there is insufficient space to display the full name. You are advised to provide both if your app's name is particularly long.</li>
+ <li><code>start_url</code>: Provides a path to the asset that should be loaded when the added-to-Home screen app is launched. Note that this has to be a relative URL pointing to the site index, relative to the url of the manifest. Also, be aware that Chrome requires this before it will display the install banner, whereas Firefox doesn't require it for showing the home-with-a-plus icon.</li>
+</ul>
+
+<p>The manifest for our sample app looks like this:</p>
+
+<pre class="brush: js">{
+ "background_color": "purple",
+ "description": "Shows random fox pictures. Hey, at least it isn't cats.",
+ "display": "fullscreen",
+ "icons": [
+ {
+ "src": "icon/fox-icon.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ }
+ ],
+ "name": "Awesome fox pictures",
+ "short_name": "Foxes",
+ "start_url": "/pwa-examples/a2hs/index.html"
+}</pre>
+
+<h3 id="Appropriate_icon">Appropriate icon</h3>
+
+<p>As shown in the above manifest listing, we are including a 192 x 192 px icon for use in our app. You can include more sizes if you want; Android will choose the most appropriate size for each different use case. You could also decide to include different types of icons so devices can use the best one they are able to (e.g., Chrome already supports the WebP format).</p>
+
+<p>Note that the <code>type</code> member in each icon's object specifies the icon's mimetype, so the browser can quickly read what type the icon is, and then ignore it and move to a different icon if it doesn't support it.</p>
+
+<p>In terms of how to design the icon, you should follow the same best practices you'd follow for any Android icon (see the <a href="https://developer.android.com/guide/practices/ui_guidelines/icon_design.html">Android icon design guidelines</a>).</p>
+
+<h3 id="Link_the_HTML_to_the_manifest">Link the HTML to the manifest</h3>
+
+<p>To finish setting up your manifest, you need to reference it from the HTML of your application's home page:</p>
+
+<pre class="brush: html">&lt;<span class="pl-ent">link</span> <span class="pl-e">rel</span>=<span class="pl-s"><span class="pl-pds">"</span>manifest<span class="pl-pds">"</span></span> <span class="pl-e">href</span>=<span class="pl-s"><span class="pl-pds">"</span>manifest.webmanifest<span class="pl-pds">"</span></span>&gt;</pre>
+
+<p>Browsers that support A2HS will know where to look for your manifest once this is in place.</p>
+
+<h2 id="What_does_A2HS_not_give_you">What does A2HS not give you?</h2>
+
+<p>Bear in mind that when you add an app to your Home screen, it just makes the app easily accessible — it doesn't download the app's assets and data to your device and make the app available offline, or anything like that. To make your app work offline, you have to use the <a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a> to handle storing the assets offline, and if required, <a href="/en-US/docs/Web/API/Web_Storage_API">Web storage</a> or <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a> to store its data.</p>
+
+<p>In our example app, we've just used a service worker to store all necessary files. The service worker is registered against the site with the final code block in the <code><a href="https://github.com/mdn/pwa-examples/blob/master/a2hs/index.js">index.js</a></code> file. We then cache all the site's assets using the <a href="/en-US/docs/Web/API/Cache">Cache API</a>, and serve them from the cache instead of the network using the code in the <a href="https://github.com/mdn/pwa-examples/blob/master/a2hs/sw.js">sw.js</a> file.</p>
+
+<h2 id="A2HS_on_desktop">A2HS on desktop</h2>
+
+<p>While originally intended to improve user experience on mobile OSes, there is movement to make PWAs installable on desktop platforms too.</p>
+
+<div class="note">
+<p><strong>Note</strong>: At the time of writing, the functionality described below was only supported in newer versions of Chrome — by default on Windows, and behind the <code>#enable-desktop-pwas</code> flag on macOS.</p>
+</div>
+
+<h3 id="Adding_an_install_button">Adding an install button</h3>
+
+<p>To make our PWA installable on desktop, we first added a button to our document to allow users to do the installation — this isn't made available automatically on desktop apps, and the installation needs to be triggered by a user gesture:</p>
+
+<pre class="brush: html">&lt;button class="add-button"&gt;Add to home screen&lt;/button&gt;</pre>
+
+<p>We then gave it some simple styling:</p>
+
+<pre class="brush: css">.add-button {
+ position: absolute;
+ top: 1px;
+ left: 1px;
+}</pre>
+
+<h3 id="JavaScript_for_handling_the_install">JavaScript for handling the install</h3>
+
+<p>At the bottom of our <a href="https://github.com/mdn/pwa-examples/blob/master/a2hs/index.js"><code>index.js</code> file</a>, we added some JavaScript to handle the installation. First of all, we declare a <code>deferredPrompt</code> variable (which we'll explain later on), get a reference to our install button, and set it to <code>display: none</code> initially:</p>
+
+<pre class="brush: js">let deferredPrompt;
+const addBtn = document.querySelector('.add-button');
+addBtn.style.display = 'none';</pre>
+
+<p>We hide the button initially because the PWA will not be available for install until it follows the A2HS criteria. When this happens, supporting browsers will fire a <code>beforeinstallprompt</code> event. We can then use a handler like the one below to handle the installation:</p>
+
+<pre class="brush: js">window.addEventListener('beforeinstallprompt', (e) =&gt; {
+ // Prevent Chrome 67 and earlier from automatically showing the prompt
+ e.preventDefault();
+ // Stash the event so it can be triggered later.
+ deferredPrompt = e;
+ // Update UI to notify the user they can add to home screen
+ addBtn.style.display = 'block';
+
+ addBtn.addEventListener('click', (e) =&gt; {
+ // hide our user interface that shows our A2HS button
+ addBtn.style.display = 'none';
+ // Show the prompt
+ deferredPrompt.prompt();
+ // Wait for the user to respond to the prompt
+ deferredPrompt.userChoice.then((choiceResult) =&gt; {
+ if (choiceResult.outcome === 'accepted') {
+ console.log('User accepted the A2HS prompt');
+ } else {
+ console.log('User dismissed the A2HS prompt');
+ }
+ deferredPrompt = null;
+ });
+ });
+});</pre>
+
+<p>So here we:</p>
+
+<ul>
+ <li>Call {{domxref("Event.preventDefault()")}} to stop Chrome 67 and earlier from calling the install prompt automatically (this behavior changed in Chrome 68).</li>
+ <li>Store the event object in the <code>deferredPrompt</code> variable so it can be used later on to perform the actual installation.</li>
+ <li>Set the button to <code>display: block</code> so it appears in the UI for the user to click.</li>
+ <li>Set a <code>click</code> handler for the button.</li>
+</ul>
+
+<p>The click handler contains the following steps:</p>
+
+<ul>
+ <li>Hide the button again with <code>display: none</code> — it is no longer needed once the app is installed.</li>
+ <li>Use the <code>prompt()</code> method available on the <code>beforeinstallprompt</code> event object (stored in <code>deferredPrompt</code>) to trigger showing the install prompt.</li>
+ <li>Respond to the user's interaction with the prompt using the <code>userChoice</code> property, again available on the <code>beforeinstallprompt</code> event object.</li>
+ <li>Set <code>deferredPrompt</code> to null since it is no longer needed.</li>
+</ul>
+
+<p>So when the button is clicked, the install prompt appears.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/16281/chrome-desktop-a2hs-banner.png" style="border-style: solid; border-width: 1px; display: block; height: 163px; margin: 0px auto; width: 300px;"></p>
+
+<p>If the user selects <em>Install</em>, the app is installed (available as standalone desktop app), and the Install button no longer shows (the <code>onbeforeinstallprompt</code> event no longer fires if the app is already installed). When you open the app, it will appear in its own window:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/16280/a2hs-installed-desktop.png" style="border-style: solid; border-width: 1px; display: block; height: 296px; margin: 0px auto; width: 500px;"></p>
+
+<p>If the user selects <em>Cancel</em>, the state of the app goes back to how it was before the button was clicked.</p>
+
+<div class="note">
+<p><strong>Note</strong>: The code for this section was mostly taken from <a href="https://developers.google.com/web/fundamentals/app-install-banners/">App install banners/Add to Home Screen</a> by Pete LaPage.</p>
+</div>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/Progressive_web_apps">Progressive web apps</a></li>
+ <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a></li>
+ <li><a href="/en-US/docs/Web/Manifest">Web manifest reference</a></li>
+ <li><a href="https://developers.google.com/web/fundamentals/app-install-banners/">App install banners</a></li>
+</ul>
+
+<div>{{QuickLinksWithSubpages("/en-US/docs/Web/Progressive_web_apps/")}}</div>
diff --git a/files/ko/web/progressive_web_apps/app_structure/index.html b/files/ko/web/progressive_web_apps/app_structure/index.html
new file mode 100644
index 0000000000..b50a62e724
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/app_structure/index.html
@@ -0,0 +1,283 @@
+---
+title: 프로그레시브 웹 앱 구조
+slug: Web/Progressive_web_apps/App_structure
+tags:
+ - App shell
+ - PWA
+ - Service Workers
+ - Streams
+ - js13kGames
+ - 구조
+ - 프로그레시브
+ - 프로그레시브 웹 앱
+translation_of: Web/Progressive_web_apps/App_structure
+---
+<div>{{PreviousMenuNext("Web/Apps/Progressive/Introduction", "Web/Apps/Progressive/Offline_Service_workers", "Web/Apps/Progressive")}}</div>
+
+<p class="summary">이제 우리는 PWA의 원리에 대해 알고 있습니다. 실제 앱의 권장 구조에 대해 살펴봅시다. 우리는 <a href="https://mdn.github.io/pwa-examples/js13kpwa/">js13kPWA</a> 어플리케이션을 왜 그렇게 구축하였는지, 그리고 무슨 이점이 있는지 분석하는 것으로 시작할 것입니다.</p>
+
+<h2 id="앱의_구조">앱의 구조</h2>
+
+<p>웹 사이트를 렌더링하는 것에는 서버 사이드와 클라이언트 사이드라는 두 가지 다른 접근법이 있습니다. 이 둘 모두 장점과 단점을 갖고 있으며, 여러분은 이 두 접근법을 적절히 혼합할 수 있습니다.</p>
+
+<ul>
+ <li>서버 사이드 렌더링(SSR)은 웹사이트가 서버에서 렌더링되는 것을 의미합니다. 따라서 더 빠른 첫 로딩을 제공할 수 있지만, 페이지간의 이동에서 모든것들을 매번 다운로드해야합니다. 브라우저를 넘어 훌륭하게 동작하고 개발 프로세스를 돕는 많은 도구들이 있지만, 각 페이지를 로딩할 때마다 서버를 거쳐야 한다는 점에서 로딩 속도 및 성능으로 인식되는 일반적인 측면에서 어려움이 있습니다.</li>
+ <li>클라이언트 사이드 렌더링(CSR)은 웹 사이트가 다른 페이지로 이동할 때 브라우저에서 거의 즉시 업데이트될 수 있도록 해주지만, 시작할 때 더 많은 초기 다운로드와 추가 렌더링이 필요합니다. 웹사이트는 첫 방문시 더 느리지만 다음 방문에서 훨씬 빠릅니다.</li>
+</ul>
+
+<p>SSR과 CSR을 혼합하여 서버에서 웹 사이트를 렌더링하고, 컨텐츠를 캐싱한 후, 필요할 때 클라이언트 사이드에서 렌더링을 업데이트하여 최고의 결과를 이끌어 낼 수 있습니다. 첫 페이지 로딩은 SSR때문에 빠르고, 페이지간의 이동은 클라이언트에서 변경된 부분만 다시 렌더링하므로 부드럽습니다.</p>
+
+<p>여러분이 선호하는 접근법을 사용해 PWA를 구축할 수 있지만, 다른 것들보다 더 잘 동작하는 몇 가지 방법이 있습니다. 가장 유명한 접근법은 바로 위에서 설명한 SSR과 CSR을 혼합한 "app shell" 개념이며, 그 다음으로 "오프라인 우선" 방법론입니다. 이는 우리의 예제 앱을 사용해 다음 문서에서 자세한 내용에 대해 설명할 것입니다. 간략히 설명드릴 <a href="/ko/docs/Web/API/Streams_API">Streams API</a>를 포함하는 새로운 접근법도 있습니다.</p>
+
+<h2 id="App_shell">App shell</h2>
+
+<p>App shell 개념은 가능한 최소한의 사용자 인터페이스를 로딩하는것에 중점을 두고 있으며, 이를 캐싱하여 다음 방문에서 앱의 모든 컨텐츠가 로딩되기 전에 오프라인에서도 사용이 가능합니다. 이렇게 하면 다음에 누군가 기기로부터 앱에 방문할 때, UI는 캐시로부터 즉시 로딩되고 새로운 컨텐츠는 서버로부터 요청합니다(캐시에서 이미 사용할 수 없는 경우).</p>
+
+<p>이 구조는 빠르고, 사용자가 로딩 스피너나 빈 페이지 대신 "무언가"를 즉시 보게됨으로써 속도가 빠름을 느낄 수 있습니다. 또한 네트워크 연결이 불가할 때 웹사이트를 오프라인에서도 접근할 수 있도록 허용합니다.</p>
+
+<p>우리는 서버로부터 요청된 것과 <a href="/ko/docs/Web/API/Service_Worker_API">service worker</a>를 사용해 캐시된 것으로부터 받은 것들을 제어할 수 있습니다. 다음 문서에서 자세한 내용에 대해 설명할 것입니다. 지금은 구조 자체에 대해 집중합시다.</p>
+
+<h3 id="이걸_사용해야_하는_이유가_무엇인가요">이걸 사용해야 하는 이유가 무엇인가요?</h3>
+
+<p>이 구조는 웹 사이트에 모든 PWA 기능들로부터 최고의 이점을 제공합니다. App shell을 캐싱하고 동적인 컨텐츠를 관리하여 훌륭하게 성능을 향상시킵니다. 기본 shell과 더불어, 앱이 사용자들의 브라우저에서 지원되지 않을 때도 여전히 사용하다는 전제하에 <a href="/ko/docs/Web/Apps/Progressive/Add_to_home_screen">홈 화면에 추가</a> 또는 <a href="/ko/docs/Web/API/Push_API">푸시 알림</a>과 같은 다른 기능들도 추가할 수 있습니다. 이 점이 점진적인 향상의 아름다움입니다.</p>
+
+<p>웹 사이트는 웹의 이점들을 모두 유지하면서 즉각적인 반응과 견고한 성능을 가진 네이티브 앱처럼 느껴집니다.</p>
+
+<h3 id="연결_가능하며_점진적이고_디자인에_반응하는_것">연결 가능하며, 점진적이고 디자인에 반응하는 것</h3>
+
+<p>어플리케이션을 디자인할 때 PWA의 이점을 기억하고 이를 유지하는 것이 중요합니다. App shell 접근법은 웹 사이트가 다음과 같이 될 수 있도록 허용합니다.</p>
+
+<ul>
+ <li>연결 가능: 네이티브 앱처럼 동작한다고해도 이는 여전히 웹 사이트입니다. 여러분은 페이지의 링크를 클릭할 수 있고, 누군가에게 URL을 공유할 수 있습니다.</li>
+ <li>점진적: "좋은 오래된 기본적인 웹사이트"로 시작해서 새로운 기능을 점진적으로 추가하되, 브라우저에서 지원하지 않는 기능을 감지하고 이에 대한 적절한 에러 처리를 할 것을 기억하시기 바랍니다. 예를 들어, service worker의 도움을 통한 오프라인 모드는 더 나은 웹 사이트 경험을 제공하는 부가적인 특성일 뿐, 없어도 충분히 사용이 가능합니다.</li>
+ <li>반응형: 반응형 웹 디자인 또한 프로그레시브 웹 앱에 적용됩니다. 둘 다 주로 모바일 기기에 해당됩니다. 기기와 브라우저는 아주 다양합니다. 따라서 <a href="/ko/docs/Mozilla/Mobile/Viewport_meta_tag">뷰포트 meta 태그</a>, <a href="/ko/docs/Web/CSS/Media_Queries/Using_media_queries">CSS 미디어 쿼리</a>, <a href="/ko/docs/Web/CSS/CSS_Flexible_Box_Layout">Flexbox</a>, <a href="/ko/docs/Web/CSS/CSS_Grid_Layout">CSS Grid</a> 와 같은 기술들을 사용해 여러분의 웹사이트를 다양한 화면 크기, 뷰포트 또는 픽셀 밀도에서 동작하도록 준비하는 것이 중요합니다.</li>
+</ul>
+
+<h2 id="다른_개념_streams">다른 개념: streams</h2>
+
+<p><a href="/ko/docs/Web/API/Streams_API">Streams API</a>를 사용해 완전히 다른 방식으로 서버 또는 클라이언트 사이드 렌더링 수행할 수 있습니다. Service worker로부터의 약간 도움으로 우리는 컨텐츠를 분석하는 방법을 크게 향상시킬 수 있습니다.</p>
+
+<p>App shell 모델은 사용할 모든 리소스를 웹 사이트가 렌더링을 시작하기 전에 필요로합니다. 이는 브라우저가 실제로 데이터를 스트리밍하고 엘리먼트가 웹 사이트에 로드되고 렌더링되었을 때 여러분이 볼 수 있으므로 HTML과 다릅니다. 하지만, JavaScript를 "동작 가능하게" 하려면, 이를 전체적으로 다운로드해야 합니다.</p>
+
+<p>Streams API는 개발자가 서버로부터의 데이터 스트리밍에 직접 접근할 수 있도록 해줍니다. 여러분이 데이터에 대한 작업을 수행하길 원할 경우(비디오에 필터를 추가하는 것과 같은), 모든 데이터의 다운로드 및 blob로의 변환(어떤 타입으로든)을 기다릴 필요없이 바로 시작할 수 있습니다. Streams API는 시작, 다른 stream으로 연결, 취소, 에러 확인 등의 세분화된 컨트롤을 제공합니다.</p>
+
+<p>이론적으로 스트리밍은 더 나은 모델이지만, 더 복잡하며 글을 작성하는 시점(2018년 3월)에서 Streams API는 여전히 작업중이며 모든 주요 브라우저에서 아직 완전하게 사용이 가능하지 않습니다. 사용이 가능해지면 이는 컨텐츠를 제공하는 가장 빠른 방법이 될 것입니다. 성능 측면에서 아주 큰 이점을 갖게 될 것입니다.</p>
+
+<p>작동하는 예제와 자세한 내용은 <a href="/ko/docs/Web/API/Streams_API">Streams API 문서</a>를 확인하시기 바랍니다.</p>
+
+<h2 id="예제_어플리케이션의_구조">예제 어플리케이션의 구조</h2>
+
+<p><a href="https://mdn.github.io/pwa-examples/js13kpwa/">js13kPWA</a> 웹 사이트 구조는 아주 간단합니다. 하나의 HTML 파일(<a href="https://github.com/mdn/pwa-examples/blob/master/js13kpwa/index.html">index.html</a>)과 기본적인 CSS 스타일링(<a href="https://github.com/mdn/pwa-examples/blob/master/js13kpwa/style.css">style.css</a>), 몇 가지 이미지, 스크립트, 폰트로 구성되어 있습니다. 폴더 구조는 다음과 같습니다.</p>
+
+<p><img alt="Folder structure of js13kPWA." src="https://mdn.mozillademos.org/files/15925/js13kpwa-directory.png" style="border-style: solid; border-width: 1px; display: block; height: 356px; margin: 0px auto; width: 320px;"></p>
+
+<h3 id="HTML">HTML</h3>
+
+<p>HTML의 관점에서보면 app shell은 컨텐츠 섹션 외부의 모든 영역입니다.</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+&lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;js13kGames A-Frame entries&lt;/title&gt;
+ &lt;meta name="description" content="A list of A-Frame entries submitted to the js13kGames 2017 competition, used as an example for the MDN articles about Progressive Web Apps."&gt;
+ &lt;meta name="author" content="end3r"&gt;
+ &lt;meta name="theme-color" content="#B12A34"&gt;
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
+ &lt;meta property="og:image" content="icons/icon-512.png"&gt;
+ &lt;link rel="shortcut icon" href="favicon.ico"&gt;
+ &lt;link rel="stylesheet" href="style.css"&gt;
+ &lt;link rel="manifest" href="js13kpwa.webmanifest"&gt;
+ &lt;script src="data/games.js" defer&gt;&lt;/script&gt;
+ &lt;script src="app.js" defer&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;header&gt;
+ &lt;p&gt;&lt;a class="logo" href="http://js13kgames.com"&gt;&lt;img src="img/js13kgames.png" alt="js13kGames"&gt;&lt;/a&gt;&lt;/p&gt;
+&lt;/header&gt;
+&lt;main&gt;
+ &lt;h1&gt;js13kGames A-Frame entries&lt;/h1&gt;
+ &lt;p class="description"&gt;List of games submitted to the &lt;a href="http://js13kgames.com/aframe"&gt;A-Frame category&lt;/a&gt; in the &lt;a href="http://2017.js13kgames.com"&gt;js13kGames 2017&lt;/a&gt; competition. You can &lt;a href="https://github.com/mdn/pwa-examples/blob/master/js13kpwa"&gt;fork js13kPWA on GitHub&lt;/a&gt; to check its source code.&lt;/p&gt;
+ &lt;button id="notifications"&gt;Request dummy notifications&lt;/button&gt;
+ &lt;section id="content"&gt;
+ // Content inserted in here
+ &lt;/section&gt;
+&lt;/main&gt;
+&lt;footer&gt;
+ &lt;p&gt;© js13kGames 2012-2018, created and maintained by &lt;a href="http://end3r.com"&gt;Andrzej Mazur&lt;/a&gt; from &lt;a href="http://enclavegames.com"&gt;Enclave Games&lt;/a&gt;.&lt;/p&gt;
+&lt;/footer&gt;
+&lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>{{htmlelement("head")}} 섹션은 title, description, CSS 링크, 웹 manifest, games 컨텐츠 JS 파일, app.js 파일을 포함합니다. JavaScript 어플리케이션이 초기화되는 곳이기도 합니다. {{htmlelement("body")}}는 {{htmlelement("header")}}(연결된 이미지를 포함), {{htmlelement("main")}}페이지(title, description, 컨텐츠를 위한 공간), {{htmlelement("footer")}}(저작권 및 링크)로 나누어져 있습니다.</p>
+
+<p>app의 유일한 작업은 js13kGames 2017 대회의 A-Frame 항목을 모두 나열하는 것입니다. 보시다시피 매우 평범하고, 한 페이지 웹 사이트 입니다. 중요한 것은 실제 PWA 기능들의 구현에 집중할 수 있는 무언가 간단한 것을 갖는 것입니다.</p>
+
+<h3 id="CSS">CSS</h3>
+
+<p>CSS도 평범합니다. {{cssxref("@font-face")}}를 사용해 커스텀 폰트를 로딩 및 사용하고, 몇 가지 HTML 엘리먼트에 간단한 스타일을 적용합니다. 전반적인 접근은 모바일(반응형 웹 디자인 접근법)과 데스크탑 기기 모두에서 괜찮게 보이도록 하는 것입니다.</p>
+
+<h3 id="메인_앱_JavaScript">메인 앱 JavaScript</h3>
+
+<p>app.js 파일은 다음 문서에서 자세히 살펴볼 몇 가지 것들을 합니다. 먼저, 다음 템플릿을 기반으로 컨텐츠를 생성합니다.</p>
+
+<pre class="brush: js">var template = "&lt;article&gt;\n\
+ &lt;img src='data/img/SLUG.jpg' alt='NAME'&gt;\n\
+ &lt;h3&gt;#POS. NAME&lt;/h3&gt;\n\
+ &lt;ul&gt;\n\
+ &lt;li&gt;&lt;span&gt;Author:&lt;/span&gt; &lt;strong&gt;AUTHOR&lt;/strong&gt;&lt;/li&gt;\n\
+ &lt;li&gt;&lt;span&gt;Twitter:&lt;/span&gt; &lt;a href='https://twitter.com/TWITTER'&gt;@TWITTER&lt;/a&gt;&lt;/li&gt;\n\
+ &lt;li&gt;&lt;span&gt;Website:&lt;/span&gt; &lt;a href='http://WEBSITE/'&gt;WEBSITE&lt;/a&gt;&lt;/li&gt;\n\
+ &lt;li&gt;&lt;span&gt;GitHub:&lt;/span&gt; &lt;a href='https://GITHUB'&gt;GITHUB&lt;/a&gt;&lt;/li&gt;\n\
+ &lt;li&gt;&lt;span&gt;More:&lt;/span&gt; &lt;a href='http://js13kgames.com/entries/SLUG'&gt;js13kgames.com/entries/SLUG&lt;/a&gt;&lt;/li&gt;\n\
+ &lt;/ul&gt;\n\
+&lt;/article&gt;";
+var content = '';
+for(var i=0; i&lt;games.length; i++) {
+ var entry = template.replace(/POS/g,(i+1))
+ .replace(/SLUG/g,games[i].slug)
+ .replace(/NAME/g,games[i].name)
+ .replace(/AUTHOR/g,games[i].author)
+ .replace(/TWITTER/g,games[i].twitter)
+ .replace(/WEBSITE/g,games[i].website)
+ .replace(/GITHUB/g,games[i].github);
+ entry = entry.replace('&lt;a href=\'http:///\'&gt;&lt;/a&gt;','-');
+ content += entry;
+};
+document.getElementById('content').innerHTML = content;</pre>
+
+<p>다음으로, service worker를 등록합니다.</p>
+
+<pre class="brush: js">if('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('/pwa-examples/js13kpwa/sw.js');
+};</pre>
+
+<p>다음 코드 블럭은 버튼을 클릭했을 때 알림에 대한 권한을 요청합니다.</p>
+
+<pre class="brush: js">var button = document.getElementById("notifications");
+button.addEventListener('click', function(e) {
+ Notification.requestPermission().then(function(result) {
+ if(result === 'granted') {
+ randomNotification();
+ }
+ });
+});</pre>
+
+<p>마지막 블럭은 게임 리스트로부터 랜덤하게 선택된 항목을 나타내는 알림을 생성합니다.</p>
+
+<pre class="brush: js">function randomNotification() {
+ var randomItem = Math.floor(Math.random()*games.length);
+ var notifTitle = games[randomItem].name;
+ var notifBody = 'Created by '+games[randomItem].author+'.';
+ var notifImg = 'data/img/'+games[randomItem].slug+'.jpg';
+ var options = {
+ body: notifBody,
+ icon: notifImg
+ }
+ var notif = new Notification(notifTitle, options);
+ setTimeout(randomNotification, 30000);
+}</pre>
+
+<h3 id="Service_worker">Service worker</h3>
+
+<p>빠르게 살펴볼 마지막 파일(sw.js)은 service worker입니다. 이는 먼저 games.js 파일로부터 데이터를 불러옵니다.</p>
+
+<pre class="brush: js">self.importScripts('data/games.js');</pre>
+
+<p>다음으로, app shell과 컨텐츠 모두로부터 캐싱할 모든 파일의 리스트를 생성합니다.</p>
+
+<pre class="brush: js">var cacheName = 'js13kPWA-v1';
+var appShellFiles = [
+ '/pwa-examples/js13kpwa/',
+ '/pwa-examples/js13kpwa/index.html',
+ '/pwa-examples/js13kpwa/app.js',
+ '/pwa-examples/js13kpwa/style.css',
+ '/pwa-examples/js13kpwa/fonts/graduate.eot',
+ '/pwa-examples/js13kpwa/fonts/graduate.ttf',
+ '/pwa-examples/js13kpwa/fonts/graduate.woff',
+ '/pwa-examples/js13kpwa/favicon.ico',
+ '/pwa-examples/js13kpwa/img/js13kgames.png',
+ '/pwa-examples/js13kpwa/img/bg.png',
+ '/pwa-examples/js13kpwa/icons/icon-32.png',
+ '/pwa-examples/js13kpwa/icons/icon-64.png',
+ '/pwa-examples/js13kpwa/icons/icon-96.png',
+ '/pwa-examples/js13kpwa/icons/icon-128.png',
+ '/pwa-examples/js13kpwa/icons/icon-168.png',
+ '/pwa-examples/js13kpwa/icons/icon-192.png',
+ '/pwa-examples/js13kpwa/icons/icon-256.png',
+ '/pwa-examples/js13kpwa/icons/icon-512.png'
+];
+var gamesImages = [];
+for(var i=0; i&lt;games.length; i++) {
+ gamesImages.push('data/img/'+games[i].slug+'.jpg');
+}
+var contentToCache = appShellFiles.concat(gamesImages);</pre>
+
+<p>다음 블럭은 service worker를 설치하여 위의 목록에 포함된 모든 파일을 실제로 캐싱합니다.</p>
+
+<pre class="brush: js">self.addEventListener('install', function(e) {
+ console.log('[Service Worker] Install');
+ e.waitUntil(
+ caches.open(cacheName).then(function(cache) {
+ console.log('[Service Worker] Caching all: app shell and content');
+ return cache.addAll(contentToCache);
+ })
+ );
+});</pre>
+
+<p>마지막으로, service worker는 가능한 경우 캐시로부터 컨텐츠를 패치하여 오프라인 기능을 제공합니다.</p>
+
+<pre class="brush: js">self.addEventListener('fetch', function(e) {
+ e.respondWith(
+ caches.match(e.request).then(function(r) {
+ console.log('[Service Worker] Fetching resource: '+e.request.url);
+ return r || fetch(e.request).then(function(response) {
+ return caches.open(cacheName).then(function(cache) {
+ console.log('[Service Worker] Caching new resource: '+e.request.url);
+ cache.put(e.request, response.clone());
+ return response;
+ });
+ });
+ })
+ );
+});</pre>
+
+<h3 id="JavaScript_데이터">JavaScript 데이터</h3>
+
+<p>게임 데이터는 JavaScript 객체(<a href="https://github.com/mdn/pwa-examples/blob/master/js13kpwa/data/games.js">games.js</a>)의 data 폴더에 있습니다.</p>
+
+<pre class="brush: js">var games = [
+ {
+ slug: 'lost-in-cyberspace',
+ name: 'Lost in Cyberspace',
+ author: 'Zosia and Bartek',
+ twitter: 'bartaz',
+ website: '',
+ github: 'github.com/bartaz/lost-in-cyberspace'
+ },
+ {
+ slug: 'vernissage',
+ name: 'Vernissage',
+ author: 'Platane',
+ twitter: 'platane_',
+ website: 'github.com/Platane',
+ github: 'github.com/Platane/js13k-2017'
+ },
+// ...
+ {
+ slug: 'emma-3d',
+ name: 'Emma-3D',
+ author: 'Prateek Roushan',
+ twitter: '',
+ website: '',
+ github: 'github.com/coderprateek/Emma-3D'
+ }
+];</pre>
+
+<p>모든 항목은 data/img 폴더안의 각각의 이미지를 갖고 있습니다. 이는 JavaScript를 사용해 컨텐츠 섹션으로 로딩될 컨텐츠입니다.</p>
+
+<h2 id="다음으로">다음으로</h2>
+
+<p>다음 문서에서는 service worker의 도움을 통한 오프라인 사용을 위해 app shell과 컨텐츠가 어떻게 캐싱되는지에 대해 더 자세히 살펴볼 것입니다.</p>
+
+<p>{{PreviousMenuNext("Web/Apps/Progressive/Introduction", "Web/Apps/Progressive/Offline_Service_workers", "Web/Apps/Progressive")}}</p>
diff --git a/files/ko/web/progressive_web_apps/index.html b/files/ko/web/progressive_web_apps/index.html
new file mode 100644
index 0000000000..c07ad4434d
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/index.html
@@ -0,0 +1,76 @@
+---
+title: 프로그레시브 웹 앱
+slug: Web/Progressive_web_apps
+tags:
+ - 앱
+ - 최신 웹 앱
+ - 프로그레시브 웹 앱
+translation_of: Web/Progressive_web_apps
+---
+<p class="summary">프로그레시브 웹 앱은 최신 웹 API와 전통적인 점진적 개선 전략을 함께 사용해 크로스 플랫폼 웹 어플리케이션을 생성합니다. 이러한 앱은 어디서든 동작하며 네이티브 앱에서의 사용자 경험 이점과 동일한 몇 가지 기능들을 제공합니다. 이 문서에서는 이에 대해 여러분이 알아야 할 모든 것들에 대해 알려드립니다.</p>
+
+<h2 id="PWA_이점">PWA 이점</h2>
+
+<p>PWA는 발견 가능, 설치 가능, 연결 가능해야 하고, 네트워크에 독립적이어야 하고, 점진적이고 재참여가 가능해야하며 반응형이고 안전해야 합니다. 이러한 것들이 무엇을 의미하는지는 <a href="/ko/docs/Web/Apps/Progressive/Advantages">프로그레시브 웹 앱 이점</a> 문서를 읽어보시기 바랍니다. PWA를 구현하는 방법은 아래 섹션에 나열된 가이드를 참조하십시오.</p>
+
+<h2 id="핵심_PWA_가이드">핵심 PWA 가이드</h2>
+
+<p>다음 가이드는 간단한 예제를 살펴보고 모든 조각이 어떻게 동작하는지 보여줌으로써 PWA 구현을 위해 해야하는 것들이 무엇인지 보여줍니다.</p>
+
+<ol>
+ <li><a href="/ko/docs/Web/Apps/Progressive/Introduction">프로그레시브 웹 앱 소개</a></li>
+ <li><a href="/ko/docs/Web/Apps/Progressive/App_structure">프로그레시브 웹 앱 구조</a></li>
+ <li><a href="/ko/docs/Web/Apps/Progressive/Offline_Service_workers">Service worker를 사용해 PWA를 오프라인에서 동작하게 만들기</a></li>
+ <li><a href="/ko/docs/Web/Apps/Progressive/Installable_PWAs">PWA를 설치가능하게 만드는 방법</a></li>
+ <li><a href="/ko/docs/Web/Apps/Progressive/Re-engageable_Notifications_Push">알림과 푸시를 사용해 PWA를 재참여(re-engageable)가능하게 만드는 방법</a></li>
+</ol>
+
+<div class="column-container">
+<div class="column-half">
+<h2 id="기술_가이드">기술 가이드</h2>
+
+<ul>
+ <li><a href="/ko/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">클라이언트 사이드 저장소</a> — 웹 저장소, IndexedDB, service worker를 언제 어떻게 사용하는지 보여주는 상세 가이드</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/API/Service_Worker_API/Using_Service_Workers">Service worker 사용</a> — Service Worker API에 대한 더 자세한 가이드.</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/API/IndexedDB_API/Using_IndexedDB">IndexedDB 사용</a> — IndexedDB의 근본에 대한 자세한 설명.</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Web Storage API 사용</a> — 간단하게 만들어진 Web storage API.</li>
+ <li><a class="external external-icon" href="https://developers.google.com/web/updates/2015/11/app-shell" rel="noopener">Application Shell 구조를 사용한 웹 앱 즉시 로딩</a> — App Shell 코딩 패턴을 사용해 빠르게 로딩되는 앱을 생성하는 가이드.</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/API/Push_API/Using_the_Push_API">Push API 사용</a> — Web Push API의 기초에 대해 배우기.</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/API/Notifications_API/Using_the_Notifications_API">Notifications API 사용</a> — 웹 알림 요약.</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/Apps/Modern/Responsive/responsive_design_building_blocks">반응형 디자인 블록 구축</a> — 반응형 디자인 기초, 최신 앱 레이아웃 필수 주제 배우기.</li>
+ <li><a href="https://developer.mozilla.org/ko/docs/Web/Apps/Modern/Responsive/Mobile_first">모바일 우선</a> — 반응형 어플리케이션 레이아웃을 생성할 때, 보통 기본적으로 모바일 레이아웃을 생성하고, 더 넓은 상단 레이아웃을 구축하는 것이 좋습니다.</li>
+ <li><a href="/ko/docs/Web/Apps/Progressive/Add_to_home_screen">홈 화면에 추가 가이드</a> — 앱을 홈 화면에 추가하여 얻을 수 있는 이점에 대해 배우기.</li>
+</ul>
+</div>
+
+<div class="column-half">
+<h2 id="도구">도구</h2>
+
+<ul>
+ <li><a class="external external-icon" href="https://localforage.github.io/localForage/" rel="noopener">localForage</a> — 아주 간단하게 클라이언트 사이드 데이터 저장소를 만들 수 있는 훌륭하고 가벼운 JavaScript 라이브러리. 기본적으로 IndexedDB를 사용하고 필요한 경우 Web SQL/Web Storage를 사용합니다.</li>
+ <li><a class="external external-icon" href="https://github.com/fxos-components/serviceworkerware" rel="noopener">ServiceWorkerWare</a> — 손쉬운 Service Worker 개발을 위한 Express 같은 마이크로프레임워크.</li>
+ <li><a class="external external-icon" href="https://github.com/mozilla/oghliner" rel="noopener">oghliner</a> — 템플릿이자 GitHub 페이지에 오프라인 웹 앱을 배포하기 위한 도구.</li>
+ <li><a class="external external-icon" href="https://github.com/GoogleChrome/sw-precache" rel="noopener">sw-precache</a> — 특정 리소스를 프리캐싱(미리 캐싱;precache)하는 service worker 코드를 생성하는 노드 모듈.</li>
+ <li><a class="external external-icon" href="https://github.com/GoogleChrome/workbox" rel="noopener">workbox</a> — 더 나은 캐싱 전략과 쉬운 프리캐싱을 제공하는 sw-precache의 정신적 지주.</li>
+ <li><a class="external external-icon" href="https://www.talater.com/upup/" rel="noopener">upup</a> — 사이트가 사용자들을 위해 항상 존재하도록 해주는 작은 스크립트.</li>
+ <li><a class="external external-icon" href="https://serviceworke.rs/" rel="noopener">The service worker cookbook</a> — 오프라인 앱 및 그 이상의 다양한 앱 구현 방법을 보여주는 훌륭한 service worker/push 가이드 시리즈.</li>
+</ul>
+
+<p> </p>
+</div>
+</div>
+
+<h2 id="함께_보기">함께 보기</h2>
+
+<ul>
+ <li><a href="https://developers.google.com/web/progressive-web-apps">Progressive web apps</a> on Google Developers</li>
+ <li class="graf--h3 graf--first" id="4c45"><a href="https://medium.com/@slightlylate/progressive-apps-escaping-tabs-without-losing-our-soul-3b93a8561955#.6czgj0myh">Progressive Web Apps: Escaping Tabs Without Losing Our Soul</a> by Alex Russell</li>
+ <li class="graf--h3 graf--first"><a href="https://developers.google.com/web/progressive-web-apps/checklist">Progressive Web Apps Check List</a></li>
+ <li class="graf--h3 graf--first"><a href="https://developers.google.com/web/tools/lighthouse">The Lighthouse Tool</a> by Google</li>
+ <li class="graf--h3 graf--first"><a href="https://github.com/angular/mobile-toolkit">Tools for building progressive web apps with Angular</a></li>
+ <li class="graf--h3 graf--first"><a href="https://github.com/codebusking/react-pwa-guide-kit">React PWA Guide Kit</a></li>
+ <li class="graf--h3 graf--first"><a href="https://www.pokedex.org/">Offline-capable Pokédex web site</a></li>
+ <li class="graf--h3 graf--first">
+ <p><a href="https://hnpwa.com/">Hacker News readers as Progressive Web Apps</a> </p>
+ </li>
+</ul>
diff --git a/files/ko/web/progressive_web_apps/installable_pwas/index.html b/files/ko/web/progressive_web_apps/installable_pwas/index.html
new file mode 100644
index 0000000000..df76c4ed2e
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/installable_pwas/index.html
@@ -0,0 +1,123 @@
+---
+title: PWA를 설치가능하게 만드는 방법
+slug: Web/Progressive_web_apps/Installable_PWAs
+tags:
+ - PWA
+ - a2hs
+ - js13kGames
+ - 설치가능
+ - 프로그레시브
+ - 프로그레시브 웹 앱
+ - 홈 화면에 추가
+translation_of: Web/Progressive_web_apps/Installable_PWAs
+---
+<div>{{PreviousMenuNext("Web/Apps/Progressive/Offline_Service_workers", "Web/Apps/Progressive/Re-engageable_Notifications_Push", "Web/Apps/Progressive")}}</div>
+
+<p class="summary">이전 문서에서는 <a href="/ko/docs/Web/API/Service_Worker_API">service worker</a>의 도움으로 <a href="https://mdn.github.io/pwa-examples/js13kpwa/">js13kPWA</a> 을 오프라인에서 동작하는 방법에 대해 알아보았습니다. 그런데 우리는 더 나아가 모바일 브라우저를 지원하는 웹 앱을 네이티브 앱처럼 설치할 수 있게 할수도 있습니다. 이 문서에서는 웹 manifest를 사용해 홈 화면에 추가라고 불리는 기능을 구현하는 방법에 대해 설명합니다.</p>
+
+<p>이러한 기술들은 앱을 URL을 수동으로 브라우저에 입력하는 대신 기기의 홈 화면에서 바로 실행할 수 있도록 해줍니다. 여러분의 웹 앱을 네이티브 어플리케이션 바로 옆 가장 좋은 자리에 놓을 수 있습니다. 따라서 접근이 더 쉽고, 브라우저 주변 기능이 없는 전체 화면에서 실행되도록 지정하여 더욱 더 네이티브 앱과 같은 느낌을 줄 수 있습니다.</p>
+
+<h2 id="요구_사항">요구 사항</h2>
+
+<p>웹 사이트를 설치가능하게 하려면 다음과 같은 것들이 필요합니다.</p>
+
+<ul>
+ <li><a href="/ko/Apps/Progressive/Add_to_home_screen#Manifest">올바른 값들로 채워진</a> 웹 manifest</li>
+ <li>보안 (HTTPS) 도메인에서 제공되는 웹 사이트</li>
+ <li>기기에서 앱을 나타낼 아이콘</li>
+ <li>앱을 오프라인에서 동작하게 하기 위한 service worker 등록(현재 Android용 Chrome에서만 요구됩니다)</li>
+</ul>
+
+<h3 id="manifest_파일">manifest 파일</h3>
+
+<p>핵심 요소는 JSON 형식으로 웹 사이트에 대한 모든 정보를 나열한 웹 manifest 파일입니다.</p>
+
+<p>파일은 일반적으로 웹 앱의 루트 폴더에 위치합니다. 앱의 title, 모바일 OS에서 앱을 나타내는데 사용(예를 들어, 홈 화면 아이콘)되는 다른 크기의 아이콘들의 경로, 로딩 또는 스플래시 화면에서 사용할 배경 색상과 같은 유용한 정보들을 포함합니다. 이는 브라우저가 웹 앱을 설치할 때 그리고 홈 화면에서 웹 앱을 적절히 표현하기 위해 필요한 정보입니다.</p>
+
+<p><a href="https://mdn.github.io/pwa-examples/js13kpwa/">js13kPWA</a> 웹 앱의 <code>js13kpwa.webmanifest</code> 파일은 코드의 다음 라인을 통해 <code>index.html</code> 파일의 {{htmlelement("head")}} 섹션에 포함됩니다.</p>
+
+<pre class="brush: html">&lt;link rel="manifest" href="js13kpwa.webmanifest"&gt;</pre>
+
+<div class="note">
+<p><strong>노트</strong>: 과거에 manifest로 사용되던 몇 가지 흔한 확장자들이 있습니다: <code>manifest.webapp</code> 은 Firefox OS 웹 manifest로 유명하며, 많은 사람들이 JSON 구조로 내용이 구성된 <code>manifest.json</code>을 사용합니다. 하지만, <code>.webmanifest</code> 확장자는 <a href="https://w3c.github.io/manifest/">W3C manifest 명세</a>에 명시적으로 언급되고 있으므로 이를 그대로 사용하도록 하겠습니다.</p>
+</div>
+
+<p>파일의 내용은 다음과 같습니다.</p>
+
+<pre class="brush: json">{
+ "name": "js13kGames Progressive Web App",
+ "short_name": "js13kPWA",
+ "description": "Progressive Web App that lists games submitted to the A-Frame category in the js13kGames 2017 competition.",
+ "icons": [
+ {
+ "src": "icons/icon-32.png",
+ "sizes": "32x32",
+ "type": "image/png"
+ },
+ // ...
+ {
+ "src": "icons/icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "start_url": "/pwa-examples/js13kpwa/index.html",
+ "display": "fullscreen",
+ "theme_color": "#B12A34",
+ "background_color": "#B12A34"
+}</pre>
+
+<p>항목은 대부분은 스스로를 설명하고있지만, 문서를 분석하고 자세한 내용에 대해 설명해드리겠습니다.</p>
+
+<ul>
+ <li><code>name</code>: 웹 앱의 이름입니다.</li>
+ <li><code>short_name</code>: 홈 화면에 표시할 약식 이름입니다.</li>
+ <li><code>description</code>: 앱이 무엇을 하는지 설명하는 간략한 문장입니다.</li>
+ <li><code>icons</code>: 아이콘들의 정보(URL, 크기, 타입)입니다. 사용자의 기기에 적합한 것을 선택할 수 있도록 여러 개를 추가하시기 바랍니다.</li>
+ <li><code>start_url</code>: 앱이 시작할 때 실행할 초기 문서입니다.</li>
+ <li><code>display</code>: 앱을 표시하는 방식입니다(전체 화면, 독립형(standalone), 최소 UI, 또는 브라우저).</li>
+ <li><code>theme_color</code>: 운영 체제에 의해 사용될 UI를 위한 주요 색상입니다.</li>
+ <li><code>background_color</code>: 스플래시 화면과 설치하는 동안 사용될 배경 색상입니다.</li>
+</ul>
+
+<p>웹 manifest를 위한 최소 요구 사항은 <code>name</code>과 적어도 하나(<code>src</code>, <code>size</code>, <code>type</code>을 포함)의 아이콘입니다. <code>description</code>, <code>short_name</code>, <code>start_url</code>은 권장사항입니다. 위에서 나열한 항목 외 더 많은 항목들이 있습니다. <a href="/ko/docs/Web/Manifest">Web App Manifest 레퍼런스</a>에서 자세한 내용에 대해 확인하시기 바랍니다.</p>
+
+<h2 id="홈_화면에_추가">홈 화면에 추가</h2>
+
+<p>"홈 화면에 추가"(또는 간단히 a2hs)는 모바일 브라우저에서 구현된 기능으로, 앱의 웹 manifest에서 찾은 정보를 사용해 아이콘과 이름 정보로 기기의 홈 화면에서 앱을 나타냅니다. 이는 앱이 위에서 설명한 모든 필수 요구조건을 만족할때만 동작합니다.</p>
+
+<p>사용자가 모바일 브라우저를 지원하는 PWA에 방문할 때, PWA로써 앱 설치를 가능하게하는 배너가 나타나야합니다.</p>
+
+<p><img alt="Add to Home screen popup of js13kPWA." src="https://mdn.mozillademos.org/files/15928/js13kpwa-icon.png" style="border-style: solid; border-width: 1px; display: block; height: 640px; margin: 0px auto; width: 360px;"></p>
+
+<p>사용자가 이 배너를 클릭하면 설치 배너가 나타납니다. 배너는 브라우저에의해 자동으로 생성되며, manifest 파일의 정보(프롬프트에 보여질 이름, 아이콘)를 기반으로합니다.</p>
+
+<p><img alt="Install banner of js13kPWA." src="https://mdn.mozillademos.org/files/15927/js13kpwa-banner.png" style="border-style: solid; border-width: 1px; display: block; height: 640px; margin: 0px auto; width: 360px;"></p>
+
+<p>사용자가 버튼을 클릭하면 앱이 어떻게 표시될지를 보여주며, 사용자에게 정말 앱 추가를 원하는지 선택하도록 하는 마지막 단계가 있습니다.</p>
+
+<p><img alt="Add to Home screen popup of js13kPWA." src="https://mdn.mozillademos.org/files/15926/js13kpwa-add.png" style="border-style: solid; border-width: 1px; display: block; height: 640px; margin: 0px auto; width: 360px;"></p>
+
+<p>확인을 하면 앱이 홈 화면에 설치됩니다.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15834/js13kpwa-installed.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>그 후, 즉시 아이콘을 사용해 이를 실행하여 시작할 수 있습니다. PWA가 가끔(여러분이 사용하는 브라우저나 운영체제에 따라) 아이콘의 우측 하단에 작은 브라우저 이미지가 있어 사용자에게 웹 특성에 대한 정보를 줍니다.</p>
+
+<h3 id="스플래시_화면">스플래시 화면</h3>
+
+<p>일부 브라우저에서, PWA가 실행될 때 보여지는 스플래시 화면 역시 manifest의 정보로부터 생성됩니다.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/15835/js13kpwa-splash.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>아이콘과 테마 그리고 배경 색상은 이 화면을 생성하기 위해 사용됩니다.</p>
+
+<h2 id="요약">요약</h2>
+
+<p>이 문서에서는 웹 manifest와 홈 화면에 추가를 사용해 PWA를 설치가능하게 하는 방법에 대해 배웠습니다.</p>
+
+<p>홈 화면에 추가에 대한 자세한 내용은 <a href="/ko/docs/Web/Apps/Progressive/Add_to_home_screen">홈 화면에 추가 가이드</a>를 읽어보시기 바랍니다. 브라우저 지원은 현재 Android 용 Firefox 58+, 모바일 Chrome 및 Android 웹 뷰 31+, Android 32+ 용 Opera로 제한되어 있지만 가까운 장래에 개선 될 것입니다.</p>
+
+<p>이제 PWA 퍼즐의 마지막 조각(푸시 알림을 통한 재참여)으로 이동해봅시다.</p>
+
+<p>{{PreviousMenuNext("Web/Apps/Progressive/Offline_Service_workers", "Web/Apps/Progressive/Re-engageable_Notifications_Push", "Web/Apps/Progressive")}}</p>
diff --git a/files/ko/web/progressive_web_apps/offline_service_workers/index.html b/files/ko/web/progressive_web_apps/offline_service_workers/index.html
new file mode 100644
index 0000000000..9c9366b12c
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/offline_service_workers/index.html
@@ -0,0 +1,205 @@
+---
+title: Service worker를 사용해 PWA를 오프라인에서 동작하게 만들기
+slug: Web/Progressive_web_apps/Offline_Service_workers
+tags:
+ - PWA
+ - Service Worker
+ - js12kGames
+ - 오프라인
+ - 프로그레시브
+ - 프로그레시브 웹 앱
+translation_of: Web/Progressive_web_apps/Offline_Service_workers
+---
+<div>{{PreviousMenuNext("Web/Apps/Progressive/App_structure", "Web/Apps/Progressive/Installable_PWAs", "Web/Apps/Progressive")}}</div>
+
+<p class="summary">우리는 js13kPWA의 구조와 기본적인 shell을 만들고 실행하는 것에 대해 살펴보았습니다. 이제 Service Worker를 사용해 오프라인 기능을 구현하는 방법에 대해 살펴봅시다. 이 문서에서는 <a href="https://mdn.github.io/pwa-examples/js13kpwa/">js13kPWA 예제</a>(<a href="https://github.com/mdn/pwa-examples/tree/master/js13kpwa">소스 코드도 있습니다</a>)에서 어떻게 사용되었는지와 오프라인 기능을 추가하는 방법을 살펴봅니다.</p>
+
+<h2 id="Service_worker_설명">Service worker 설명</h2>
+
+<p>Service Worker는 브라우저와 네트워크 사이의 가상 프록시입니다. 이는 프론트엔드 개발자들이 수년간 어려움을 겪었던 문제들을 결국 해결하였습니다(특히 웹 사이트의 자원을 적절히 캐싱하는 방법과, 사용자의 기기가 오프라인일 때 이를 사용할 수 있도록 하는 것 등).</p>
+
+<p>이는 페이지의 메인 JavaScript 코드와 독립된 스레드에서 실행되며, DOM 구조에 대한 어떠한 접근도 갖지 않습니다. 이는 전통적인 웹 프로그래밍과 다른 접근법을 소개합니다. API는 비차단형(non-blocking)이며 여러 컨텍스트 사이에 커뮤니케이션을 주고 받을 수 있습니다. 여러분은 Service Worker에 어떤 작업을 전달할 수 있으며, <a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> 기반 접근법을 사용해 결과가 준비될때마다 전달받을 수 있습니다.</p>
+
+<p>Service Worker는 "단지" 오프라인 기능을 제공하는 것 이상으로 알림 처리, 독립된 스레드에서의 복잡한 계산 등 많은 것들을 할 수 있습니다. Service worker는 네트워크 요청을 제어하고 수정하며, 캐시로부터 반환된 커스텀 응답을 제공하거나 응답을 완전히 가공할 수도 있으므로 매우 강력합니다.</p>
+
+<h3 id="보안">보안</h3>
+
+<p>Service Worker는 매우 강력하기때문에 안전한 컨텍스트(HTTPS를 의미)에서만 실행됩니다. 코드를 상용으로 푸시하기전에 먼저 테스트하길 원하신다면, localhost에서 테스트하거나 GitHub Pages를 설정하면 됩니다. 둘 다 HTTPS를 지원합니다.</p>
+
+<h2 id="오프라인_우선">오프라인 우선</h2>
+
+<p>"오프라인 우선" — 또는 "캐시 우선" — 패턴은 사용자에게 컨텐츠를 제공하는 가장 유명한 전략입니다. 리소스가 캐싱되었고 오프라인 사용이 가능한 경우, 서버로부터 다운로드를 시도하기전에 캐시를 먼저 반환합니다. 캐시에 없는 경우, 다음 사용을 위해 다운로드하고 캐싱합니다.</p>
+
+<h2 id="PWA의_점진적">PWA의 "점진적"</h2>
+
+<p>점진적인 향상으로써 제대로 구현이 되면, service worker는 오프라인 지원을 제공하여 API를 지원하는 최신 브라우저를 사용하는 사용자에게 유용하지만, 구형 브라우저를 사용하는 사람들에게도 사이트 사용에 아무런 문제가 없습니다.</p>
+
+<h2 id="js13kPWA_앱의_Service_worker">js13kPWA 앱의 Service worker</h2>
+
+<p>이론은 충분합니다. 소스 코드를 봅시다!</p>
+
+<h3 id="Service_Worker_등록">Service Worker 등록</h3>
+
+<p>app.js 파일에서 새로운 Service Worker를 등록하는 코드를 살펴보는 것으로 시작할 것입니다.</p>
+
+<pre class="brush: js">if('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('/pwa-examples/js13kpwa/sw.js');
+};</pre>
+
+<p>브라우저에서 Service worker API를 지원한다면, {{domxref("ServiceWorkerContainer.register()")}} 메소드를 사용해 사이트에대해 등록됩니다. 컨텐츠는 sw.js 파일안에 있으며 등록이 성공한 후에 실행됩니다. 이것이 app.js 파일안에 있는 Service Worker 코드의 유일한 부분입니다. Service Worker에 대한 다른 모든 것들은 sw.js 파일에 작성되어 있습니다.</p>
+
+<h3 id="Service_Worker의_수명_주기">Service Worker의 수명 주기</h3>
+
+<p>등록이 완료되면, sw.js 파일은 자동으로 다운로드된 후 설치되고 마지막으로 활성화됩니다.</p>
+
+<h4 id="설치">설치</h4>
+
+<p>API는 우리가 관심있는 주요 이벤트에 대한 이벤트 리스너를 추가할 수 있게 해줍니다. 첫 번째 것은 <code>install</code> 이벤트 입니다.</p>
+
+<pre class="brush: js">self.addEventListener('install', function(e) {
+ console.log('[Service Worker] Install');
+});</pre>
+
+<p><code>install</code> 리스너에서 캐시를 초기화하고 오프라인 사용을 위한 파일들을 추가할 수 있습니다. js13kPWA 앱도 정확히 그런 작업을 합니다.</p>
+
+<p>먼저, 캐시 이름을 저장할 변수를 생성하고, app shell 파일들을 하나의 배열에 나열합니다.</p>
+
+<pre class="brush: js">var cacheName = 'js13kPWA-v1';
+var appShellFiles = [
+ '/pwa-examples/js13kpwa/',
+ '/pwa-examples/js13kpwa/index.html',
+ '/pwa-examples/js13kpwa/app.js',
+ '/pwa-examples/js13kpwa/style.css',
+ '/pwa-examples/js13kpwa/fonts/graduate.eot',
+ '/pwa-examples/js13kpwa/fonts/graduate.ttf',
+ '/pwa-examples/js13kpwa/fonts/graduate.woff',
+ '/pwa-examples/js13kpwa/favicon.ico',
+ '/pwa-examples/js13kpwa/img/js13kgames.png',
+ '/pwa-examples/js13kpwa/img/bg.png',
+ '/pwa-examples/js13kpwa/icons/icon-32.png',
+ '/pwa-examples/js13kpwa/icons/icon-64.png',
+ '/pwa-examples/js13kpwa/icons/icon-96.png',
+ '/pwa-examples/js13kpwa/icons/icon-128.png',
+ '/pwa-examples/js13kpwa/icons/icon-168.png',
+ '/pwa-examples/js13kpwa/icons/icon-192.png',
+ '/pwa-examples/js13kpwa/icons/icon-256.png',
+ '/pwa-examples/js13kpwa/icons/icon-512.png'
+];</pre>
+
+<p>다음으로, data/games.js 파일의 컨텐츠와 함께 로딩될 이미지 링크가 두 번째 배열에 생성됩니다. 그런 다음, {{jsxref("Array.prototype.concat()")}} 함수를 사용해 두 배열을 병합합니다.</p>
+
+<pre class="brush: js">var gamesImages = [];
+for(var i=0; i&lt;games.length; i++) {
+ gamesImages.push('data/img/'+games[i].slug+'.jpg');
+}
+var contentToCache = appShellFiles.concat(gamesImages);</pre>
+
+<p>그러면 <code>install</code> 이벤트 자체를 관리할 수 있게 됩니다.</p>
+
+<pre class="brush: js">self.addEventListener('install', function(e) {
+ console.log('[Service Worker] Install');
+ e.waitUntil(
+ caches.open(cacheName).then(function(cache) {
+ console.log('[Service Worker] Caching all: app shell and content');
+ return cache.addAll(contentToCache);
+ })
+ );
+});</pre>
+
+<p>여기서 두 가지에 대한 설명이 필요합니다: {{domxref("ExtendableEvent.waitUntil")}}이 무엇을 하는지, 그리고 {{domxref("caches","Caches")}} 객체가 무엇인지.</p>
+
+<p>Service worker는 <code>waitUntil</code> 안의 코드가 실행되기전까지 설치되지 않습니다. 이는 promise를 반환합니다. 설치에 약간의 시간이 걸릴 수 있으므로 완료될 때까지 기다려야하기 때문에 이 접근법이 필요합니다.</p>
+
+<p><code>Caches</code> 는 데이터를 저장할 수 있도록 주어진 Service Worker의 범위 내에서 사용할 수 있는 특별한 객체입니다. 웹 저장소는 동기적이므로 <a href="/ko/docs/Web/API/Web_Storage_API">웹 저장소</a>로의 저장은 동작하지 않을 것입니다. Service Worker는 Cache API를 대신 사용합니다.</p>
+
+<p>여기에 주어진 이름을 갖는 캐시를 열고 캐시에서 사용할 앱의 모든 파일을 추가하여 다음 로딩에서 사용할 수 있게됩니다(요청 URL로 식별됨).</p>
+
+<h4 id="활성화">활성화</h4>
+
+<p><code>install</code>과 같은 방식으로 사용되는 <code>activate</code> 이벤트도 있습니다. 이 이벤트는 일반적으로 더 이상 필요하지 않은 파일을 제거하고 앱이 끝난 후 정리하는데 사용됩니다. 우리 앱에서는 사용하지 않으므로 생략하겠습니다.</p>
+
+<h3 id="패치_응답">패치 응답</h3>
+
+<p>처리를 위한 <code>fetch</code> 이벤트도 있습니다. 이는 앱으로부터 HTTP 요청이 출발할 때 마다 발생합니다. 이는 요청을 가로채 커스텀 응답으로 응답할 수 있어 매우 유용합니다.<br>
+ 다음은 간단한 사용 예시입니다.</p>
+
+<pre class="brush: js">self.addEventListener('fetch', function(e) {
+ console.log('[Service Worker] Fetched resource '+e.request.url);
+});</pre>
+
+<p>응답은 파일 요청, 캐시된 사본, 또는 특정 작업을 수행하는 JavaScript 코드 조각 등 원하는 어떠한것도 될 수 있습니다. 가능성은 무한합니다.</p>
+
+<p>예제 앱에서 우리는 리소스가 실제로 캐시에 있는한 네트워크 대신 캐시로부터 컨텐츠를 제공합니다. 앱이 온라인이든 오프라인이든간에 이렇게 수행합니다. 파일이 캐시에 없을 경우, 이를 제공하기 전에 먼저 캐시에 추가합니다.</p>
+
+<pre class="brush: js">self.addEventListener('fetch', function(e) {
+ e.respondWith(
+ caches.match(e.request).then(function(r) {
+ console.log('[Service Worker] Fetching resource: '+e.request.url);
+ return r || fetch(e.request).then(function(response) {
+ return caches.open(cacheName).then(function(cache) {
+ console.log('[Service Worker] Caching new resource: '+e.request.url);
+ cache.put(e.request, response.clone());
+ return response;
+ });
+ });
+ })
+ );
+});</pre>
+
+<p>여기에서 우리는 리소스를 찾고 존재할 경우 응답을 반환하는 함수로 패치 이벤트에 응답합니다. 응답이 없을 경우 다른 패치 요청을 사용해 네트워크로부터 패치한 후 캐시에 응답을 저장하여 다음 요청에서 사용할 수 있도록 합니다.</p>
+
+<p>{{domxref("FetchEvent.respondWith")}} 메소드가 제어를 대신합니다. 이는 앱과 네트워크 사이의 프록시 서버로서 기능하는 부분입니다. 이는 Service Worker에 의해 준비되고, 캐시로부터 가져와, 필요한 경우 수정하여 모든 요청에 대해 우리가 원하는 응답을 할 수 있게 해줍니다.</p>
+
+<p>이게 다입니다! 우리 앱은 설치에서 자원을 캐싱하고 캐시로부터 이를 패치하여 전달함으로 사용자가 오프라인인 경우에도 동작합니다. 새로운 컨텐츠가 추가되면 역시 캐싱합니다.</p>
+
+<h2 id="업데이트">업데이트</h2>
+
+<p>다뤄야 할 하나가 더 남았습니다. 새 자원을 포함하는 앱의 새 버전이 사용가능할 때 어떻게 Service Worker를 업그레이드하나요? 캐시 이름안의 버전 넘버가 핵심입니다.</p>
+
+<pre class="brush: js">var cacheName = 'js13kPWA-v1';</pre>
+
+<p>v2로 업데이트했을 때, 새 캐시에 모든 파일(새 파일들을 포함)을 추가할 수 있습니다.</p>
+
+<pre class="brush: js">contentToCache.push('/pwa-examples/js13kpwa/icons/icon-32.png');
+
+// ...
+
+self.addEventListener('install', function(e) {
+ e.waitUntil(
+ caches.open('js13kPWA-v2').then(function(cache) {
+ return cache.addAll(contentToCache);
+ })
+ );
+});</pre>
+
+<p>새 service worker가 백그라운드에서 설치되고 이전의 것(v1)이 사용하는 페이지가 없을 때까지 올바르게 동작합니다. 새로운 Service Worker는 그 후 활성화되고 이전의 것으로부터 페이지의 관리를 넘겨받습니다.</p>
+
+<h2 id="캐시_지우기">캐시 지우기</h2>
+
+<p>생략했던 <code>activate</code> 이벤트를 기억하시나요? 더 이상 필요하지 않은 오래된 캐시를 지우는데 사용할 수 있습니다.</p>
+
+<pre class="brush: js">self.addEventListener('activate', function(e) {
+ e.waitUntil(
+ caches.keys().then(function(keyList) {
+ return Promise.all(keyList.map(function(key) {
+ if(cacheName.indexOf(key) === -1) {
+ return caches.delete(key);
+ }
+ }));
+ })
+ );
+});</pre>
+
+<p>이는 캐시에 우리가 필요한 파일만 있도록 보장하여, 불필요한 파일을 남기지 않게 됩니다. <a href="/ko/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria">브라우저에서 사용가능한 캐시 공간은 제한적</a>이므로 이를 지우는 것은 우리 스스로를 위한 좋은 아이디어입니다.</p>
+
+<h2 id="다른_유즈_케이스">다른 유즈 케이스</h2>
+
+<p>캐시로부터 파일들을 전달하는 것은 Service Worker가 제공하는 유일한 기능이 아닙니다. 복잡한 계산을 해야하는 경우, 메인 스레드로부터 이를 분리하여 worker에서 수행하도록 하고 결과가 나오는대로 받을 수 있습니다. 성능 측면에서 볼 때, 지금 당장 필요하지는 않지만 가까운 미래에 필요할 수도 있는 리소스를 미리 패치하여 실제로 그 리소스들을 필요로할 때 앱이 더 빨라집니다.</p>
+
+<h2 id="요약">요약</h2>
+
+<p>이 문서에서는 service worker를 사용해 PWA가 오프라인에서 동작하도록 만드는 방법에 대해 간략히 살펴보았습니다. <a href="/ko/docs/Web/API/Service_Worker_API">Service Worker API</a>의 개념과 사용 방법에 대한 더 자세한 내용을 배우시려면 우리의 추가 문서를 확인하시기 바랍니다.</p>
+
+<p>Service Worker는 <a href="/en-US/docs/Web/API/Push_API">푸시 알림</a>을 처리할 때에도 사용됩니다. 이는 이어지는 문서에서 설명할 것입니다.</p>
+
+<p>{{PreviousMenuNext("Web/Apps/Progressive/App_structure", "Web/Apps/Progressive/Installable_PWAs", "Web/Apps/Progressive")}}</p>
diff --git a/files/ko/web/progressive_web_apps/re-engageable_notifications_push/index.html b/files/ko/web/progressive_web_apps/re-engageable_notifications_push/index.html
new file mode 100644
index 0000000000..83a5e4ff4e
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/re-engageable_notifications_push/index.html
@@ -0,0 +1,253 @@
+---
+title: 알림과 푸시를 사용해 PWA를 재참여(re-engageable)가능하게 만드는 방법
+slug: Web/Progressive_web_apps/Re-engageable_Notifications_Push
+tags:
+ - PWA
+ - js13kGames
+ - 알림
+ - 푸시
+ - 프로그레시브
+ - 프로그레시브 웹 앱
+translation_of: Web/Progressive_web_apps/Re-engageable_Notifications_Push
+---
+<div>{{PreviousMenu("Web/Apps/Progressive/Installable_PWAs", "Web/Apps/Progressive")}}</div>
+
+<p class="summary">앱을 오프라인에서 동작하도록 컨텐츠를 캐싱하는 능력은 훌륭한 기능입니다. 사용자가 홈 화면에 웹 앱을 설치하도록 허용하는 것은 더 좋습니다. 하지만, 사용자의 동작에 의존하는 대신 푸시 메시지와 알림을 사용해 새로운 컨텐츠가 있을때 이를 전달하여 사용자를 자동으로 다시 참여하도록 할 수 있습니다.</p>
+
+<h2 id="두_개의_API_하나의_목적">두 개의 API, 하나의 목적</h2>
+
+<p><a href="/ko/docs/Web/API/Push_API">Push API</a>와 <a href="/ko/docs/Web/API/Notifications_API">Notifications API</a>는 두 개의 독립된 API이지만, 여러분의 앱에 재참여 기능을 제공하려고 할 때 함께 잘 동작합니다. Push는 클라이언트 사이드의 관여 없이 서버로부터 앱으로 새로운 컨텐츠를 전달하는데 사용되며, 이 작업은 앱의 service worker에 의해 처리됩니다. Notification은 service worker에 의해 사용자에게 새로운 정보를 보여주거나 무언가 업데이트 되었음을 알리는데 사용됩니다.</p>
+
+<p>두 API는 service worker와 마찬가지로 브라우저 창의 바깥에서 동작하기때문에 앱의 페이지를 보고 있지 않거나 심지어 종료되었을 때도 업데이트 푸시를 보내거나 알림을 보여줄 수 있습니다.</p>
+
+<h2 id="Notifications">Notifications</h2>
+
+<p>알림으로 시작해봅시다. 알림은 푸시 없이도 동작하지만, 푸시와 결합했을 때 매우 유용합니다. 먼저 독립적으로 보도록하겠습니다.</p>
+
+<h3 id="권한_요청">권한 요청</h3>
+
+<p>알림을 보여주려면 먼저 권한을 요청해야 합니다. 즉시 알림을 보여주는대신 사용자가 버튼을 클릭하여 팝업을 요청할 때 요청 팝업을 보여주는 것이 좋은 사용법입니다.</p>
+
+<pre class="brush: js">var button = document.getElementById("notifications");
+button.addEventListener('click', function(e) {
+ Notification.requestPermission().then(function(result) {
+ if(result === 'granted') {
+ randomNotification();
+ }
+ });
+});</pre>
+
+<p>팝업은 운영체제가 가진 알림 서비스를 사용해 보여집니다.</p>
+
+<p><img alt="Notification of js13kPWA." src="https://mdn.mozillademos.org/files/15930/js13kpwa-notification.png" style="display: block; height: 640px; margin: 0px auto; width: 360px;"></p>
+
+<p>사용자가 알림 수신을 확인하면 앱이 알림을 보여줄 수 있습니다. 사용자는 기본, 승인 또는 거절을 선택할 수 있습니다. 기본 옵션은 사용자가 선택할 수 없을 때 사용되며, 다른 두 옵션은 사용자가 예 또는 아니오를 선택했을 때 사용됩니다.</p>
+
+<p>승인이 되면, 권한은 알림과 푸시 모두에 대해 동작합니다.</p>
+
+<h3 id="알림_생성">알림 생성</h3>
+
+<p>예시 앱은 사용가능한 데이터를 알림으로 생성합니다. 게임은 무작위로 선택되며, 선택된 것은 게임의 이름을 title로, 제작자를 body로, 이미지를 아이콘으로 보여주는 컨텐츠를 알림으로 제공합니다.</p>
+
+<pre class="brush: js">function randomNotification() {
+ var randomItem = Math.floor(Math.random()*games.length);
+ var notifTitle = games[randomItem].name;
+ var notifBody = 'Created by '+games[randomItem].author+'.';
+ var notifImg = 'data/img/'+games[randomItem].slug+'.jpg';
+ var options = {
+ body: notifBody,
+ icon: notifImg
+ }
+ var notif = new Notification(notifTitle, options);
+ setTimeout(randomNotification, 30000);
+}</pre>
+
+<p>새로운 무작위 알림은 사용자가 너무 귀찮아 비활성화 하기 전까지는 매 30초마다 생성됩니다. (실제 앱에서는 알림이 너무 잦아선 안되며 더 유용해야합니다.) Notifications API의 이점은 운영체제의 알림 기능을 사용한다는 것입니다. 이는 사용자가 웹 앱을 보고있지않더라도 알림을 보여줄 수 있으며, 알림이 네이티브 앱에서 표시하는 것과 유사하다는 것을 의미합니다.</p>
+
+<h2 id="Push">Push</h2>
+
+<p>푸시는 알림보다 더 복잡합니다. 우리는 앱으로 데이터를 다시 전송해줄 서버를 구독해야합니다. 앱의 Service Worker는 푸시 서버로부터 데이터를 수신하며 알림 시스템 또는 원하는 경우 다른 메커니즘을 사용해 이를 보여줄 수 있습니다.</p>
+
+<p>이 기술은 여전히 아주 초기 단계에 있습니다. 몇몇 동작하는 예제들은 Google Cloude Messaging 플랫폼을 사용하지만, <a href="https://blog.mozilla.org/services/2016/08/23/sending-vapid-identified-webpush-notifications-via-mozillas-push-service/">VAPID</a>(자발적 어플리케이션 식별, Voluntary Application Identification)를 지원하도록 재작성되어 앱을 위한 부가적인 보안 계층을 제공합니다. <a href="https://serviceworke.rs/push-payload.html">Service Workers Cookbook examples</a>를 확인하고, <a href="https://firebase.google.com/">Firebase</a>를 사용하는 푸시 메시징 서버를 설정하거나, 여러분만의 서버(예제에서는 Node.js를 사용)를 구축해보시기 바랍니다.</p>
+
+<p>앞서 언급듯이, 푸시 알림을 수신하려면 service worker가 있어야 합니다. 이를 위한 기본적인 내용은 <a class="new" href="https://developer.mozilla.org/ko/docs/Web/Apps/Progressive/Offline_Service_workers" rel="nofollow">Service worker를 사용해 PWA를 오프라인에서 동작하게 만들기</a> 문서에서 이미 설명했습니다. Service worker 안에서 푸시 서비스 구독 메커니즘이 생성됩니다.</p>
+
+<pre class="brush: js">registration.pushManager.getSubscription() .then( /* ... */ );</pre>
+
+<p>사용자가 구독을 하기 시작하면, 서버로부터 푸시 알림을 받을 수 있습니다.</p>
+
+<p>서버사이드에서는 보안적인 이유로 전체 프로세스를 공개키와 비공개키를 사용하여 암호화해야 합니다. 모든 사람들이 앱을 사용하여 안전하지 않은 푸시 메시지를 보내도록 허용하는 것은 끔찍할 것입니다. 서버는 사용자가 구독했을 때 받은 모든 정보를 저장하므로 이 후 필요할 때 메시지를 보낼 수 있습니다.</p>
+
+<p>푸시 메시지를 수신하려면, Service Worker 파일에서 {{event("push")}}이벤트를 사용하면됩니다.</p>
+
+<pre class="brush: js">self.addEventListener('push', function(e) { /* ... */ });</pre>
+
+<p>데이터는 반환되어 알림으로 사용자에게 즉시 보여집니다. 예를 들어, 이는 사용자에게 무언가를 다시 알려주거나, 앱에서 사용 가능한 새로운 컨텐츠에 대해 알려주는데 사용할 수 있습니다.</p>
+
+<h3 id="푸시_예제">푸시 예제</h3>
+
+<p>푸시는 동작을 위해 서버 파트가 필요하므로, 정적인 파일의 호스팅만 제공하는 GitHub Pages에 호스팅된 js13kPWA 예제를 포함 할 수 없습니다. 이는 <a href="https://serviceworke.rs/">Service Worker Cookbook</a>에 모두 설명되어 있습니다. <a href="https://serviceworke.rs/push-payload.html">Push Payload 데모</a>를 확인하시기 바랍니다.</p>
+
+<p>이 데모는 세 파일을 포함하고 있습니다.</p>
+
+<ul>
+ <li><a href="https://github.com/mozilla/serviceworker-cookbook/blob/master/push-payload/index.js">index.js</a>, 앱의 소스 코드를 포함합니다</li>
+ <li><a href="https://github.com/mozilla/serviceworker-cookbook/blob/master/push-payload/server.js">server.js</a>, 서버 파트(Node.js로 작성됨)를 포함합니다</li>
+ <li><a href="https://github.com/mozilla/serviceworker-cookbook/blob/master/push-payload/service-worker.js">service-worker.js</a>, Service Worker 관련 코드를 포함합니다.</li>
+</ul>
+
+<p>이 모든 것들에 대해 확인해봅시다</p>
+
+<h4 id="index.js">index.js</h4>
+
+<p><code>index.js</code> 파일은 service worker를 등록하는 것으로 시작합니다.</p>
+
+<pre class="brush: js">navigator.serviceWorker.register('service-worker.js')
+.then(function(registration) {
+ return registration.pushManager.getSubscription()
+ .then(async function(subscription) {
+ // registration part
+ });
+})
+.then(function(subscription) {
+ // subscription part
+});</pre>
+
+<p><a href="https://mdn.github.io/pwa-examples/js13kpwa/">js13kPWA 데모</a>에서 봤던 service worker보다 조금 더 복잡합니다. 이 특정 케이스에서는, 등록한 후에 등록 객체를 사용해 구독하며, 그 후 구독 객체를 사용해 전체 프로세스를 완료합니다.</p>
+
+<p>등록 파트의 코드는 다음과 같습니다.</p>
+
+<pre class="brush: js">if(subscription) {
+ return subscription;
+}</pre>
+
+<p>사용자가 이미 구독했을경우, 구독 객체를 반환하며 구독 파트로 이동합니다. 그렇지 않을 경우 새로운 구독을 초기화합니다.</p>
+
+<pre class="brush: js">const response = await fetch('./vapidPublicKey');
+const vapidPublicKey = await response.text();
+const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);</pre>
+
+<p>앱은 서버의 공개 키를 패치하고 응답을 텍스트로 변환합니다. 그 후 Uint8Array(Chrome 지원을 위해)로 변환이 필요합니다. VAPID 키에 대한 자세한 내용은 <a href="https://blog.mozilla.org/services/2016/08/23/sending-vapid-identified-webpush-notifications-via-mozillas-push-service/">Sending VAPID identified WebPush Notifications via Mozilla’s Push Service</a> 블로그 포스트를 읽어보시기 바랍니다.</p>
+
+<p>앱은 이제 새로운 사용자를 구독하기 위해 {{domxref("PushManager")}}를 사용합니다. 두 옵션이 {{domxref("PushManager.subscribe()")}} 메소드로 전달됩니다. 첫 번째는 <code>userVisibleOnly: true</code>이며 사용자에게 전송되는 모든 알림이 보여진다는 것을 의미하며, 두 번째 것은 <code>applicationServerKey</code>이며 성공적으로 획득하고 변환된 VAPID 키를 포함합니다.</p>
+
+<pre class="brush: js">return registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: convertedVapidKey
+});</pre>
+
+<p>이제 구독 파트로 이동해봅시다. 앱은 Fetch를 사용해 먼저 서버로 JSON으로 된 구독 상세 정보를 전송합니다.</p>
+
+<pre class="brush: js">fetch('./register', {
+ method: 'post',
+ headers: {
+ 'Content-type': 'application/json'
+ },
+ body: JSON.stringify({
+ subscription: subscription
+ }),
+});</pre>
+
+<p>그 다음 <em>구독</em> 버튼의 {{domxref("onclick","GlobalEventHandlers.onclick")}}이 정의됩니다.</p>
+
+<pre class="brush: js">document.getElementById('doIt').onclick = function() {
+ const payload = document.getElementById('notification-payload').value;
+ const delay = document.getElementById('notification-delay').value;
+ const ttl = document.getElementById('notification-ttl').value;
+
+ fetch('./sendNotification', {
+ method: 'post',
+ headers: {
+ 'Content-type': 'application/json'
+ },
+ body: JSON.stringify({
+ subscription: subscription,
+ payload: payload,
+ delay: delay,
+ ttl: ttl,
+ }),
+ });
+};</pre>
+
+<p>버튼이 클릭되면, <code>fetch</code>는 제공된 파라미터를 사용해 서버로 알림을 전송합니다. <code>payload</code>는 알림에 표시될 텍스트이고, <code>delay</code>는 알림이 보여질 때 까지의 지연 시간을 정의하며, <code>ttl</code>은 지정된 시간(초 단위로도 정의됨)동안 서버에서 알림을 사용할 수 있게하는 time-to-live 설정입니다.</p>
+
+<p>이제, 다음 JavaScript 파일로 넘어갑니다.</p>
+
+<h4 id="server.js">server.js</h4>
+
+<p>서버 파트는 Node.js로 작성되었으며 어딘가 적합한 곳에 호스팅되어야 합니다. 이는 완전히 다른 문서의 주제입니다. 여기에서는 높은 수준의 개요만 제공합니다.</p>
+
+<p><a href="https://www.npmjs.com/package/web-push">web-push 모듈</a>은 VAPID 키를 설정하기 위해 사용되며, 존재하지 않을 경우 선택적으로 생성합니다.</p>
+
+<pre class="brush: js">const webPush = require('web-push');
+
+if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
+ console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
+ "environment variables. You can use the following ones:");
+ console.log(webPush.generateVAPIDKeys());
+ return;
+}
+
+webPush.setVapidDetails(
+ 'https://serviceworke.rs/',
+ process.env.VAPID_PUBLIC_KEY,
+ process.env.VAPID_PRIVATE_KEY
+);
+</pre>
+
+<p>그 다음, 모듈은 앱이 처리해야할 모든 라우트(VAPID 공개 키 얻기, 등록 후 알림 보내기)를 정의하고 내보냅니다. <code>index.js</code> 파일에서 사용중인 <code>payload</code>, <code>delay</code>, <code>ttl</code> 변수를 볼 수 있습니다.</p>
+
+<pre class="brush: js">module.exports = function(app, route) {
+ app.get(route + 'vapidPublicKey', function(req, res) {
+ res.send(process.env.VAPID_PUBLIC_KEY);
+ });
+
+ app.post(route + 'register', function(req, res) {
+
+ res.sendStatus(201);
+ });
+
+ app.post(route + 'sendNotification', function(req, res) {
+ const subscription = req.body.subscription;
+ const payload = req.body.payload;
+ const options = {
+ TTL: req.body.ttl
+ };
+
+ setTimeout(function() {
+ webPush.sendNotification(subscription, payload, options)
+ .then(function() {
+ res.sendStatus(201);
+ })
+ .catch(function(error) {
+ console.log(error);
+ res.sendStatus(500);
+ });
+ }, req.body.delay * 1000);
+ });
+};</pre>
+
+<h4 id="service-worker.js">service-worker.js</h4>
+
+<p>마지막으로 살펴볼 파일은 service worker입니다.</p>
+
+<pre class="brush: js">self.addEventListener('push', function(event) {
+ const payload = event.data ? event.data.text() : 'no payload';
+ event.waitUntil(
+ self.registration.showNotification('ServiceWorker Cookbook', {
+ body: payload,
+ })
+ );
+});</pre>
+
+<p>이 모든 것은 {{event("push")}} 이벤트에 리스너를 추가하고, 데이터로부터 받은 텍스트로 구성된 payload 변수를 생성한 후(또는 데이터가 비어있을 경우 사용할 문자열을 생성), 사용자에게 보여줄 알림을 보여줄 때까지 기다립니다.</p>
+
+<p><a href="https://serviceworke.rs/">Service Worker Cookbook</a> 예제의 나머지 부분의 동작 방법도 자유롭게 살펴보시기 바랍니다. <a href="https://github.com/mozilla/serviceworker-cookbook/">전체 소스 코드는 GitHub에서 사용 가능합니다</a>. 일반적인 사용과 웹 푸시, 캐싱 전략, 성능, 오프라인 동작 등을 보여주는 동작 예제가 많이 있습니다.</p>
+
+<h2 id="결론">결론</h2>
+
+<p>이것이 튜토리얼 시리즈의 전부입니다. <a href="https://github.com/mdn/pwa-examples/tree/master/js13kpwa">js13kPWA 예제 앱의 소스 코드</a>를 살펴봤으며 <a href="/ko/docs/Web/Apps/Progressive/Introduction">소개</a>, <a href="/ko/docs/Web/Apps/Progressive/App_structure">PWA 구조</a>, <a href="/ko/docs/Web/Apps/Progressive/Offline_Service_workers">Service Worker를 사용한 오프라인 기능</a>, <a href="https://developer.mozilla.org/ko/docs/Web/Apps/Progressive/Installable_PWAs">설치 가능한 PWA</a> 그리고 마지막으로 알림을 포함해 프로그레시브 웹 앱의 기능의 사용에 대해 배웠습니다. 또한 <a href="https://serviceworke.rs/">Service Worker Cookbook</a>의 도움으로 푸시에 대해서도 설명했습니다.</p>
+
+<p>코드를 실험해보시고, 여러분의 앱을 PWA 기능으로 개선하거나, 완전히 새로운 무언가를 구축해 보세요. PWA는 일반 웹 앱에 비해 큰 이점을 제공합니다.</p>
+
+<p>{{PreviousMenu("Web/Apps/Progressive/Installable_PWAs", "Web/Apps/Progressive")}}</p>
diff --git a/files/ko/web/progressive_web_apps/소개/index.html b/files/ko/web/progressive_web_apps/소개/index.html
new file mode 100644
index 0000000000..e253c96ce9
--- /dev/null
+++ b/files/ko/web/progressive_web_apps/소개/index.html
@@ -0,0 +1,92 @@
+---
+title: 프로그레시브 웹 앱 소개
+slug: Web/Progressive_web_apps/소개
+tags:
+ - PWA
+ - js13kGames
+ - 소개
+ - 프로그레시브
+ - 프로그레시브 웹 앱
+translation_of: Web/Progressive_web_apps/Introduction
+---
+<div>{{NextMenu("Web/Apps/Progressive/App_structure", "Web/Apps/Progressive")}}</div>
+
+<p class="summary">이 문서는 프로그레시브 웹 앱(PWA)의 소개입니다. PWA가 무엇이고 일반 웹 앱에 어떤 이점을 가져다주는지 설명합니다.</p>
+
+<h2 id="프로그레시브_웹_앱이_무엇인가요">프로그레시브 웹 앱이 무엇인가요?</h2>
+
+<p>PWA는 웹과 네이티브 앱의 기능 모두의 이점을 갖도록 수 많은 특정 기술과 표준 패턴을 사용해 개발된 웹 앱입니다.</p>
+
+<p>예를 들어, 웹 앱은 발견이 쉽습니다 — 어플리케이션을 설치하는 것보다 웹사이트에 방문하는 것이 훨씬 쉽고 빠르며, 링크로 웹 앱을 공유할수도 있습니다.</p>
+
+<p>반면에, 네이티브 앱은 운영체제와 보다 잘 통합되므로 더 부드러운 사용자 경험을 제공할 수 있습니다. 네이티브 앱은 설치할 수 있으므로 오프라인에서 동작하며, 사용자는 홈 화면의 아이콘을 탭하여 브라우저를 사용하여 이동하는 것보다 선호하는 앱에 더 쉽게 접근할 수 있습니다.</p>
+
+<p>PWA는 이들과 동일한 이점을 즐길 수 있는 웹 앱을 생성하는 능력을 제공합니다.</p>
+
+<p>완전히 새로운 개념은 아닙니다 — 이런 아이디어는 과거에 다양한 접근 방법으로 웹 플랫폼상에서 여러번 재검토되었습니다. 점진적인 향상과 반응형 디자인은 이미 우리가 모바일 친화적인 웹사이트를 구축할 수 있게 해주고 있습니다. 오프라인에서 동작하는 것과 앱을 설치하는 것은 몇 년 전 Firefox OS 생태계에서 이미 가능했었습니다.</p>
+
+<p>하지만, PWA는 웹을 훌륭하게 만드는 이미 존재하는 어떤 기능도 제거하지 않은 상태로 이 모든 것 그리고 그 이상을 제공합니다.</p>
+
+<h2 id="앱을_PWA로_만드는_것은_무엇인가요">앱을 PWA로 만드는 것은 무엇인가요?</h2>
+
+<p>위에서 암시했듯이, PWA는 하나의 기술로 생성된 것이 아닙니다. 이는 일부 특정 패턴, API 및 다른 기능들을 포함하는 웹 앱을 구축하는 하나의 새로운 철학을 나타냅니다. 첫눈에 웹 앱이 PWA인이 아닌지 구분하기는 쉽지 않습니다. 앱이 특정 요구 사항을 만족하거나 다음 기능들이 구현되었을 때 PWA라고 볼 수 있습니다: 오프라인에서 동작, 설치가 가능, 쉬운 동기화, 푸시 알림, 등.</p>
+
+<p>게다가, 앱의 완성도를 퍼센트로 측정하는 도구들도 있습니다. (<a href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a>가 현재 가장 유명합니다.) 다양한 기술적 이점을 구현함으로써, 앱을 더 점진적이게 만들 수 있고, 더 높은 Lighthouse 점수를 받을 수 있습니다. 하지만 이는 대략적인 지표일뿐입니다.</p>
+
+<p>다음은 웹 앱을 PWA로 식별되기 위해 확인해야 하는 몇 가지 핵심 원칙입니다.</p>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Discoverable">발견 가능</a>, 따라서 컨텐츠를 검색 엔진을 통해 찾을 수 있습니다.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Installable">설치 가능</a>, 따라서 기기의 홈 화면에서 사용할 수 있습니다.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Linkable">연결 가능</a>, 따라서 간단하게 URL을 전송해 공유할 수 있습니다.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Network_independent">네트워크 독립적</a>, 따라서 오프라인이나 불안한 네트워크 연결에서 동작합니다.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Progressive">점진적</a>, 따라서 최신 브라우저의 모든 기능은 사용할 수 없지만 이전 브라우저의 기본 기능은 여전히 사용할 수 있습니다.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Re-engageable">재 참여 가능(Re-engageable)</a>, 따라서 새 컨텐츠가 사용 가능할 때마다 알림을 보낼 수 있습니다.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Responsive">반응형</a>, 따라서 모든 기기의 화면이나 브라우저에서 사용할 수 있습니다 — 모바일 폰, 태블릿, 노트북, TV, 냉장고, 등.</li>
+ <li><a href="https://developer.mozilla.org/ko/Apps/Progressive/Advantages#Safe">안전</a>, 따라서 여러분과 앱 사이의 연결이 여러분의 민감한 데이터에 접근하려는 모든 제3자로부터 안전합니다.</li>
+</ul>
+
+<h3 id="이_모든_것들을_할만한_가치가_있나요">이 모든 것들을 할만한 가치가 있나요?</h3>
+
+<p>물론입니다! 비교적 적은 노력으로 PWA 핵심 기능들을 구현할 수 있으며, 그 이점은 거대합니다. 예를 들면:</p>
+
+<ul>
+ <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> 를 사용한 캐싱 덕분에 앱을 설치한 후에 로딩 시간이 줄어들어 소중한 데이터와 시간을 절약.</li>
+ <li>앱 업데이트가 있을 때 변경된 컨텐츠만 업데이트 할 수 있음. 반면, 네이티브 앱의 경우, 아주 작은 수정에도 사용자가 어플리케이션 전체를 다시 다운로드하도록 강제함.</li>
+ <li>네이티브 플랫폼에 보다 통합된 외관과 느낌 — 홈 화면의 앱 아이콘, 전체 화면으로 실행되는 앱, 등.</li>
+ <li>시스템 알림 및 푸시 메시지를 통한 사용자의 재 참여. 참여율이 높은 사용자와 더 나은 전환율을 이끌어 냄.</li>
+</ul>
+
+<p>PWA 라우트를 시도하고 네이티브 앱 보다 더 향상된 웹 사이트 경험을 선택하여 측정 가능한 의미있는 이득을 본 회사들의 성공 스토리가 많습니다. <a href="https://www.pwastats.com/">PWA Stats</a> 웹 사이트는 이러한 이점을 나타내는 많은 사례 연구들을 공유합니다.</p>
+
+<p>가장 잘 알려진 성공 스토리는 아마 <a href="https://stories.flipkart.com/flipkart-lite/">Flipkart Lite</a> 일 것입니다 — 2015년에 프로그레시브 웹 앱으로 사이트를 재구축해 전환율을 70% 상승시킨 인도의 가장 큰 전자 상거래 사이트입니다. <a href="https://m.aliexpress.com/">AliExpress</a> PWA 역시 새로운 사용자에 대한 전환율을 104% 상승시키는 것으로 웹이나 네이티브 앱보다 훨씬 더 나은 결과를 보였습니다. 이윤 증가 및 PWA로 전환을 위해 상대적으로 적은 양의 작업을 놓고 봤을 때, 이점은 분명합니다.</p>
+
+<p>더 많은 예제는 <a href="https://pwa.rocks/">pwa.rocks</a> 의 목록에서 확인하시기 바랍니다. <a href="https://hnpwa.com/">hnpwa.com</a> 페이지는 특별히 언급할 가치가 있습니다 — 여기에는 일반적인 TodoMVC 앱 대신 다양한 프론트엔드 프레임워크의 사용을 볼 수 있는 Hacker News 웹사이트의 구현 예제가 나열되어 있습니다.</p>
+
+<p>심지어 <a href="https://www.pwabuilder.com/">PWABuilder</a> 웹사이트를 사용해 PWA를 온라인에서 생성할수도 있습니다.</p>
+
+<p>Service worker와 푸시에 관련된 정보는 최신 사이트에서 service worker를 사용하는 예제를 모아둔 <a href="https://serviceworke.rs/">Service Worker Cookbook</a>을 확인하시기 바랍니다.</p>
+
+<p>PWA 접근은 시도해볼만한 가치가 있으며, 여러분의 앱에서 동작하는지 스스로 확인해보시기 바랍니다.</p>
+
+<h2 id="브라우저_호환성">브라우저 호환성</h2>
+
+<p>앞서 언급했듯이, PWA는 하나의 API에 의존하지 않고, 가능한 최고의 웹 경험을 전달하기 위한 목표를 달성하기 위해 다양한 기술들을 사용합니다.</p>
+
+<p>PWA를 위해 요구되는 핵심 요소는 <a href="/ko/docs/Web/API/Service_Worker_API">service worker</a> 지원입니다. 고맙게도 service worker는 현재 데스크탑 및 모바일의 <a href="https://jakearchibald.github.io/isserviceworkerready/">모든 주요 브라우저에서 지원됩니다</a>.<a href="https://jakearchibald.github.io/isserviceworkerready/"> </a></p>
+
+<p><a href="/ko/docs/Web/Manifest">웹 앱 Manifest</a>, <a href="/ko/docs/Web/API/Push_API">푸시</a>, <a href="/ko/docs/Web/API/Notifications_API">알림</a>, <a href="/ko/docs/Web/Apps/Progressive/Add_to_home_screen">홈 화면에 추가</a> 기능과 같은 다른 기능들도 널리 지원되고 있습니다. 현재 Safari에서는 웹 앱 Manifest 및 홈 화면에 추가에 지원이 제한적이며 웹 푸시 알림은 지원하지 않습니다. 반면, 다른 주요 브라우저에서는 이 모든 기능들을 지원합니다.</p>
+
+<p>이러한 API의 일부는 실험중이며 문서도 여전히 완성되지 않았지만, Flipkart 와 AliExpress와 같은 성공 스토리를 보면 여러분의 웹 앱에 PWA 기능의 일부를 시도하고 구현하는 것에 대해 이미 납득이 되었을것입니다.</p>
+
+<p>무엇보다도 여러분은 프로그레시브 향상 규칙을 따라야 합니다 — 이러한 향상을 제공하는 기술들은 지원이 되는 경우에만 사용하고, 그렇지 않은 경우에도 여전히 기본 기능을 제공하시기 바랍니다. 이 방법으로 모든 사용자가 앱을 사용할 수 있지만, 최신 브라우저를 사용하는 사용자는 PWA 기능으로부터 더 많은 이점을 얻을 수 있습니다.</p>
+
+<h2 id="예시_어플리케이션">예시 어플리케이션</h2>
+
+<p>이 문서 시리즈에서는 <a href="http://2017.js13kgames.com/">js13kGames 2017</a> 대회의 <a href="http://js13kgames.com/aframe">A-Frame 카테고리</a>에 제출된 게임에 대한 정보를 나열하는 아주 간단한 웹사이트의 소스코드를 살펴볼 것입니다. 여러분은 웹 사이트의 실제 컨텐츠가 무엇인지에 대해서는 생각할 필요가 없습니다 — 중요한 점은 여러분의 프로젝트에 PWA 기능을 어떻게 사용하는지를 배우는 것입니다.</p>
+
+<p>온라인 버전은 <a href="https://mdn.github.io/pwa-examples/js13kpwa/">mdn.github.io/pwa-examples/js13kpwa</a> (<a href="https://github.com/mdn/pwa-examples/tree/master/js13kpwa">소스 코드도 확인하세요</a>)에서 확인하실 수 있으며, 다음 몇 가지 문서에서 자세히 설명할 것입니다.</p>
+
+<p>이제, 우리의 예제 앱의 구조에 대해 살펴볼 이 시리즈의 두 번째 파트로 이동합시다.</p>
+
+<p>{{NextMenu("Web/Apps/Progressive/App_structure", "Web/Apps/Progressive")}}</p>