서비스 워커를 사용하여 Jekyll 블로그를 오프라인으로 작동시키는 방법
게시 됨: 2017-01-26Short Bytes: 서비스 워커의 등장으로 웹사이트가 오프라인에서 작동하도록 만들 수 있다는 사실을 알고 계셨습니까? 이러한 웹 앱을 PWA(Progressive Web Apps)라고 합니다. 이 방법에서는 서비스 워커를 사용하여 Jekyll 기반 블로그/웹사이트를 오프라인에서 작동하게 하는 방법과 함께 제공되는 몇 가지 멋진 방법을 알려 드리겠습니다.
(참고 : 기사의 코드 스니펫은 내 블로그의 코드 저장소에서 가져왔습니다. 필요한 경우 참조할 수 있습니다. Jekyll을 처음 사용하는 경우 CSS Tricks에 대한 3 시리즈 기사를 읽을 수 있습니다.)
배경
이전에는 yuk YAML 파일 기반 App Cache가 있었습니다. 이 앱 캐시는 본질적으로 매우 하드 코딩되어 자산과 웹 페이지를 동적으로 캐시하는 데 사용할 수 없었습니다. 들어가라, 서비스 워커. 네트워크가 없을 때 웹 페이지를 제공하는 데 사용할 수 있도록 자산을 저장하기 위해 동적 서비스 작업자 캐싱을 수행하는 간단한 일반 이벤트 기반 Javascript API.
서비스 워커는 2014년에 Chrome Canary에 도착했지만 해당 사양은 여전히 수정/추가 및 설계되고 있습니다. 2015년과 2016년에 Google의 Chrome 팀은 브라우저에서 이 새로운 기술을 널리 퍼뜨렸습니다. Apple만이 (이 기사를 작성하는 시점에도) 그들의 기기에서 (알 수 없는 이유로) 이것을 지원하지 않았습니다.
서비스 워커란? 기본적으로 스테로이드에 대한 웹 작업자입니다. 웹 작업자의 한 가지 특징은 웹 작업자의 모든 작업이 기본 JavaScript 실행 스레드(이벤트 루프)와 별도로(비동기식으로) 실행된다는 것입니다. 이 기능은 웹 앱의 사용자 인터페이스 성능을 손상시키지 않으면서 복잡한 계산과 같은 CPU 또는 메모리 집약적인 작업을 실행하는 데 도움이 됩니다.
Service Worker를 사용하면 JavaScript, CSS, HTML, 이미지, 글꼴 파일과 같은 자산을 브라우저의 서비스 작업자 캐시에 캐시(오랫동안 저장)할 수 있으므로 다음에 사용자가 해당 페이지를 로드할 때 거의 즉시 로드됩니다. . 또한 이 캐싱 전략에서는 브라우저가 서비스 작업자 캐시에서 먼저 자산의 가용성을 찾기 때문에 웹 페이지는 오프라인일 때도 제공됩니다! 캐시에 자산이 없으면 가져오기 위해 네트워크 요청이 전송됩니다.
서비스 워커는 또한 Facebook, 웹 상의 Whatsapp 및 Twitter를 포함하여 오늘날 많은 웹사이트에서 흔히 볼 수 있는 푸시 알림을 활성화합니다. 주로 오프라인 기능에 대해 이야기하겠습니다. 이 방법은 Jekyll에만 해당되지만 대부분의 서비스 워커 코드는 일반적으로 모든 웹사이트에 적용할 수 있습니다.
Jekyll은 정적 콘텐츠를 제공하기 때문에( 정적 사이트 생성기입니다. 그렇죠! ) 서비스 워커 코드는 매우 기본적이고 이해하기 쉽습니다.
하자 롤:
모든 관련 페이지에서 다음 스크립트가 실행됩니다. 다음과 같은 작업을 수행합니다.
- 브라우저에서 서비스 워커 API가 존재하는지 확인하고 서비스 워커를 등록합니다.
- 서비스 워커가 활성화되면 웹사이트가 이제 오프라인에서 사용할 준비가 되었다는 멋진 토스트/칩 메시지를 사용자에게 보냅니다.
기능 showOfflineToast() { let offlineToast = document.querySelector('.offline-ready'); offlineToast.classList.add('활성'); setTimeout(함수(){ offlineToast.className = offlineToast.className.replace("활성", "").trim(); }, 5500); } // (1) if (내비게이터.serviceWorker) { navigator.serviceWorker.register('/sw.js').then(함수(reg) { if (!reg.installing) return; console.log("[*] ServiceWorker 설치 중..."); var 작업자 = reg.installing; 작업자.addEventListener('상태 변경', function() { if (worker.state == '중복') { console.log('[*] 설치 실패'); } if (worker.state == '설치됨') { console.log('[*] 설치 성공!'); } // (2) if (worker.state == '활성화' && !navigator.serviceWorker.controller) { showOfflineToast(); } }); }); }
이 코드 조각을 Jekyll 코드의 포함 디렉토리 안에 있는 serviceWorker.html 파일에 추가하고 Jekyll의 액체 템플릿 엔진을 사용하여 default.html 에 포함할 수 있습니다.
<!DOCTYPE HTML> <html> {% 포함 head.html %} <본체> {% 포함 header.html %} <div class="페이지 콘텐츠"> <div 클래스="래퍼"> {{ 콘텐츠 }} </div> </div> {% 포함 footer.html %} <!-- 스크립트 태그에 위의 코드 포함--> {% 포함 serviceWorker.html %} <div class="offline-ready">사이트 오프라인 사용 준비</div> </바디> </html>
이제 마술을 수행하는 실제 서비스 작업자 코드로 이동합니다. 이 코드는 Jekyll 코드의 루트에 있는 sw.js 에 있습니다.
//sw.js --- 레이아웃: null --- const staticCacheName = "gdad-s-river-static-v61"; console.log("서비스 워커 설치"); const filesToCache = [ "/", {site.html_pages의 페이지 %} '{{ page.url }}', {% endfor %} {site.posts의 게시물 %} '{{ post.url }}', {% endfor %} // 수동 입력이 아닌 자동화 가능 "/자산/이미지/bhavri-github-callbacks.png", "/assets/images/bhavri-github-issues.png", "/assets/images/jakethecake-svg-line-anime.png", "/assets/images/svg-animated-mast-text-shapes-tweet.png", "css/main.css", "/에 대한/", "/index.html" ];
staticCacheName 은 캐시된 응답을 변경할 때마다 업데이트되는 캐시 버전입니다(예: CSS 파일이나 블로그 게시물을 변경함). 그리고 어떤 요청을 가로채고 배열에 캐시할지 정의하고 있습니다(다음 스니펫에서 사용됨).
//sw.js self.addEventListener("설치", function(e){ self.skipWaiting(); e.wait까지( caches.open(staticCacheName).then(함수(캐시){ 반환 cache.addAll(filesToCache); }) ) });
self.skipWaiting 은 이 sw.js 파일이 변경될 때마다 최신 버전의 서비스 워커가 대기열에 들어가지 않고 즉시 활성화되어야 한다는 것입니다. 웹 페이지가 업데이트/변경되었습니다. 새로 고침을 클릭하여 새 게시물을 로드하거나 무엇이든 로드합니다. ), 이전 버전을 버립니다.
e.waitUntil MDN 웹사이트에서 인용:
“ ExtendableEvent.waitUntil() 메서드는 이벤트의 수명을 연장합니다. 서비스 워커에서 이벤트의 수명을 연장하면 이벤트 내의 비동기 작업이 완료되기 전에 브라우저가 서비스 워커를 종료하는 것을 방지할 수 있습니다."
내 캐시 이름이 포함된 프라미스를 반환하는 gdad-s-river-static-v61 캐시를 연 다음 캐시의 모든 요청을 가져오는 cache.addAll (백그라운드에서 가져오기 API 사용)을 호출합니다. 배열이 제공되고 캐시됩니다.
다음 스 니펫으로!
//sw.js self.addEventListener("활성화", function(e){ e.wait까지( caches.keys().then(함수(캐시 이름){ 반환 Promise.all( 캐시이름.필터(함수(캐시이름){ 반환 cacheName.startsWith("gdad-s-river-static-") && 캐시 이름 != 정적 캐시 이름; }).map(함수(캐시 이름){ 반환 cache.delete(cacheName); }) )봄 여름 시즌 }) ) });
서비스 워커가 활성화되면 최신 버전이 아닌 모든 서비스 워커가 삭제되도록 보장합니다. 예를 들어, 내 최신 캐시 버전이 gdad-s-river-static-v61 이고 누군가가 여전히 gdad-s-river-static-v58 에 있는 경우 다음 방문에서 해당 클라이언트가 신경 쓰지 않기를 바랍니다. 한 번에 하나의 버전을 펌핑하지만 최신 버전을 설치하려면 해당 버전을 완전히 삭제하십시오.
//sw.js self.addEventListener("가져오기", function(e){ e.respondWith( caches.match(e.request).then(함수(응답) { 응답을 반환 || 가져오기(e.요청); }) ) });
가져오기 이벤트에서 나는 단순히 서비스 워커에게 특정 요청에 응답하는 방법을 알려주고 있습니다. 브라우저에 캐시된 요청과 일치하도록 지시하고 요청에 대한 특정 응답을 찾지 못하면 네트워크를 통해 가져오고 그렇지 않으면 캐시에서 제공합니다.
타다! 서비스 워커가 Jekyll 기반 블로그를 오프라인으로 만들었습니다!
놀라다! 멋진 점:
당황: iOS 기기에서는 작동하지 않습니다.
다음과 같이 프로젝트의 루트에 웹 앱 manifest.json 파일을 추가하는 경우:
{ "이름": "gdad-s-river", "short_name": "gdad-s-river", "theme_color": "#2196f3", "background_color": "#2196f3", "디스플레이": "독립 실행형", "범위": "/", "start_url": "/", "아이콘": [ { "src": "자산/이미지/favicon_images/android-icon-36x36.png", "크기": "36x36", "유형": "이미지\/png", "밀도": "0.75" }, { "src": "자산/이미지/favicon_images/android-icon-48x48.png", "크기": "48x48", "유형": "이미지\/png", "밀도": "1.0" }, { "src": "자산/이미지/favicon_images/android-icon-72x72.png", "크기": "72x72", "유형": "이미지\/png", "밀도": "1.5" }, { "src": "자산/이미지/favicon_images/android-icon-96x96.png", "크기": "96x96", "유형": "이미지\/png", "밀도": "2.0" }, { "src": "자산/이미지/favicon_images/android-icon-144x144.png", "크기": "144x144", "유형": "이미지\/png", "밀도": "3.0" }, { "src": "자산/이미지/favicon_images/android-icon-192x192.png", "크기": "192x192", "유형": "이미지\/png", "밀도": "4.0" } ] }
head 태그 안의 head.html 파일에 추가합니다.
<머리> <!-- 몇가지 --> <link rel="manifest" href="/manifest.json"> <!-- 몇가지 --> </head>
그런 다음 웹사이트를 두 번째 방문(5분 이내)하면 사용자에게 홈 화면에 웹사이트를 추가하라는 메시지가 표시됩니다(다른 기본 앱과 마찬가지로 아이콘이 표시됨). 앱.
자원
- 서비스 워커의 오프라인 기능 및 캐싱 전략에 대한 자세한 내용은 이 멋진 Jake Archibald의 오프라인 요리책에서 찾을 수 있습니다.
- 서비스 워커와 IndexDB에 대해 알아야 할 모든 것에 대한 매우 상세한 무료 Udacity 과정입니다.
Jekyll 블로그의 이 기사가 흥미롭고 도움이 되었습니까? 의견과 피드백을 공유하는 것을 잊지 마십시오.
더 읽어 보기: Ecosia — 나무를 심는 검색 엔진