Service Worker - team-yaza/mozi-client GitHub Wiki

์„œ๋น„์Šค ์›Œ์ปค๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋กœ, ์›น ํŽ˜์ด์ง€์™€๋Š” ๋ณ„๊ฐœ๋กœ ์ž‘๋™ํ•˜๋ฉฐ ์›น ํŽ˜์ด์ง€ ๋˜๋Š” ์‚ฌ์šฉ์ž์˜ ์ธํ„ฐ๋ž™์…˜์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค. ์„œ๋น„์Šค ์›Œ์ปค์˜ ์ˆ˜๋ช…์ฃผ๊ธฐ๋Š” ์›น ํŽ˜์ด์ง€์™€๋Š” ์™„์ „ํžˆ ๋ณ„๊ฐœ์ด๋‹ค. ์›น ์„œ๋น„์Šค์™€ ๋ธŒ๋ผ์šฐ์ € ๋ฐ ๋„คํŠธ์›Œํฌ ์‚ฌ์ด์—์„œ ํ”„๋ก์‹œ ์„œ๋ฒ„ ์—ญํ• ์„ ํ•˜๋ฉฐ, ์˜คํ”„๋ผ์ธ์—์„œ๋„ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

์›น ํŽ˜์ด์ง€์™€ ๋ณ„๊ฐœ๋กœ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ œ์•ฝ์ด ์žˆ๋‹ค.

  1. ์„œ๋น„์Šค ์›Œ์ปค๋Š” ์š”์ฒญํ•˜์ง€ ์•Š๋Š” ์ด์ƒ, ์—†๋Š” ๊ฒƒ์ด๋‚˜ ๋‹ค๋ฆ„์ด ์—†๋‹ค.
  2. ์›น ํŽ˜์ด์ง€ life cycle์„ ๋”ฐ๋ฅด์ง€ ์•Š๋Š”๋‹ค. ์„œ๋น„์Šค ์›Œ์ปค๋Š” ์›น ํŽ˜์ด์ง€๊ฐ€ ๋‹ซํžˆ๋”๋ผ๋„ ์ž๋™์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์ง€ ์•Š๋Š”๋‹ค.
  3. ์›น ํŽ˜์ด์ง€์™€ ๋ณ„๊ฐœ๋กœ ์กด์žํ•ด๋ฏ€๋กœ DOM์ด๋‚˜ window ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

์บ์‹œ์™€ ์ƒํ˜ธ์ž‘์šฉ

image

fetch ์ด๋ฒคํŠธ์˜ ์ค‘๊ฐ„์ž ์—ญํ• ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์„œ๋น„์Šค ์›Œ์ปค๋Š” HTTP๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์š”์ฒญํ•˜๋Š” ๋Œ€์‹  ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์บ์‹œ์—์„œ ์ž๋ฃŒ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. ์บ์‹œ๊ฐ€ ์‚ญ์ œ๋˜์ง€ ์•Š๋Š” ํ•œ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ธํ„ฐ๋„ท ์—ฐ๊ฒฐ ์—†์ด๋„ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

ํ‘ธ์‰ฌ ์•Œ๋ฆผ

image

๋ธŒ๋ผ์šฐ์ € ์ฐฝ์ด ๋‹ซํžŒ ์ƒํƒœ์—์„œ๋„ ๋™์ž‘ํ•˜๋ฏ€๋กœ, ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋™๊ธฐํ™”

image

์ฑ„ํŒ… ๋ฉ”์‹œ์ง€ ๋˜๋Š” ์‚ฌ์ง„ ์—…๋กœ๋“œ ๋“ฑ์˜ ์ž‘์—… ๋„์ค‘ ์ปดํ“จํ„ฐ๊ฐ€ ์˜คํ”„๋ผ์ธ ์ƒํƒœ๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ ์˜จ๋ผ์ธ ์ƒํƒœ๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ํ•ด๋‹น ์ž‘์—…์„ ๋งˆ์ € ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ๋‹ค.

Fetch

