{"id":37103,"date":"2025-12-27T12:40:44","date_gmt":"2025-12-27T09:40:44","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=37103"},"modified":"2025-12-27T12:40:44","modified_gmt":"2025-12-27T09:40:44","slug":"vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/","title":{"rendered":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber"},"content":{"rendered":"<p><body><\/p>\n<h2>Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber<\/h2>\n<p>Progressive Web Uygulamalar\u0131 (PWA&#8217;lar), modern web geli\u015ftirmenin en heyecan verici ve d\u00f6n\u00fc\u015ft\u00fcr\u00fcc\u00fc alanlar\u0131ndan biridir. Kullan\u0131c\u0131 deneyimini \u00f6nemli \u00f6l\u00e7\u00fcde iyile\u015ftirerek, web sitelerini yerel uygulamalar\u0131n sundu\u011fu zengin \u00f6zelliklerle birle\u015ftiren PWA&#8217;lar, \u00e7evrimd\u0131\u015f\u0131 \u00e7al\u0131\u015fma, ana ekrana ekleme, anl\u0131k bildirimler ve daha fazlas\u0131n\u0131 m\u00fcmk\u00fcn k\u0131lar. Bu makalede, herhangi bir k\u00fct\u00fcphane veya framework kullanmadan, tamamen Vanilla JavaScript ile s\u0131f\u0131rdan bir PWA&#8217;n\u0131n nas\u0131l olu\u015fturulaca\u011f\u0131n\u0131 ad\u0131m ad\u0131m inceleyece\u011fiz. Bu yakla\u015f\u0131m, PWA&#8217;lar\u0131n temelini olu\u015fturan teknolojileri derinlemesine anlaman\u0131z\u0131 sa\u011flayacak ve projenize minimum ba\u011f\u0131ml\u0131l\u0131kla maksimum esneklik katacakt\u0131r.<\/p>\n<h3>Giri\u015f: PWA Nedir ve Neden \u00d6nemlidir?<\/h3>\n<p>Progressive Web Uygulamalar\u0131 (PWA&#8217;lar), web&#8217;in en iyi \u00f6zelliklerini (geni\u015f eri\u015fim, g\u00fcncelleme kolayl\u0131\u011f\u0131) yerel uygulamalar\u0131n en iyi \u00f6zellikleriyle (h\u0131z, g\u00fcvenilirlik, etkile\u015fim) birle\u015ftiren uygulamalard\u0131r. Google taraf\u0131ndan ortaya konan bu konsept, kullan\u0131c\u0131lar\u0131n herhangi bir uygulama ma\u011fazas\u0131ndan indirme yapmadan, do\u011frudan web taray\u0131c\u0131lar\u0131 \u00fczerinden y\u00fcksek performansl\u0131 ve zengin deneyimler ya\u015famas\u0131n\u0131 hedefler.<\/p>\n<h4>PWA&#8217;n\u0131n Temel \u00d6zellikleri ve Faydalar\u0131<\/h4>\n<p>*   <strong>G\u00fcvenilirlik (Reliable):<\/strong> A\u011f ba\u011flant\u0131s\u0131n\u0131n zay\u0131f oldu\u011fu veya hi\u00e7 olmad\u0131\u011f\u0131 durumlarda bile h\u0131zl\u0131 y\u00fckleme ve \u00e7al\u0131\u015fma yetene\u011fi. Service Worker&#8217;lar sayesinde \u00e7evrimd\u0131\u015f\u0131 \u00f6nbellekleme ile bu sa\u011flan\u0131r.<br \/>\n*   <strong>H\u0131z (Fast):<\/strong> Kullan\u0131c\u0131 etkile\u015fimlerine an\u0131nda yan\u0131t verir, animasyonlar ak\u0131c\u0131d\u0131r ve sayfa ge\u00e7i\u015fleri gecikmesizdir. Performans optimizasyonlar\u0131 ve \u00f6nbellekleme stratejileri ile bu m\u00fcmk\u00fcn olur.<br \/>\n*   <strong>Etkile\u015fim (Engaging):<\/strong> Ana ekrana eklenebilir, tam ekran modunda \u00e7al\u0131\u015fabilir ve anl\u0131k bildirimler g\u00f6nderebilir. Web Uygulamas\u0131 Manifest dosyas\u0131 ve Push API bu \u00f6zellikleri sa\u011flar.<br \/>\n*   <strong>Ke\u015ffedilebilirlik (Discoverable):<\/strong> Web tabanl\u0131 oldu\u011fu i\u00e7in arama motorlar\u0131 taraf\u0131ndan indekslenebilir ve kolayca payla\u015f\u0131labilir.<br \/>\n*   <strong>G\u00fcncellenebilirlik (Updatable):<\/strong> Kullan\u0131c\u0131 m\u00fcdahalesi olmadan arka planda otomatik olarak g\u00fcncellenebilir.<br \/>\n*   <strong>G\u00fcvenlik (Secure):<\/strong> Her zaman HTTPS \u00fczerinden sunulur, bu da veri g\u00fcvenli\u011fini ve gizlili\u011fini sa\u011flar.<\/p>\n<p>PWA&#8217;lar, geli\u015ftiricilere tek bir kod taban\u0131yla hem web hem de mobil platformlarda harika deneyimler sunma imkan\u0131 tan\u0131rken, kullan\u0131c\u0131lara ise daha az veri kullan\u0131m\u0131, daha h\u0131zl\u0131 eri\u015fim ve daha zengin etkile\u015fimler vaat eder. Vanilla JavaScript ile PWA geli\u015ftirmek, bu temel teknolojilerin nas\u0131l \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 en saf haliyle anlaman\u0131n ve kontrol etmenin en iyi yoludur.<\/p>\n<h3>PWA Temelleri ve Bile\u015fenleri<\/h3>\n<p>Bir PWA olu\u015fturmak i\u00e7in birka\u00e7 temel bile\u015fene ihtiyac\u0131m\u0131z vard\u0131r. Bu bile\u015fenler, uygulaman\u0131z\u0131n &#8220;ilerici&#8221; \u00f6zelliklerini etkinle\u015ftiren yap\u0131 ta\u015flar\u0131d\u0131r.<\/p>\n<h4>Web Uygulamas\u0131 Manifest Dosyas\u0131 (Web App Manifest)<\/h4>\n<p>Bu JSON dosyas\u0131, taray\u0131c\u0131ya uygulaman\u0131z hakk\u0131nda meta veriler sa\u011flar. Taray\u0131c\u0131 bu bilgileri kullanarak uygulaman\u0131z\u0131 kullan\u0131c\u0131n\u0131n ana ekran\u0131na eklerken, bir ba\u015flang\u0131\u00e7 \u200b\u200bekran\u0131 g\u00f6r\u00fcnt\u00fclerken veya sistem aray\u00fcz\u00fcnde g\u00f6sterirken nas\u0131l davranaca\u011f\u0131n\u0131 belirler. Manifest dosyas\u0131nda uygulaman\u0131n ad\u0131, k\u0131sa ad\u0131, ba\u015flang\u0131\u00e7 \u200b\u200bURL&#8217;si, g\u00f6r\u00fcnt\u00fclenecek mod (tam ekran, ba\u011f\u0131ms\u0131z), tema renkleri ve \u00e7e\u015fitli boyutlardaki simgeler gibi bilgiler bulunur.<\/p>\n<h4>Service Workers<\/h4>\n<p>Service Worker&#8217;lar, web taray\u0131c\u0131s\u0131 ile a\u011f aras\u0131nda bir proxy g\u00f6revi g\u00f6ren JavaScript dosyalar\u0131d\u0131r. Uygulaman\u0131z\u0131n a\u011f isteklerini kesebilir, \u00f6nbelle\u011fe alabilir ve \u00e7evrimd\u0131\u015f\u0131 i\u015flevsellik sa\u011flayabilirler. Bir web sayfas\u0131ndan ba\u011f\u0131ms\u0131z olarak arka planda \u00e7al\u0131\u015f\u0131rlar ve bu sayede anl\u0131k bildirimler, arka plan senkronizasyonu gibi \u00f6zellikler m\u00fcmk\u00fcn olur. PWA&#8217;n\u0131n \u00e7evrimd\u0131\u015f\u0131 yetene\u011finin kalbi Service Worker&#8217;lard\u0131r.<\/p>\n<h4>HTTPS<\/h4>\n<p>T\u00fcm PWA&#8217;lar HTTPS \u00fczerinden sunulmal\u0131d\u0131r. Bu, hem g\u00fcvenlik hem de Service Worker&#8217;lar\u0131n d\u00fczg\u00fcn \u00e7al\u0131\u015fmas\u0131 i\u00e7in zorunlu bir gerekliliktir. HTTPS, sunucu ile istemci aras\u0131ndaki ileti\u015fimi \u015fifreleyerek veri b\u00fct\u00fcnl\u00fc\u011f\u00fcn\u00fc ve gizlili\u011fini sa\u011flar.<\/p>\n<h4>Duyarl\u0131 Tasar\u0131m (Responsive Design)<\/h4>\n<p>PWA&#8217;lar farkl\u0131 ekran boyutlar\u0131na ve cihazlara uyum sa\u011flayabilmelidir. Bu, uygulaman\u0131z\u0131n masa\u00fcst\u00fc, tablet veya mobil cihazlarda tutarl\u0131 ve kullan\u0131c\u0131 dostu bir deneyim sunmas\u0131n\u0131 sa\u011flar. CSS medya sorgular\u0131 ve esnek d\u00fczenler kullanarak duyarl\u0131 tasar\u0131m elde edilir.<\/p>\n<h3>Ad\u0131m Ad\u0131m Vanilla JS PWA Geli\u015ftirme<\/h3>\n<p>\u015eimdi, Vanilla JavaScript kullanarak basit bir PWA&#8217;y\u0131 nas\u0131l olu\u015fturaca\u011f\u0131m\u0131z\u0131 ad\u0131m ad\u0131m inceleyelim.<\/p>\n<h4>1. Proje Yap\u0131land\u0131rmas\u0131 ve Temel HTML<\/h4>\n<p>\u00d6ncelikle, projemiz i\u00e7in temel bir dosya yap\u0131s\u0131 olu\u015ftural\u0131m. Bir <code>index.html<\/code>, <code>style.css<\/code> ve <code>app.js<\/code> dosyas\u0131na ihtiyac\u0131m\u0131z olacak.<\/p>\n<pre><code class=\"language-\">pwa-vanilla-js\/\n\u251c\u2500\u2500 index.html\n\u251c\u2500\u2500 style.css\n\u2514\u2500\u2500 app.js<\/code><\/pre>\n<p><strong><code>index.html<\/code>:<\/strong> Temel HTML yap\u0131s\u0131n\u0131 ve PWA i\u00e7in gerekli meta etiketlerini i\u00e7erir.<\/p>\n<pre><code class=\"language-html\"><!DOCTYPE html>\n<html lang=\"tr\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Vanilla PWA Uygulamas\u0131<\/title>\n    <link rel=\"stylesheet\" href=\"style.css\">\n    <link rel=\"manifest\" href=\"manifest.json\">\n    <meta name=\"theme-color\" content=\"#317EFB\"\/> <!-- Taray\u0131c\u0131 aray\u00fcz\u00fc rengi -->\n    <link rel=\"apple-touch-icon\" href=\"icons\/icon-192x192.png\"> <!-- iOS i\u00e7in ana ekran simgesi -->\n<\/head>\n<body>\n    <header>\n        \n    <\/header>\n    <main>\n        <p>Bu, Vanilla JavaScript ile olu\u015fturulmu\u015f basit bir PWA'd\u0131r.<\/p>\n        <button id=\"fetchButton\">Veri \u00c7ek<\/button>\n        <div id=\"content\"><\/div>\n    <\/main>\n    <footer>\n        <p>&copy; 2023 Vanilla PWA<\/p>\n    <\/footer>\n\n    <script src=\"app.js\"><\/script>\n<\/body>\n<\/html><\/code><\/pre>\n<p>Yukar\u0131daki HTML dosyas\u0131nda dikkat edilmesi gerekenler:<br \/>\n*   <code><meta name=\"viewport\"><\/code>: Duyarl\u0131 tasar\u0131m i\u00e7in olmazsa olmazd\u0131r.<br \/>\n*   <code><link rel=\"manifest\" href=\"manifest.json\"><\/code>: PWA manifest dosyam\u0131z\u0131 ba\u011fl\u0131yoruz.<br \/>\n*   <code><meta name=\"theme-color\"><\/code>: Taray\u0131c\u0131n\u0131n tema rengini belirler.<br \/>\n*   <code><link rel=\"apple-touch-icon\"><\/code>: iOS cihazlarda ana ekrana eklendi\u011finde kullan\u0131lacak simgeyi belirtir.<br \/>\n*   <code><script src=\"app.js\"><\/script><\/code>: Ana JavaScript dosyam\u0131z\u0131 ba\u011fl\u0131yoruz.<\/p>\n<p><strong><code>style.css<\/code>:<\/strong> Uygulamam\u0131za biraz stil ekleyelim.<\/p>\n<pre><code class=\"language-css\">body {\n    font-family: Arial, sans-serif;\n    margin: 0;\n    padding: 0;\n    background-color: #f4f4f4;\n    color: #333;\n    text-align: center;\n}\nheader {\n    background-color: #317EFB;\n    color: white;\n    padding: 1rem 0;\n}\nmain {\n    padding: 20px;\n}\nbutton {\n    background-color: #007bff;\n    color: white;\n    border: none;\n    padding: 10px 20px;\n    border-radius: 5px;\n    cursor: pointer;\n    font-size: 1rem;\n    margin-top: 15px;\n}\nbutton:hover {\n    background-color: #0056b3;\n}\n#content {\n    margin-top: 20px;\n    padding: 15px;\n    border: 1px solid #ccc;\n    background-color: white;\n    border-radius: 8px;\n    text-align: left;\n    max-width: 600px;\n    margin-left: auto;\n    margin-right: auto;\n}\nfooter {\n    background-color: #333;\n    color: white;\n    padding: 1rem 0;\n    position: fixed;\n    bottom: 0;\n    width: 100%;\n}<\/code><\/pre>\n<h4>2. Web Uygulamas\u0131 Manifest Dosyas\u0131 Olu\u015fturma<\/h4>\n<p><code>manifest.json<\/code> dosyas\u0131n\u0131 projemizin k\u00f6k dizininde olu\u015ftural\u0131m. Bu dosya, PWA&#8217;m\u0131z\u0131n ana ekrana eklendi\u011finde nas\u0131l g\u00f6r\u00fcnece\u011fini ve davranaca\u011f\u0131n\u0131 tan\u0131mlar. Ayr\u0131ca, uygulaman\u0131z i\u00e7in \u00e7e\u015fitli boyutlarda simgeler sa\u011flaman\u0131z gerekecektir. Bu simgeleri <code>icons<\/code> ad\u0131nda bir klas\u00f6rde saklayabilirsiniz (\u00f6rne\u011fin, <code>icons\/icon-192x192.png<\/code>, <code>icons\/icon-512x512.png<\/code>).<\/p>\n<pre><code class=\"language-json\">{\n    \"name\": \"Vanilla PWA Uygulamas\u0131\",\n    \"short_name\": \"Vanilla PWA\",\n    \"description\": \"Vanilla JavaScript ile olu\u015fturulmu\u015f basit bir PWA.\",\n    \"start_url\": \"\/\",\n    \"display\": \"standalone\",\n    \"background_color\": \"#f4f4f4\",\n    \"theme_color\": \"#317EFB\",\n    \"icons\": [\n        {\n            \"src\": \"icons\/icon-72x72.png\",\n            \"sizes\": \"72x72\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-96x96.png\",\n            \"sizes\": \"96x96\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-128x128.png\",\n            \"sizes\": \"128x128\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-144x144.png\",\n            \"sizes\": \"144x144\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-152x152.png\",\n            \"sizes\": \"152x152\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-192x192.png\",\n            \"sizes\": \"192x192\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-384x384.png\",\n            \"sizes\": \"384x384\",\n            \"type\": \"image\/png\"\n        },\n        {\n            \"src\": \"icons\/icon-512x512.png\",\n            \"sizes\": \"512x512\",\n            \"type\": \"image\/png\"\n        }\n    ]\n}<\/code><\/pre>\n<p>*   <code>name<\/code>: Uygulaman\u0131n tam ad\u0131.<br \/>\n*   <code>short_name<\/code>: Ana ekranda veya uygulama ba\u015flat\u0131c\u0131s\u0131nda g\u00f6sterilecek k\u0131sa ad.<br \/>\n*   <code>description<\/code>: Uygulaman\u0131n k\u0131sa a\u00e7\u0131klamas\u0131.<br \/>\n*   <code>start_url<\/code>: Uygulama ba\u015flat\u0131ld\u0131\u011f\u0131nda a\u00e7\u0131lacak URL. <code>\/<\/code> genellikle k\u00f6k dizini i\u015faret eder.<br \/>\n*   <code>display<\/code>: Uygulaman\u0131n nas\u0131l g\u00f6r\u00fcnt\u00fclenece\u011fini belirler. <code>standalone<\/code> taray\u0131c\u0131 aray\u00fcz\u00fc olmadan ba\u011f\u0131ms\u0131z bir uygulama gibi g\u00f6r\u00fcnmesini sa\u011flar.<br \/>\n*   <code>background_color<\/code>: Uygulama ba\u015flat\u0131l\u0131rken g\u00f6sterilen splash screen&#8217;in arka plan rengi.<br \/>\n*   <code>theme_color<\/code>: Taray\u0131c\u0131n\u0131n tema rengi.<br \/>\n*   <code>icons<\/code>: Farkl\u0131 boyutlardaki uygulama simgeleri.<\/p>\n<h4>3. Service Worker Kayd\u0131 ve Temel \u0130\u015flevsellik<\/h4>\n<p>Service Worker, PWA&#8217;n\u0131n en kritik par\u00e7as\u0131d\u0131r. \u00d6nbellekleme, \u00e7evrimd\u0131\u015f\u0131 destek ve arka plan i\u015flemleri i\u00e7in kullan\u0131l\u0131r.<\/p>\n<p><strong><code>app.js<\/code>:<\/strong> Service Worker&#8217;\u0131 kaydedece\u011fimiz ana JavaScript dosyam\u0131z.<\/p>\n<pre><code class=\"language-javascript\">if ('serviceWorker' in navigator) {\n    window.addEventListener('load', () => {\n        navigator.serviceWorker.register('\/service-worker.js')\n            .then(registration => {\n                console.log('Service Worker kay\u0131tl\u0131: ', registration.scope);\n            })\n            .catch(error => {\n                console.error('Service Worker kayd\u0131 ba\u015far\u0131s\u0131z: ', error);\n            });\n    });\n} else {\n    console.warn('Taray\u0131c\u0131n\u0131z Service Worker\\'\u0131 desteklemiyor.');\n}\n\n\/\/ Basit bir veri \u00e7ekme fonksiyonu\ndocument.getElementById('fetchButton').addEventListener('click', async () => {\n    const contentDiv = document.getElementById('content');\n    contentDiv.innerHTML = 'Veri \u00e7ekiliyor...';\n    try {\n        const response = await fetch('https:\/\/jsonplaceholder.typicode.com\/todos\/1'); \/\/ \u00d6rnek API\n        if (!response.ok) {\n            throw new Error(<code>HTTP hatas\u0131! Durum: ${response.status}<\/code>);\n        }\n        const data = await response.json();\n        contentDiv.innerHTML = <code><p><strong>Ba\u015fl\u0131k:<\/strong> ${data.title}<\/p><p><strong>Tamamland\u0131:<\/strong> ${data.completed ? 'Evet' : 'Hay\u0131r'}<\/p><\/code>;\n    } catch (error) {\n        contentDiv.innerHTML = <code><p style=\"color: red;\">Veri \u00e7ekme hatas\u0131: ${error.message}<\/p><p>L\u00fctfen internet ba\u011flant\u0131n\u0131z\u0131 kontrol edin.<\/p><\/code>;\n        console.error('Veri \u00e7ekme hatas\u0131:', error);\n    }\n});<\/code><\/pre>\n<p>Yukar\u0131daki kod, taray\u0131c\u0131n\u0131n Service Worker&#8217;\u0131 destekleyip desteklemedi\u011fini kontrol eder ve destekliyorsa <code>load<\/code> olay\u0131nda <code>service-worker.js<\/code> dosyas\u0131n\u0131 kaydeder.<\/p>\n<p><strong><code>service-worker.js<\/code>:<\/strong> Bu dosya, Service Worker&#8217;\u0131n\u0131z\u0131n t\u00fcm mant\u0131\u011f\u0131n\u0131 i\u00e7erecektir. Proje k\u00f6k dizininde olmal\u0131d\u0131r.<\/p>\n<pre><code class=\"language-javascript\">const CACHE_NAME = 'vanilla-pwa-cache-v1';\nconst urlsToCache = [\n    '\/',\n    '\/index.html',\n    '\/style.css',\n    '\/app.js',\n    '\/manifest.json',\n    '\/icons\/icon-72x72.png',\n    '\/icons\/icon-96x96.png',\n    '\/icons\/icon-128x128.png',\n    '\/icons\/icon-144x144.png',\n    '\/icons\/icon-152x152.png',\n    '\/icons\/icon-192x192.png',\n    '\/icons\/icon-384x384.png',\n    '\/icons\/icon-512x512.png'\n];\n\n\/\/ Y\u00fckleme (Install) Olay\u0131: Service Worker ilk y\u00fcklendi\u011finde tetiklenir\nself.addEventListener('install', event => {\n    console.log('[Service Worker] Y\u00fckleniyor...');\n    event.waitUntil(\n        caches.open(CACHE_NAME)\n            .then(cache => {\n                console.log('[Service Worker] \u00d6nbellek a\u00e7\u0131ld\u0131, dosyalar \u00f6nbelle\u011fe al\u0131n\u0131yor.');\n                return cache.addAll(urlsToCache);\n            })\n            .then(() => {\n                console.log('[Service Worker] Y\u00fckleme tamamland\u0131, yeni Service Worker etkinle\u015fmeye haz\u0131r.');\n                self.skipWaiting(); \/\/ Eski Service Worker'\u0131n hemen sonland\u0131r\u0131lmas\u0131n\u0131 sa\u011flar\n            })\n            .catch(error => {\n                console.error('[Service Worker] \u00d6nbelle\u011fe alma hatas\u0131:', error);\n            })\n    );\n});\n\n\/\/ Etkinle\u015ftirme (Activate) Olay\u0131: Eski Service Worker'lar temizlenir\nself.addEventListener('activate', event => {\n    console.log('[Service Worker] Etkinle\u015ftiriliyor...');\n    event.waitUntil(\n        caches.keys().then(cacheNames => {\n            return Promise.all(\n                cacheNames.map(cacheName => {\n                    if (cacheName !== CACHE_NAME) {\n                        console.log('[Service Worker] Eski \u00f6nbellek temizleniyor:', cacheName);\n                        return caches.delete(cacheName);\n                    }\n                    return null;\n                }).filter(Boolean) \/\/ null de\u011ferleri filtrele\n            );\n        }).then(() => {\n            console.log('[Service Worker] Etkinle\u015ftirme tamamland\u0131, istemciler \u00fczerinde kontrol ele al\u0131n\u0131yor.');\n            return self.clients.claim(); \/\/ Service Worker'\u0131n sayfay\u0131 hemen kontrol etmesini sa\u011flar\n        })\n    );\n});\n\n\/\/ Fetch Olay\u0131: Her a\u011f iste\u011fi Service Worker \u00fczerinden ge\u00e7er\nself.addEventListener('fetch', event => {\n    \/\/ Sadece GET isteklerini ve http\/https protokollerini \u00f6nbelle\u011fe al\n    if (event.request.method !== 'GET' || !event.request.url.startsWith('http')) {\n        return;\n    }\n\n    event.respondWith(\n        caches.match(event.request)\n            .then(cachedResponse => {\n                \/\/ \u00d6nbellekte varsa do\u011frudan \u00f6nbellekten d\u00f6nd\u00fcr\n                if (cachedResponse) {\n                    console.log('[Service Worker] \u00d6nbellekten servis ediliyor:', event.request.url);\n                    return cachedResponse;\n                }\n\n                \/\/ \u00d6nbellekte yoksa a\u011f\u0131 dene\n                return fetch(event.request)\n                    .then(response => {\n                        \/\/ Ge\u00e7erli bir yan\u0131t gelirse (200 OK) ve bir uzant\u0131s\u0131 varsa \u00f6nbelle\u011fe al\n                        if (!response || response.status !== 200 || response.type !== 'basic') {\n                            return response;\n                        }\n\n                        \/\/ Yan\u0131t\u0131 klonla \u00e7\u00fcnk\u00fc bir yan\u0131t sadece bir kez t\u00fcketilebilir\n                        const responseToCache = response.clone();\n                        caches.open(CACHE_NAME)\n                            .then(cache => {\n                                cache.put(event.request, responseToCache);\n                                console.log('[Service Worker] A\u011fa \u00e7ekilen yan\u0131t \u00f6nbelle\u011fe al\u0131nd\u0131:', event.request.url);\n                            });\n\n                        return response;\n                    })\n                    .catch(() => {\n                        \/\/ A\u011f ba\u011flant\u0131s\u0131 yoksa veya hata olu\u015fursa, \u00e7evrimd\u0131\u015f\u0131 fallback sayfalar\u0131n\u0131 d\u00f6nd\u00fcr\n                        console.log('[Service Worker] A\u011f ba\u011flant\u0131s\u0131 yok veya hata olu\u015ftu:', event.request.url);\n                        \/\/ E\u011fer \u00f6zel bir \u00e7evrimd\u0131\u015f\u0131 sayfan\u0131z varsa buraya ekleyebilirsiniz.\n                        \/\/ \u00d6rne\u011fin: return caches.match('\/offline.html');\n                        return new Response('<p>\u0130nternet ba\u011flant\u0131n\u0131z yok gibi g\u00f6r\u00fcn\u00fcyor.<\/p>', {\n                            headers: { 'Content-Type': 'text\/html' }\n                        });\n                    });\n            })\n    );\n});<\/code><\/pre>\n<p>Service Worker kodunda \u00fc\u00e7 ana olay dinleyicisi bulunur:<br \/>\n*   <strong><code>install<\/code>:<\/strong> Service Worker ilk kez y\u00fcklendi\u011finde tetiklenir. Burada uygulaman\u0131z\u0131n temel statik dosyalar\u0131n\u0131 (HTML, CSS, JS, simgeler) \u00f6nbelle\u011fe al\u0131rs\u0131n\u0131z. <code>self.skipWaiting()<\/code> \u00e7a\u011fr\u0131s\u0131, yeni Service Worker&#8217;\u0131n hemen etkinle\u015fmesini sa\u011flar ve sayfan\u0131n yeniden y\u00fcklenmesini beklemez.<br \/>\n*   <strong><code>activate<\/code>:<\/strong> Yeni Service Worker etkinle\u015fti\u011finde tetiklenir. Genellikle eski \u00f6nbellekleri temizlemek i\u00e7in kullan\u0131l\u0131r. <code>self.clients.claim()<\/code> \u00e7a\u011fr\u0131s\u0131, etkinle\u015fen Service Worker&#8217;\u0131n hemen mevcut a\u00e7\u0131k sekmeleri kontrol etmesini sa\u011flar.<br \/>\n*   <strong><code>fetch<\/code>:<\/strong> Uygulaman\u0131z\u0131n yapt\u0131\u011f\u0131 her a\u011f iste\u011fi bu olay dinleyicisinden ge\u00e7er. Burada iste\u011fi \u00f6nbellekte arayabilir, bulursan\u0131z \u00f6nbellekten servis edebilir veya a\u011f\u0131 deneyip yan\u0131t\u0131 \u00f6nbelle\u011fe alabilirsiniz. Bu, PWA&#8217;n\u0131n \u00e7evrimd\u0131\u015f\u0131 yetene\u011finin temelini olu\u015fturur.<\/p>\n<p>Yukar\u0131daki <code>fetch<\/code> olay dinleyicisi, &#8220;Cache-First, then Network&#8221; stratejisini uygular. Yani \u00f6nce \u00f6nbellekte arar, bulursa oradan d\u00f6nd\u00fcr\u00fcr. Bulamazsa a\u011f\u0131 dener ve ba\u015far\u0131l\u0131 olursa yan\u0131t\u0131 \u00f6nbelle\u011fe al\u0131r. A\u011f hatas\u0131 durumunda ise basit bir \u00e7evrimd\u0131\u015f\u0131 mesaj\u0131 d\u00f6nd\u00fcr\u00fcr.<\/p>\n<h4>4. Offline Deste\u011fi ve Dinamik \u0130\u00e7erik \u00d6nbellekleme<\/h4>\n<p>Service Worker&#8217;\u0131m\u0131z\u0131n <code>install<\/code> olay\u0131nda statik dosyalar\u0131 \u00f6nbelle\u011fe alarak temel \u00e7evrimd\u0131\u015f\u0131 deste\u011fi sa\u011flad\u0131k. <code>fetch<\/code> olay\u0131nda ise dinamik i\u00e7erikler (\u00f6rne\u011fin API istekleri) i\u00e7in \u00f6nbelle\u011fe alma stratejileri uygulayabiliriz. Yukar\u0131daki \u00f6rnekte, API iste\u011fi ba\u015far\u0131l\u0131 oldu\u011funda yan\u0131t\u0131 \u00f6nbelle\u011fe alarak sonraki ayn\u0131 istekler i\u00e7in \u00f6nbellekten servis edilmesini sa\u011flad\u0131k.<\/p>\n<p><strong>\u00d6nbellekleme Stratejileri:<\/strong><br \/>\n*   <strong>Cache-First (\u00d6nbellek \u00d6nce):<\/strong> \u00d6nce \u00f6nbellekte arar, bulamazsa a\u011f\u0131 dener. Statik varl\u0131klar i\u00e7in idealdir.<br \/>\n*   <strong>Network-First (A\u011f \u00d6nce):<\/strong> \u00d6nce a\u011f\u0131 dener, ba\u015far\u0131s\u0131z olursa \u00f6nbelle\u011fe bakar. En g\u00fcncel veriyi sa\u011flamak istendi\u011finde kullan\u0131l\u0131r.<br \/>\n*   <strong>Stale-While-Revalidate:<\/strong> \u00d6nbellekten hemen bir yan\u0131t d\u00f6nd\u00fcr\u00fcrken, ayn\u0131 zamanda a\u011fdan g\u00fcncel bir s\u00fcr\u00fcm \u00e7ekmeye \u00e7al\u0131\u015f\u0131r ve \u00f6nbelle\u011fi g\u00fcnceller. Kullan\u0131c\u0131ya h\u0131zl\u0131 bir yan\u0131t verirken arka planda i\u00e7eri\u011fi g\u00fcncel tutar.<br \/>\n*   <strong>Cache Only:<\/strong> Sadece \u00f6nbellekten servis eder, a\u011f\u0131 hi\u00e7 denemez. Uygulama ba\u015flat\u0131ld\u0131\u011f\u0131nda de\u011fi\u015fmeyecek varl\u0131klar i\u00e7in kullan\u0131l\u0131r.<br \/>\n*   <strong>Network Only:<\/strong> Sadece a\u011fdan servis eder, \u00f6nbelle\u011fi hi\u00e7 kullanmaz. Her zaman en g\u00fcncel veriye ihtiya\u00e7 duyulan durumlar i\u00e7in (ancak bu durumda PWA&#8217;n\u0131n \u00e7evrimd\u0131\u015f\u0131 yetene\u011fi olmaz).<\/p>\n<p>Bizim <code>service-worker.js<\/code> dosyam\u0131z, statik dosyalar i\u00e7in <code>Cache Only<\/code> (install an\u0131nda \u00f6nbelle\u011fe alma) ve dinamik i\u00e7erikler (fetch) i\u00e7in <code>Cache-First, then Network<\/code> (a\u011fdan hata al\u0131n\u0131rsa basit bir \u00e7evrimd\u0131\u015f\u0131 yan\u0131t) stratejisinin bir kombinasyonunu kullanmaktad\u0131r.<\/p>\n<h4>5. Push Bildirimleri (Opsiyonel ama \u00f6nemli)<\/h4>\n<p>Push bildirimleri, kullan\u0131c\u0131 uygulaman\u0131z\u0131 kullanm\u0131yorken bile onlara mesaj g\u00f6ndermenizi sa\u011flayan g\u00fc\u00e7l\u00fc bir etkile\u015fim arac\u0131d\u0131r. Vanilla JS ile push bildirimleri uygulamak biraz daha karma\u015f\u0131kt\u0131r \u00e7\u00fcnk\u00fc bir sunucu taraf\u0131 bile\u015feni de gerektirir (bildirimleri g\u00f6ndermek i\u00e7in). Ancak, istemci taraf\u0131ndaki ad\u0131mlar\u0131 inceleyebiliriz.<\/p>\n<p><strong><code>app.js<\/code> (Push Bildirimleri i\u00e7in ekleme):<\/strong><\/p>\n<pre><code class=\"language-javascript\">\/\/ ... Service Worker kay\u0131t kodu ...\n\n\/\/ Push Bildirimleri i\u00e7in izin isteme ve abonelik\nasync function subscribeUserToPush() {\n    if (!('PushManager' in window)) {\n        console.warn('Taray\u0131c\u0131n\u0131z Push API\\'y\u0131 desteklemiyor.');\n        return;\n    }\n\n    try {\n        const registration = await navigator.serviceWorker.ready;\n        const subscription = await registration.pushManager.subscribe({\n            userVisibleOnly: true, \/\/ Kullan\u0131c\u0131n\u0131n her bildirimi g\u00f6rmesi gerekti\u011fini belirtir\n            applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE') \/\/ Sunucunuzdan alaca\u011f\u0131n\u0131z VAPID anahtar\u0131\n        });\n        console.log('Push aboneli\u011fi ba\u015far\u0131l\u0131:', JSON.stringify(subscription));\n        \/\/ Abonelik bilgisini sunucunuza g\u00f6nderin\n        \/\/ await fetch('\/api\/subscribe', { method: 'POST', body: JSON.stringify(subscription) });\n    } catch (error) {\n        console.error('Push aboneli\u011fi ba\u015far\u0131s\u0131z:', error);\n    }\n}\n\n\/\/ Bir d\u00fc\u011fmeye t\u0131klayarak abonelik iste\u011fini tetikleyebiliriz\n\/\/ document.getElementById('subscribeButton').addEventListener('click', subscribeUserToPush);\n\n\/\/ VAPID anahtar\u0131n\u0131 do\u011fru formata d\u00f6n\u00fc\u015ft\u00fcrmek i\u00e7in yard\u0131mc\u0131 fonksiyon\nfunction urlBase64ToUint8Array(base64String) {\n    const padding = '='.repeat((4 - base64String.length % 4) % 4);\n    const base64 = (base64String + padding)\n        .replace(\/\\-\/g, '+')\n        .replace(\/_\/g, '\/');\n\n    const rawData = window.atob(base64);\n    const outputArray = new Uint8Array(rawData.length);\n\n    for (let i = 0; i < rawData.length; ++i) {\n        outputArray[i] = rawData.charCodeAt(i);\n    }\n    return outputArray;\n}\n\n\/\/ ... Di\u011fer app.js kodlar\u0131 ...<\/code><\/pre>\n<p><strong><code>service-worker.js<\/code> (Push Bildirimleri i\u00e7in ekleme):<\/strong><\/p>\n<pre><code class=\"language-javascript\">\/\/ ... Di\u011fer Service Worker kodlar\u0131 ...\n\n\/\/ Push Bildirimi alma olay\u0131\nself.addEventListener('push', event => {\n    console.log('[Service Worker] Push Bildirimi al\u0131nd\u0131.');\n    const data = event.data ? event.data.json() : { title: 'Yeni Bildirim', body: 'Push bildirim mesaj\u0131.' };\n\n    const options = {\n        body: data.body,\n        icon: '\/icons\/icon-192x192.png', \/\/ Bildirimde g\u00f6sterilecek simge\n        badge: '\/icons\/icon-72x72.png', \/\/ Mobil cihazlarda uygulama simgesinde g\u00f6sterilecek k\u00fc\u00e7\u00fck simge\n        vibrate: [200, 100, 200], \/\/ Titre\u015fim deseni\n        data: {\n            url: data.url || '\/' \/\/ Bildirime t\u0131klan\u0131nca a\u00e7\u0131lacak URL\n        },\n        actions: [ \/\/ Bildirimde g\u00f6sterilecek eylem d\u00fc\u011fmeleri\n            { action: 'explore', title: 'Ke\u015ffet', icon: '\/icons\/icon-72x72.png' },\n            { action: 'close', title: 'Kapat', icon: '\/icons\/icon-72x72.png' }\n        ]\n    };\n\n    event.waitUntil(\n        self.registration.showNotification(data.title, options)\n    );\n});\n\n\/\/ Bildirime t\u0131klama olay\u0131\nself.addEventListener('notificationclick', event => {\n    console.log('[Service Worker] Bildirime t\u0131kland\u0131:', event.notification.tag);\n    event.notification.close(); \/\/ Bildirimi kapat\n\n    event.waitUntil(\n        clients.openWindow(event.notification.data.url) \/\/ Bildirimle ili\u015fkilendirilmi\u015f URL'yi a\u00e7\n    );\n});<\/code><\/pre>\n<p>Push bildirimleri i\u00e7in bir <strong>VAPID (Voluntary Application Server Identification)<\/strong> anahtar\u0131na ihtiyac\u0131n\u0131z olacak. Bu anahtar\u0131 olu\u015fturan ve bildirimleri g\u00f6nderen bir sunucu taraf\u0131 servise sahip olman\u0131z gerekir. Bu makale Vanilla JS istemci taraf\u0131na odakland\u0131\u011f\u0131 i\u00e7in sunucu taraf\u0131 implementasyonu detaylar\u0131na girmiyoruz.<\/p>\n<h4>6. \"Ana Ekrana Ekle\" (Add to Home Screen) \u00d6zelli\u011fi<\/h4>\n<p>Bu \u00f6zellik, manifest dosyas\u0131 ve Service Worker'\u0131n varl\u0131\u011f\u0131 sayesinde taray\u0131c\u0131 taraf\u0131ndan otomatik olarak tetiklenir. Taray\u0131c\u0131, PWA kriterlerini kar\u015f\u0131layan bir siteyi ziyaret etti\u011finde kullan\u0131c\u0131ya \"Ana Ekrana Ekle\" veya benzeri bir \u00f6neri sunabilir. Kullan\u0131c\u0131 bunu kabul etti\u011finde, uygulaman\u0131z ana ekranda bir simgeyle belirir ve ba\u011f\u0131ms\u0131z bir uygulama gibi ba\u015flat\u0131labilir.<\/p>\n<h3>PWA Deneyimi \u0130\u00e7in En \u0130yi Uygulamalar<\/h3>\n<p>Bir PWA'n\u0131n sadece \u00e7al\u0131\u015fmas\u0131 de\u011fil, ayn\u0131 zamanda harika bir kullan\u0131c\u0131 deneyimi sunmas\u0131 da \u00f6nemlidir.<\/p>\n<p>*   <strong>Performans Optimizasyonu:<\/strong> H\u0131zl\u0131 y\u00fckleme s\u00fcreleri, PWA'lar\u0131n temelidir.<br \/>\n    *   <strong>Lighthouse:<\/strong> Google Lighthouse, PWA'n\u0131z\u0131n performans\u0131n\u0131, eri\u015filebilirli\u011fini, en iyi uygulamalar\u0131n\u0131 ve PWA puan\u0131n\u0131 denetlemek i\u00e7in harika bir ara\u00e7t\u0131r. D\u00fczenli olarak kullan\u0131n.<br \/>\n    *   <strong>G\u00f6rsel Optimizasyonu:<\/strong> Resimleri s\u0131k\u0131\u015ft\u0131r\u0131n, do\u011fru formatlar\u0131 (WebP) kullan\u0131n ve lazy loading uygulay\u0131n.<br \/>\n    *   <strong>Kod B\u00f6lme (Code Splitting):<\/strong> Yaln\u0131zca o anki g\u00f6r\u00fcn\u00fcm i\u00e7in gerekli olan JavaScript ve CSS'i y\u00fckleyin.<br \/>\n    *   <strong>Kritik CSS:<\/strong> Sayfan\u0131n ilk y\u00fcklenmesinde g\u00f6r\u00fcnen i\u00e7eri\u011fi (above-the-fold) h\u0131zl\u0131ca stilize etmek i\u00e7in kritik CSS'i HTML i\u00e7ine dahil edin.<br \/>\n*   <strong>G\u00fcvenlik (HTTPS):<\/strong> Daha \u00f6nce de belirtildi\u011fi gibi, HTTPS zorunludur. \u00dccretsiz SSL\/TLS sertifikalar\u0131 sa\u011flayan Let's Encrypt gibi hizmetleri kullan\u0131n.<br \/>\n*   <strong>Kullan\u0131c\u0131 Deneyimi (UX):<\/strong><br \/>\n    *   <strong>Duyarl\u0131 Tasar\u0131m:<\/strong> Uygulaman\u0131z\u0131n t\u00fcm cihazlarda iyi g\u00f6r\u00fcnmesini ve \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flay\u0131n.<br \/>\n    *   <strong>Eri\u015filebilirlik:<\/strong> Engelli kullan\u0131c\u0131lar dahil herkesin uygulaman\u0131z\u0131 kullanabilmesini sa\u011flay\u0131n. Semantik HTML, ARIA rolleri ve klavye navigasyonu \u00f6nemlidir.<br \/>\n    *   <strong>Offline Fallback:<\/strong> A\u011f ba\u011flant\u0131s\u0131 olmad\u0131\u011f\u0131nda kullan\u0131c\u0131ya ne olaca\u011f\u0131n\u0131 a\u00e7\u0131k\u00e7a belirtin veya faydal\u0131 \u00e7evrimd\u0131\u015f\u0131 i\u00e7erik sunun.<br \/>\n*   <strong>G\u00fcncelleme Stratejileri:<\/strong> Service Worker'\u0131n\u0131z\u0131n yeni s\u00fcr\u00fcmlerini nas\u0131l da\u011f\u0131taca\u011f\u0131n\u0131z\u0131 planlay\u0131n. Kullan\u0131c\u0131ya yeni bir s\u00fcr\u00fcm\u00fcn mevcut oldu\u011funu bildirebilir ve sayfay\u0131 yenilemelerini isteyebilirsiniz.<\/p>\n<h3>PWA'n\u0131n Test Edilmesi ve Da\u011f\u0131t\u0131m\u0131<\/h3>\n<p>PWA'n\u0131z\u0131 geli\u015ftirdikten sonra, d\u00fczg\u00fcn \u00e7al\u0131\u015ft\u0131\u011f\u0131ndan emin olmak i\u00e7in test etmeniz gerekir.<\/p>\n<p>*   <strong>Lighthouse Denetimleri:<\/strong> Chrome Geli\u015ftirici Ara\u00e7lar\u0131'nda bulunan Lighthouse sekmesini kullanarak PWA'n\u0131z\u0131n performans\u0131n\u0131, eri\u015filebilirli\u011fini ve PWA uyumlulu\u011funu kontrol edin. Bu size eksik veya geli\u015ftirilebilecek alanlar hakk\u0131nda de\u011ferli bilgiler verecektir.<br \/>\n*   <strong>Taray\u0131c\u0131 Geli\u015ftirici Ara\u00e7lar\u0131:<\/strong><br \/>\n    *   <strong>Application Sekmesi:<\/strong> Chrome Geli\u015ftirici Ara\u00e7lar\u0131'nda \"Application\" sekmesi alt\u0131nda Service Worker'lar\u0131, \u00f6nbellek depolamas\u0131n\u0131 ve manifest dosyas\u0131n\u0131 inceleyebilirsiniz. Service Worker'\u0131 kayd\u0131n\u0131 silebilir, g\u00fcncelleyebilir ve \u00e7evrimd\u0131\u015f\u0131 modu sim\u00fcle edebilirsiniz.<br \/>\n    *   <strong>Network Sekmesi:<\/strong> A\u011f isteklerinin Service Worker taraf\u0131ndan nas\u0131l i\u015flendi\u011fini g\u00f6rmek i\u00e7in \"Network\" sekmesini kullan\u0131n.<br \/>\n*   <strong>Farkl\u0131 Cihazlarda Test:<\/strong> Uygulaman\u0131z\u0131n farkl\u0131 taray\u0131c\u0131larda (Chrome, Firefox, Edge, Safari) ve farkl\u0131 cihazlarda (masa\u00fcst\u00fc, mobil, tablet) nas\u0131l davrand\u0131\u011f\u0131n\u0131 test edin.<br \/>\n*   <strong>HTTPS Hosting:<\/strong> PWA'n\u0131z\u0131 da\u011f\u0131tmak i\u00e7in HTTPS destekli bir bar\u0131nd\u0131rma hizmetine ihtiyac\u0131n\u0131z vard\u0131r. GitHub Pages, Netlify, Vercel, Firebase Hosting gibi bir\u00e7ok platform \u00fccretsiz veya uygun maliyetli HTTPS hosting sunar.<\/p>\n<p>### Sonu\u00e7<\/p>\n<p>Vanilla JavaScript ile Progressive Web Uygulamas\u0131 geli\u015ftirmek, modern web teknolojilerini derinlemesine anlaman\u0131n ve g\u00fc\u00e7l\u00fc, performansl\u0131, \u00e7evrimd\u0131\u015f\u0131 yetenekli uygulamalar olu\u015fturman\u0131n etkili bir yoludur. Manifest dosyas\u0131, Service Worker'lar ve HTTPS gibi temel bile\u015fenleri do\u011fru bir \u015fekilde uygulayarak, web sitenizi yerel uygulama benzeri bir deneyime d\u00f6n\u00fc\u015ft\u00fcrebilirsiniz.<\/p>\n<p>PWA'lar, kullan\u0131c\u0131 deneyimini iyile\u015ftiren, eri\u015filebilirli\u011fi art\u0131ran ve da\u011f\u0131t\u0131m kolayl\u0131\u011f\u0131 sa\u011flayan gelece\u011fin web uygulamalar\u0131d\u0131r. Bu rehberdeki ad\u0131mlar\u0131 takip ederek, kendi Vanilla JS PWA'n\u0131z\u0131 in\u015fa etmek i\u00e7in sa\u011flam bir temel atm\u0131\u015f oldunuz. \u015eimdi bu bilgiyi kullanarak yarat\u0131c\u0131l\u0131\u011f\u0131n\u0131z\u0131 konu\u015fturma ve kullan\u0131c\u0131lar\u0131n\u0131za ola\u011fan\u00fcst\u00fc web deneyimleri sunma zaman\u0131. Web'in g\u00fcc\u00fcn\u00fc mobilin rahatl\u0131\u011f\u0131yla birle\u015ftirin ve PWA'lar\u0131n sundu\u011fu s\u0131n\u0131rs\u0131z potansiyeli ke\u015ffedin!<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber\nProgressive Web Uygulamalar\u0131 (PWA&#8217;lar), modern web geli\u015ftirmenin en heyecan verici ve","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[129],"tags":[],"class_list":{"0":"post-37103","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-javascript","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber\" \/>\n<meta property=\"og:description\" content=\"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber Progressive Web Uygulamalar\u0131 (PWA&#039;lar), modern web geli\u015ftirmenin en heyecan verici ve\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-12-27T09:40:44+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber\",\"datePublished\":\"2025-12-27T09:40:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\"},\"wordCount\":2309,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"Javascript\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\",\"name\":\"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-12-27T09:40:44+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/","og_locale":"tr_TR","og_type":"article","og_title":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber","og_description":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber Progressive Web Uygulamalar\u0131 (PWA'lar), modern web geli\u015ftirmenin en heyecan verici ve","og_url":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-12-27T09:40:44+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"18 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber","datePublished":"2025-12-27T09:40:44+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/"},"wordCount":2309,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["Javascript"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/","url":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/","name":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-12-27T09:40:44+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/vanilla-javascript-ile-pwa-gelistirme-kapsamli-bir-rehber\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Vanilla JavaScript ile PWA Geli\u015ftirme: Kapsaml\u0131 Bir Rehber"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/37103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=37103"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/37103\/revisions"}],"predecessor-version":[{"id":37104,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/37103\/revisions\/37104"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=37103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=37103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=37103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}