2022년에 당신이 당신의 웹사이트를 위해 할 수 있는 가장 좋은 일 중 하나는 서비스 직원을 추가하는 것이다, 만약 당신이 이미 자리를 잡고 있지 않다면. 서비스 직원들은 당신의 웹사이트에 초능력을 줍니다. 오늘, 저는 그들이 할 수 있는 놀라운 일들 중 몇 가지를 보여드리고, 여러분의 사이트에서 바로 사용할 수 있는 번호별 페인트 보일러를 드리고 싶습니다.
서비스 노동자는 무엇인가?
요컨대, 서비스 직원은 보다 빠르고 탄력적인 웹 환경을 구축할 수 있도록 지원합니다.
일반적인 자바스크립트 파일과 달리 서비스 작업자들은 DOM에 접근할 수 없다. 또한 자체 스레드에서 실행되므로 다른 JavaScript의 실행을 차단하지 마십시오. 서비스 근로자들은 완전히 비동기적이 되도록 설계되었다.
보안
사이트 또는 웹 앱에 서비스 직원 추가
To use a service worker, the first thing we need to do is register it with the browser. You can register a service worker using the `navigator.serviceWorker.register()` method. Pass in the path to the service worker file as an argument.
navigator.serviceWorker.register('sw.js');
navigator.serviceWorker.register('sw.js');
You can run this in an external JavaScript file, but prefer to run it directly in a `script` element inline in my HTML so that it runs as soon as possible.
Unlike other types of JavaScript files, service workers only work for the directory in which they exist (and any of its sub-directories). A service worker file located at `/js/sw.js` would only work for files in the `/js` directory. As a result, you should place your service worker file inside the root directory of your site.
서비스 직원은 브라우저 지원이 탁월하지만 등록 스크립트를 실행하기 전에 브라우저가 이를 지원하는지 확인하는 것이 좋습니다.
if (navigator && navigator.serviceWorker) {
navigator.serviceWorker.register('sw.js');
}
if (navigator && navigator.serviceWorker) {
navigator.serviceWorker.register('sw.js');
}
서비스 작업자가 설치된 후 브라우저에서 활성화할 수 있습니다. 일반적으로 이 문제는 다음과 같은 경우에만 발생합니다.
- 현재 활성 상태인 서비스 직원이 없거나
- 사용자가 페이지를 새로 고칩니다.
서비스 작업자는 활성화될 때까지 요청을 실행하거나 가로채지 않습니다.
서비스 작업자의 요청 수신
Once the service worker is active, it can start intercepting requests and running other tasks. We can listen for requests with `self.addEventListener()` and the `fetch` event.
// Listen for request events
self.addEventListener('fetch', function (event) {
// Do stuff...
});
// Listen for request events
self.addEventListener('fetch', function (event) {
// Do stuff...
});
Inside the event listener, the `event.request` property is the request object itself. For ease, we can save it to the `request` variable.
크롬 브라우저의 특정 버전에는 페이지가 새 탭에서 열리면 오류가 발생하는 버그가 있습니다. 다행스럽게도, 만약을 대비해서 폴 아이리쉬의 간단한 수정 사항이 있습니다.
// Listen for request events
self.addEventListener('fetch', function (event) {
// Get the request
let request = event.request;
// Bug fix
// https://stackoverflow.com/a/49719964
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return;
});
// Listen for request events
self.addEventListener('fetch', function (event) {
// Get the request
let request = event.request;
// Bug fix
// https://stackoverflow.com/a/49719964
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return;
});
Once your service worker is active, every single request is sent through it, and will be intercepted with the `fetch` event.
서비스 작업자 전략
브라우저의 캐쉬로 자산을 가져오려면 어떻게 해야 합니까? 일반적으로 자산 유형에 따라 두 가지 접근 방식을 사용합니다.
- 설치 시 사전 캐시. 모든 사이트와 웹 앱은 CSS, 자바스크립트, 로고, favicon, 폰트 등 거의 모든 페이지에서 사용되는 일련의 핵심 자산을 가지고 있다. 설치 이벤트 중에 미리 캐싱한 후 요청이 있을 때마다 오프라인 우선 방식을 사용하여 서비스를 제공할 수 있습니다.
- 탐색할 때 캐시합니다. 당신의 사이트나 앱은 모든 방문자나 방문자가 접근할 수 없는 자료를 가지고 있을 것이다. 예를 들어, 블로그 게시물이나 기사와 어울리는 이미지와 같은 것들이 있다. 이러한 자산의 경우 방문자가 액세스할 때 실시간으로 캐싱할 수 있습니다.
그런 다음 접근 방식에 따라 이러한 캐시된 자산을 기본적으로 또는 예비로 제공할 수 있습니다.
서비스 작업자에게 네트워크 우선 및 오프라인 우선 전략 구현
Inside a `fetch` event in your service worker, the `request.headers.get('Accept')` method returns the MIME type for the content. We can use that to determine what type of file the request is for. MDN has a list of common files and their MIME types. For example, HTML files have a MIME type of `text/html`.
We can pass the type of file we’re looking for into the `String.includes()` method as an argument, and use `if` statements to respond in different ways based on the file type.
// Listen for request events
self.addEventListener('fetch', function (event) {
// Get the request
let request = event.request;
// Bug fix
// https://stackoverflow.com/a/49719964
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return;
// HTML files
// Network-first
if (request.headers.get('Accept').includes('text/html')) {
// Handle HTML files...
return;
}
// CSS & JavaScript
// Offline-first
if (request.headers.get('Accept').includes('text/css') || request.headers.get('Accept').includes('text/javascript')) {
// Handle CSS and JavaScript files...
return;
}
// Images
// Offline-first
if (request.headers.get('Accept').includes('image')) {
// Handle images...
}
});
// Listen for request events
self.addEventListener('fetch', function (event) {
// Get the request
let request = event.request;
// Bug fix
// https://stackoverflow.com/a/49719964
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return;
// HTML files
// Network-first
if (request.headers.get('Accept').includes('text/html')) {
// Handle HTML files...
return;
}
// CSS & JavaScript
// Offline-first
if (request.headers.get('Accept').includes('text/css') || request.headers.get('Accept').includes('text/javascript')) {
// Handle CSS and JavaScript files...
return;
}
// Images
// Offline-first
if (request.headers.get('Accept').includes('image')) {
// Handle images...
}
});
Inside each `if` statement, we use the `event.respondWith()` method to modify the response that’s sent back to the browser.
For assets that use a network-first approach, we use the `fetch()` method, passing in the `request`, to pass through the request for the HTML file. If it returns successfully, we’ll `return` the `response` in our callback function. This is the same behavior as not having a service worker at all.
If there’s an error, we can use `Promise.catch()` to modify the response instead of showing the default browser error message. We can use the `caches.match()` method to look for that page, and `return` it instead of the network `response`.
// Send the request to the network first
// If it's not found, look in the cache
event.respondWith(
fetch(request).then(function (response) {
return response;
}).catch(function (error) {
return caches.match(request).then(function (response) {
return response;
});
})
);
// Send the request to the network first
// If it's not found, look in the cache
event.respondWith(
fetch(request).then(function (response) {
return response;
}).catch(function (error) {
return caches.match(request).then(function (response) {
return response;
});
})
);
For assets that use an offline-first approach, we’ll first check inside the browser cache using the `caches.match()` method. If a match is found, we’ll `return` it. Otherwise, we’ll use the `fetch()` method to pass the `request` along to the network.
// Check the cache first
// If it's not found, send the request to the network
event.respondWith(
caches.match(request).then(function (response) {
return response || fetch(request).then(function (response) {
return response;
});
})
);
// Check the cache first
// If it's not found, send the request to the network
event.respondWith(
caches.match(request).then(function (response) {
return response || fetch(request).then(function (response) {
return response;
});
})
);
Inside an `install` event listener in the service worker, we can use the `caches.open()` method to open a service worker cache. We pass in the name we want to use for the cache, `app`, as an argument.
캐시의 범위가 지정되고 도메인으로 제한됩니다. 다른 사이트에서는 접속할 수 없고, 같은 이름의 캐시가 있을 경우 내용은 완전히 분리된다.
The `caches.open()` method returns a Promise. If a cache already exists with this name, the Promise will resolve with it. If not, it will create the cache first, then resolve.
// Listen for the install event
self.addEventListener('install', function (event) {
event.waitUntil(caches.open('app'));
});
// Listen for the install event
self.addEventListener('install', function (event) {
event.waitUntil(caches.open('app'));
});
Next, we can chain a `then()` method to our `caches.open()` method with a callback function.
In order to add files to the cache, we need to request them, which we can do with the `new Request()` constructor. We can use the `cache.add()` method to add the file to the service worker cache. Then, we `return` the `cache` object.
We want the `install` event to wait until we’ve cached our file before completing, so let’s wrap our code in the `event.waitUntil()` method:
// Listen for the install event
self.addEventListener('install', function (event) {
// Cache the offline.html page
event.waitUntil(caches.open('app').then(function (cache) {
cache.add(new Request('offline.html'));
return cache;
}));
});
// Listen for the install event
self.addEventListener('install', function (event) {
// Cache the offline.html page
event.waitUntil(caches.open('app').then(function (cache) {
cache.add(new Request('offline.html'));
return cache;
}));
});
I find it helpful to create an array with the paths to all of my core files. Then, inside the `install` event listener, after I open my cache, I can loop through each item and add it.
let coreAssets = [
'/css/main.css',
'/js/main.js',
'/img/logo.svg',
'/img/favicon.ico'
];
// On install, cache some stuff
self.addEventListener('install', function (event) {
// Cache core assets
event.waitUntil(caches.open('app').then(function (cache) {
for (let asset of coreAssets) {
cache.add(new Request(asset));
}
return cache;
}));
});
let coreAssets = [
'/css/main.css',
'/js/main.js',
'/img/logo.svg',
'/img/favicon.ico'
];
// On install, cache some stuff
self.addEventListener('install', function (event) {
// Cache core assets
event.waitUntil(caches.open('app').then(function (cache) {
for (let asset of coreAssets) {
cache.add(new Request(asset));
}
return cache;
}));
});
당신의 사이트나 앱은 모든 방문자나 방문자가 접근할 수 없는 자료를 가지고 있을 것이다. 예를 들어, 블로그 게시물이나 기사와 어울리는 이미지와 같은 것들이 있다. 이러한 자산의 경우 방문자가 액세스할 때 실시간으로 캐싱할 수 있습니다. 이후 방문 시 캐쉬에서 직접 로드하거나(오프라인 우선 접근 방식으로) 네트워크에 장애가 발생할 경우(네트워크 우선 접근 방식 사용) 예비로 사용할 수 있습니다.
When a `fetch()` method returns a successful `response`, we can use the `Response.clone()` method to create a copy of it.
Next, we can use the `caches.open()` method to open our cache. Then, we’ll use the `cache.put()` method to save the copied response to the cache, passing in the `request` and `copy` of the `response` as arguments. Because this is an asynchronous function, we’ll wrap our code in the `event.waitUntil()` method. This prevents the event from ending before we’ve saved our `copy` to cache. Once the `copy` is saved, we can `return` the `response` as normal.
/explanation We use `cache.put()` instead of `cache.add()` because we already have a `response`. Using `cache.add()` would make another network call.
// HTML files
// Network-first
if (request.headers.get('Accept').includes('text/html')) {
event.respondWith(
fetch(request).then(function (response) {
// Create a copy of the response and save it to the cache
let copy = response.clone();
event.waitUntil(caches.open('app').then(function (cache) {
return cache.put(request, copy);
}));
// Return the response
return response;
}).catch(function (error) {
return caches.match(request).then(function (response) {
return response;
});
})
);
}
// HTML files
// Network-first
if (request.headers.get('Accept').includes('text/html')) {
event.respondWith(
fetch(request).then(function (response) {
// Create a copy of the response and save it to the cache
let copy = response.clone();
event.waitUntil(caches.open('app').then(function (cache) {
return cache.put(request, copy);
}));
// Return the response
return response;
}).catch(function (error) {
return caches.match(request).then(function (response) {
return response;
});
})
);
}
모든 것을 종합하면
'css' 카테고리의 다른 글
사용자 지정 속성이 있는 CSS 페인트 API의 선호 색상 스키마 (0) | 2021.12.29 |
---|---|
2021년 가장 좋아하는 Chrome 확장 기능 (0) | 2021.12.29 |
웹 피드 작업: RSS 그 이상 (0) | 2021.12.29 |
HTML 검사기 API (0) | 2021.12.29 |
일관되고 유연한 스케일링 유형 및 간격 (0) | 2021.12.29 |
댓글