fetch๋ž€ web resource์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ํ–‰ํ•ด์ง€๋Š” ๋ชจ๋“  request action์„ ์˜๋ฏธํ•œ๋‹ค. service worker๋Š” fetch๋ฅผ ํ†ตํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  http request๋ฅผ ์ค‘๊ฐ„์—์„œ ๊ฐ€๋กœ์ฑŒ ์ˆ˜ ์žˆ๋‹ค. (proxy) ์˜ˆ๋ฅผ ๋“ค์–ด ์‹ค ์„œ๋ฒ„๋กœ ๋ณด๋‚ด์ง€๋Š” request๋ฅผ ์ค‘๊ฐ„์—์„œ ๊ฐ€๋กœ์ฑ„์–ด ์„œ๋ฒ„๋กœ ๋ณด๋‚ด์ง€ ๋ง๊ณ  ๋Œ€์‹  cache ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋“ฑ์˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

http request๊ฐ€ ์žˆ์„ ๋•Œ๋งˆ๋‹ค fetch์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ service worker๋Š” fetch event listener๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ fetch์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ listener์—์„œ request๋ฅผ interceptํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

๋ฉ”์‹œ์ง€๋ฅผ ํ†ตํ•œ ์„œ๋น„์Šค ์›Œ์ปค์™€ ํŽ˜์ด์ง€๊ฐ„์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜

  • ์œˆ๋„์šฐ์—์„œ ํ•ด๋‹น ์œˆ๋„์šฐ๋ฅผ ์ œ์–ดํ•˜๋Š” ์„œ๋น„์Šค ์›Œ์ปค๋กœ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
  • ์„œ๋น„์Šค ์›Œ์ปค์—์„œ ๋ฒ”์œ„ ๋‚ด์˜ ๋ชจ๋“  ์œˆ๋„์šฐ๋กœ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
  • ์„œ๋น„์Šค ์›Œ์ปค์—์„œ ํŠน์ • ์œˆ๋„์šฐ๋กœ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
  • ์œˆ๋„์šฐ๊ฐ„ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ (์„œ๋น„์Šค ์›Œ์ปค๋ฅผ ํ†ตํ•ด)

ํŽ˜์ด์ง€์—์„œ ์„œ๋น„์Šค์›Œ์ปค๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ดํ•œ๋‹ค.

navigator.serviceWorker.controller

๊ทธ ํ›„์—๋Š” ๋ฉ”์‹œ์ง€ ์ž์ฒด๋ฅผ ์ฒซ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ์„œ๋น„์Šค ์›Œ์ปค์˜ postMessage() ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•œ๋‹ค.์ด ๋ฉ”์‹œ์ง€๋Š” ๋ฌด์—‡์ด๋“  ๋  ์ˆ˜ ์žˆ๋‹ค.

๋ฉ”์‹œ์ง€๊ฐ€ ๊ฒŒ์‹œ๋˜๊ณ  ๋‚˜๋ฉด ์„œ๋น„์Šค ์›Œ์ปค๋Š” message ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

self.addEventListener('message', function(event){
   console.log(event.data)
})

์œ„ ์˜ˆ์ œ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„์„œ ์ฝ˜์†”์— ์ถœ๋ ฅํ•œ๋‹ค. ๋ฉ”์‹œ์ง€์— ํฌํ•จ๋œ ์ฝ˜ํ…์ธ ๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์— ์ „๋‹ฌ๋œ ์ด๋ฒคํŠธ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ ์†์„ฑ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ฉ”์‹œ์ง€ ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ ์ด์™ธ์—๋„ ์ด๋ฒคํŠธ ๊ฐ์ฒด๋Š” ์—ฌ๋Ÿฌ ์œ ์šฉํ•œ ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๊ฐ€์žฅ ์œ ์šฉํ•œ ์†์„ฑ์ค‘ ์ผ๋ถ€๋Š” source ์†์„ฑ์— ์žˆ๋‹ค.

source ์†์„ฑ์—๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ธ ์œˆ๋„์šฐ ์ •๋ณด๊ฐ€ ๋“ค์–ด์žˆ๋‹ค. ์ด ์ •๋ณด๋ฅผ ํ™œ์šฉํ•ด์„œ ๋ฌด์—‡์„ ํ• ์ง€ ๊ทธ๋ฆฌ๊ณ  ์‘๋‹ต์„ ์–ด๋””๋กœ ๋ณด๋‚ผ์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ๋Š” ๋ฉ”์‹œ์ง€์˜ source ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ ์ฝ”๋“œ์ด๋‹ค.

