단일 페이지 웹 애플리케이션 (SPA)의 일반적인 아키텍처 기능은 애플리케이션의 전역 기능을 구동하는 데 필요한 최소한의 HTML, CSS, 자바스크립트 집합입니다. 실제로는 모든 페이지에서 유지되는 헤더, 탐색 및 기타 일반적인 사용자 인터페이스 요소입니다. 서비스 워커가 이 최소 UI의 HTML 및 종속 애셋을 사전 캐시하면 이를 애플리케이션 셸이라고 합니다.
애플리케이션 셸은 웹 애플리케이션에서 인지되는 성능에서 중요한 역할을 합니다. 콘텐츠가 가장 먼저 로드되므로 사용자가 콘텐츠가 사용자 인터페이스에 채워질 때까지 기다리는 동안 가장 먼저 표시됩니다.
네트워크를 사용할 수 있고 최소한 어느 정도 빠른 경우 애플리케이션 셸은 빠르게 로드되지만, 애플리케이션 셸 및 관련 애셋을 사전 캐시하는 서비스 워커는 애플리케이션 셸 모델에 다음과 같은 추가적인 이점을 제공합니다.
- 재방문에 대해 안정적이고 일관된 실적을 제공합니다. 서비스 워커가 설치되지 않은 앱을 처음 방문할 때 애플리케이션의 마크업과 관련 자산을 네트워크에서 로드해야 서비스 워커가 캐시에 저장할 수 있습니다. 그러나 재방문 시 캐시에서 애플리케이션 셸을 가져오므로 로드와 렌더링이 즉시 수행됩니다.
- 오프라인 시나리오에서도 기능에 안정적으로 액세스. 때때로 인터넷 접속이 불안정하거나 아예 없을 때 "해당 웹사이트를 찾을 수 없습니다"라는 화면 때문에 걱정스러울 때가 있습니다. 애플리케이션 셸 모델은 캐시에서 애플리케이션 셸 마크업으로 모든 탐색 요청에 응답하여 이를 해결합니다. 누군가 이전에 방문한 적이 없는 웹 앱의 URL을 방문하더라도 애플리케이션 셸은 캐시에서 제공되며 유용한 콘텐츠로 채워질 수 있습니다.
애플리케이션 셸 모델을 사용해야 하는 경우
애플리케이션 셸은 경로마다 변경되지 않지만 콘텐츠는 변경되는 공통 사용자 인터페이스 요소가 있을 때 가장 적합합니다. 대부분의 SPA는 실제로 애플리케이션 셸 모델을 이미 사용할 가능성이 높습니다.
이것이 프로젝트에 설명되어 있고 서비스 워커를 추가하여 안정성과 성능을 향상시키려는 경우 애플리케이션 셸은 다음을 수행해야 합니다.
- 빠르게 로드됩니다.
Cache
인스턴스의 정적 애셋을 사용합니다.- 헤더 및 사이드바와 같은 일반적인 인터페이스 요소를 페이지 콘텐츠와 별도로 포함합니다.
- 페이지별 콘텐츠를 검색하고 표시합니다.
- 필요한 경우 오프라인에서 볼 수 있도록 동적 콘텐츠를 캐시합니다(선택사항).
애플리케이션 셸은 API 또는 자바스크립트에 번들된 콘텐츠를 통해 페이지별 콘텐츠를 동적으로 로드합니다. 또한, 애플리케이션 셸의 마크업이 변경되면 서비스 워커 업데이트가 새 애플리케이션 셸을 선택해 자동으로 캐시해야 한다는 점에서 자동 업데이트되어야 합니다.
애플리케이션 셸 빌드
애플리케이션 셸은 콘텐츠와는 별개로 존재해야 하지만 콘텐츠 내에 채워질 콘텐츠의 기반을 제공해야 합니다. 되도록이면 슬림하지만 초기 다운로드에 사용자 환경이 빠르게 로드되고 있음을 사용자가 이해할 수 있도록 의미 있는 콘텐츠를 충분히 포함하는 것이 이상적입니다.
적절한 균형은 앱에 따라 다릅니다. 제이크 아치볼드의 Trained To Thrill 앱용 애플리케이션 셸에는 Flickr에서 새 콘텐츠를 가져올 수 있는 새로고침 버튼이 있는 헤더가 포함되어 있습니다.
애플리케이션 셸 마크업은 프로젝트마다 다르지만, 다음은 애플리케이션 상용구를 제공하는 index.html
파일의 한 가지 예입니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>
Application Shell Example
</title>
<link rel="manifest" href="/manifest.json">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="styles/global.css">
</head>
<body>
<header class="header">
<!-- Application header -->
<h1 class="header__title">Application Shell Example</h1>
</header>
<nav class="nav">
<!-- Navigation items -->
</nav>
<main id="app">
<!-- Where the application content populates -->
</main>
<div class="loader">
<!-- Spinner/content placeholders -->
</div>
<!-- Critical application shell logic -->
<script src="app.js"></script>
<!-- Service worker registration script -->
<script>
if ('serviceWorker' in navigator) {
// Register a service worker after the load event
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js');
});
}
</script>
</body>
</html>
그러나 프로젝트에서 애플리케이션 셸을 생성할 때 다음과 같은 특성을 지녀야 합니다.
- HTML은 개별 사용자 인터페이스 요소에 대해 명확하게 분리된 영역이 있어야 합니다. 위의 예에서는 애플리케이션의 헤더, 탐색, 기본 콘텐츠 영역, 콘텐츠를 로드할 때만 표시되는 로딩 '스피너' 공간이 포함됩니다.
- 애플리케이션 셸을 위해 로드되는 초기 자바스크립트 및 CSS는 최소화되어야 하며 콘텐츠가 아닌 애플리케이션 셸 자체의 기능과만 관련이 있어야 합니다. 이렇게 하면 애플리케이션이 셸을 최대한 빠르게 렌더링하고 콘텐츠가 표시될 때까지 기본 스레드 작업이 최소화됩니다.
- 서비스 워커를 등록하는 인라인 스크립트
애플리케이션 셸이 빌드되면 서비스 워커와 서비스 워커를 모두 캐시하는 서비스 워커를 빌드할 수 있습니다.
애플리케이션 셸 캐싱
애플리케이션 셸과 필요한 애셋은 서비스 워커가 설치 시 즉시 사전 캐시해야 하는 대상입니다. 위의 예시와 같은 애플리케이션 셸을 가정하고 workbox-build
을 사용하여 기본 Workbox 예시에서 이를 실행하는 방법을 살펴보겠습니다.
// build-sw.js
import {generateSW} from 'workbox-build';
// Where the generated service worker will be written to:
const swDest = './dist/sw.js';
generateSW({
swDest,
globDirectory: './dist',
globPatterns: [
// The necessary CSS and JS for the app shell
'**/*.js',
'**/*.css',
// The app shell itself
'shell.html'
],
// All navigations for URLs not precached will use this HTML
navigateFallback: 'shell.html'
}).then(({count, size}) => {
console.log(`Generated ${swDest}, which precaches ${count} assets totaling ${size} bytes.`);
});
build-sw.js
에 저장된 이 구성은 shell.html
에 포함된 애플리케이션 셸 마크업 파일을 포함하여 앱의 CSS 및 자바스크립트를 가져옵니다. 스크립트는 다음과 같이 Node를 사용하여 실행됩니다.
node build-sw.js
생성된 서비스 워커는 ./dist/sw.js
에 기록되며 완료되면 다음 메시지가 로깅됩니다.
Generated ./dist/sw.js, which precaches 5 assets totaling 44375 bytes.
페이지가 로드되면 서비스 워커가 애플리케이션 셸 마크업과 해당 종속 항목을 사전 캐시합니다.
번들러를 사용하는 프로젝트를 비롯한 거의 모든 워크플로에서 애플리케이션 셸의 HTML, CSS 및 JavaScript를 미리 캐시할 수 있습니다. 이 문서를 살펴보다 보면 Workbox를 직접 사용하여 도구 모음을 설정하여 SPA이든 프로젝트에 가장 적합한 서비스 워커를 빌드하는 방법을 배우게 됩니다.
결론
애플리케이션 셸 모델을 서비스 워커와 결합하면 오프라인 캐싱에 효과적이며, 특히 마크업 또는 API 응답을 위한 사전 캐싱 기능을 네트워크 우선, 캐시로 대체 전략과 결합하는 경우에 특히 유용합니다. 그 결과, 오프라인 상태에서도 재방문 시 애플리케이션 셸을 즉시 렌더링하는 안정적이고 빠른 환경이 구축됩니다.