self.addEventListener('message', function(event) {
    console.log('Message received:', event.data);
    console.log('From a window with the id:', event.source.id);  
    console.log('which is currently pointing at:', event.source.url);
    console.log('and is', event.source.focused ? 'focused' : 'not focused');
    console.log('and', event.source.visibilityState)
})

ํŽ˜์ด์ง€์—์„œ ์„œ๋น„์Šค์›Œ์ปค๋กœ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ์บ์‹œํ•˜๋ผ๊ณ  ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

navigator.serviceWorker.controller.postMessage('cache-current-page')

์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ํŽ˜์ด์ง€์— ๋ฐฉ๋ฌธํ•˜๋ฉด ์„œ๋น„์Šค ์›Œ์ปค์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์„œ๋น„์Šค ์›Œ์ปค๋Š” ์ด ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ , ์–ด๋Š ํŽ˜์ด์ง€๋ฅผ ์บ์‹ฑํ• ์ง€ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ฒคํŠธ source ์†์„ฑ์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์„œ๋น„์Šค ์›Œ์ปค์—์„œ ํŽ˜์ด์ง€๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์€ ํŽ˜์ด์ง€์—์„œ ์„œ๋น„์Šค ์›Œ์ปค๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฒŒ์‹œํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ค. ์œ ์ผํ•œ ์ฐจ์ด์ ์€ postMessage()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฐ์ฒด์ด๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ์„œ๋น„์Šค ์›Œ์ปค์—์„œ postMessage()๋ฅผ ํ˜ธ์ถœํ–ˆ๋‹ค๋ฉด ์ด๋ฒˆ์—๋Š” ์„œ๋น„์Šค ์›Œ์ปค ํด๋ผ์ด์–ธํŠธ์—์„œ ํ˜ธ์ถœํ•œ๋‹ค.

์„œ๋น„์Šค ์›Œ์ปค๋‚ด์—์„œ ์„œ๋น„์Šค ์›Œ์ปค์˜ ๊ธ€๋กœ๋ฒŒ ๊ฐ์ฒด์ธ clients ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด ํ˜„์žฌ ์„œ๋น„์Šค ์›Œ์ปค ๋ฒ”์ฃผ์•ˆ์— ์—ด๋ ค ์žˆ๋Š” ๋ชจ๋“  ์œˆ๋„์šฐ(Window Clients)๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. clients ๊ฐ์ฒด๋Š” matchAll ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์„œ๋น„์Šค์›Œ์ปค ๋ฒ”์ฃผ ๋‚ด์— ์—ด๋ ค ์žˆ๋Š” ๋ชจ๋“  ์œˆ๋„์šฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. matchAll() ๋ฉ”์„œ๋“œ๋Š” 0๊ฐœ ํ˜น์€ ๊ทธ ์ด์ƒ์˜ WindowClient ๊ฐ์ฒด๋ฅผ ๋‹ด๋Š” ๋ฐฐ์—ด๋กœ ๋ฆฌ์กธ๋ธŒ๋˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

self.clients.matchAll().then(function(clients) {
  clients.forEach(function(client) {
    if (client.url.includes("/my-account")) {
      client.postMessage("Hi client: " + client.id;
    }
    })
})

์ด ์ฝ”๋“œ๋Š” ํ˜„์žฌ ์„œ๋น„์Šค ์›Œ์ปค๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ฐ€์ ธ์™€ ํ•˜๋‚˜์”ฉ ๋Œ๋ฉฐ ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ์žˆ๋Š” ์œˆ๋„์šฐ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ธ๋‹ค. ์ด ๋ฉ”์‹œ์ง€๋ฅผ ์œˆ๋„์šฐ์—์„œ ๋ฐ›๋Š” ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

navigator.serviceWorker.addEventListener('message', function(event){
    console.log(event.data)
})

์„œ๋น„์Šค ์›Œ์ปค๊ฐ€ ์„ค์น˜๋˜๊ณ  ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค ์บ์‹ฑ์ด ๋๋‚˜๋ฉด ์•ฑ ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜จ๋ผ์ธ์ด๋“  ์˜คํ”„๋ผ์ธ์ด๋“  ์ƒ๊ด€์—†์ด ์•ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์•Œ๋ ค์•ผํ•ฉ๋‹ˆ๋‹ค.

self.addEventListener('install', function() {
  event.waitUntil (
    caches.open(CACHE_NAME).then(function(cache) {
      return cache.addAll(CACHED_URLS)
    }).then(function() {
      return self.clients.matchAll({
        includeUncontrolled: true
      })
    }).then(function (clients) {
      clients.forEach(client) {
        client.postMessage('caching-complete')
      }
    })
  )
})

์œ„ ์ฝ”๋“œ์—์„œ clients.matchAll()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์˜ต์…˜ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์ œ์–ด๋˜์ง€ ์•Š๋Š” ํด๋ผ์ด์–ธํŠธ๋„ ๊ฒฐ๊ณผ์— ํฌํ•จ๋˜๋„๋ก ์š”์ฒญํ•œ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์— ์ฒ˜์Œ ๋ฐฉ๋ฌธํ•˜๋ฉด ์„œ๋น„์Šค ์›Œ์ปค๊ฐ€ ์„ค์น˜๋˜๊ณ  ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€๋Š” ์—ฌ์ „ํžˆ ์„œ๋น„์Šค ์›Œ์ปค์—์˜ํ•ด ์ œ์–ด๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งŒ์ผ self.clients.matchAll()์— ์ œ์–ด๋˜์ง€ ์•Š๋Š” ์œˆ๋„์šฐ๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋„๋ก ์•Œ๋ ค์ฃผ์ง€ ์•Š์•˜๋‹ค๋ฉด ๋ฉ”์‹œ์ง€๋Š” ๋ชฉ์ ์ง€์— ๋„๋‹ฌํ•˜์ง€ ๋ชปํ•  ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

LifeCycle

์„œ๋น„์Šค ์›Œ์ปค์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์€ ๋ณต์žกํ•˜๋‹ค.
์„œ๋น„์Šค ์›Œ์ปค๊ฐ€ ๋ฌด์—‡์„ ํ•˜๋ ค๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ๊ทธ ๋ผ์ดํ”„์‚ฌ์ดํด์ด ์–ด๋–ค ์ด์ ์ด ์žˆ๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค๋ฉด, ์„œ๋น„์Šค์›Œ์ปค์™€ ์‹ธ์šฐ๊ณ  ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์งˆ ์ˆ˜ ์žˆ๋‹ค.

But once you know how it works, you can deliver seamless, unobtrusive updates to users, mixing the best of web and native patterns.

์„œ๋น„์Šค ์›Œ์ปค ๋ผ์ดํ”„ ์‚ฌ์ดํด์˜ ๋ชฉ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Make offline-first possible.
  • Allow a new service worker to get itself ready without disrupting the current one.
  • Ensure an in-scope page is controlled by the same service worker (or no service worker) throughout.
  • Ensure there's only one version of your site running at once.

๋ผ์ดํ”„ ์‚ฌ์ดํด์˜ ๊ธฐ๋ณธ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

  • The install event is the first event a service worker gets, and it only happens once.
  • A promise passed to installEvent.waitUntil() signals the duration and success or failure of your install.
  • A service worker won't receive events like fetch and push until it successfully finishes installing and becomes "active".
  • By default, a page's fetches won't go through a service worker unless the page request itself went through a service worker. So you'll need to refresh the page to see the effects of the service worker.
  • clients.claim() can override this default, and take control of non-controlled pages.

Install

The first event a service worker gets is install. It's triggered as soon as the worker executes, and it's only called once per service worker. If you alter your service worker script the browser considers it a different service worker, and it'll get its own install event.

The install event is your chance to cache everything you need before being able to control clients. The promise you pass to event.waitUntil() lets the browser know when your install completes, and if it was successful.

If your promise rejects, this signals the install failed, and the browser throws the service worker away. It'll never control clients.

Activate

Once your service worker is ready to control clients and handle functional events like push and sync, you'll get an activate event.
But that doesn't mean the page that called .register() will be controlled.

clients claim

You can take control of uncontrolled clients by calling clients.claim() within your service worker once it's activated.

If you use your service worker to load pages differently than they'd load via the network, clients.claim() can be troublesome, as your service worker ends up controlling some clients that loaded without it.

Note: I see a lot of people including clients.claim() as boilerplate, but I rarely do so myself. It only really matters on the very first load, and due to progressive enhancement the page is usually working happily without service worker anyway.

์ฐธ๊ณ