@julien-lin/universal-pwa-templates 1.3.13 → 1.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,11 +30,15 @@ __export(index_exports, {
30
30
  laravelApiServiceWorkerTemplate: () => laravelApiServiceWorkerTemplate,
31
31
  laravelSpaServiceWorkerTemplate: () => laravelSpaServiceWorkerTemplate,
32
32
  laravelSsrServiceWorkerTemplate: () => laravelSsrServiceWorkerTemplate,
33
+ nextSsrServiceWorkerTemplate: () => nextSsrServiceWorkerTemplate,
34
+ nuxtSsrServiceWorkerTemplate: () => nuxtSsrServiceWorkerTemplate,
33
35
  phpServiceWorkerTemplate: () => phpServiceWorkerTemplate,
34
36
  placeholder: () => placeholder,
37
+ remixSsrServiceWorkerTemplate: () => remixSsrServiceWorkerTemplate,
35
38
  spaServiceWorkerTemplate: () => spaServiceWorkerTemplate,
36
39
  ssrServiceWorkerTemplate: () => ssrServiceWorkerTemplate,
37
40
  staticServiceWorkerTemplate: () => staticServiceWorkerTemplate,
41
+ svelteKitSsrServiceWorkerTemplate: () => svelteKitSsrServiceWorkerTemplate,
38
42
  symfonyApiServiceWorkerTemplate: () => symfonyApiServiceWorkerTemplate,
39
43
  symfonySpaServiceWorkerTemplate: () => symfonySpaServiceWorkerTemplate,
40
44
  wordpressServiceWorkerTemplate: () => wordpressServiceWorkerTemplate
@@ -1547,6 +1551,644 @@ if (typeof workbox !== 'undefined') {
1547
1551
  }
1548
1552
  `;
1549
1553
 
1554
+ // src/service-worker/next-ssr.ts
1555
+ var nextSsrServiceWorkerTemplate = `
1556
+ // Load Workbox from CDN
1557
+ importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.4.0/workbox-sw.js')
1558
+
1559
+ // Ensure Workbox is loaded
1560
+ if (typeof workbox !== 'undefined') {
1561
+ // Precache des assets statiques critiques
1562
+ workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
1563
+
1564
+ // ====== STATIQUES FINGERPRINTED (_next/static) ======
1565
+ // CacheFirst - Les assets fingerprints ne changent jamais
1566
+ workbox.routing.registerRoute(
1567
+ ({ url }) => url.pathname.startsWith('/_next/static/'),
1568
+ new workbox.strategies.CacheFirst({
1569
+ cacheName: 'next-static-cache',
1570
+ plugins: [
1571
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1572
+ new workbox.expiration.ExpirationPlugin({
1573
+ maxEntries: 100,
1574
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
1575
+ }),
1576
+ ],
1577
+ })
1578
+ )
1579
+
1580
+ // ====== PAGES HTML (SSR DYNAMIQUE) ======
1581
+ // NetworkFirst avec fallback pour les pages
1582
+ workbox.routing.registerRoute(
1583
+ ({ request }) => request.mode === 'navigate',
1584
+ new workbox.strategies.NetworkFirst({
1585
+ cacheName: 'next-pages-cache',
1586
+ plugins: [
1587
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1588
+ new workbox.expiration.ExpirationPlugin({
1589
+ maxEntries: 50,
1590
+ maxAgeSeconds: 24 * 60 * 60, // 24h
1591
+ }),
1592
+ ],
1593
+ networkTimeoutSeconds: 5,
1594
+ })
1595
+ )
1596
+
1597
+ // ====== ISR (Incremental Static Regeneration) ======
1598
+ // Aussi NetworkFirst pour /_next/data/** (API ISR)
1599
+ workbox.routing.registerRoute(
1600
+ ({ url }) => url.pathname.startsWith('/_next/data/'),
1601
+ new workbox.strategies.NetworkFirst({
1602
+ cacheName: 'next-isr-cache',
1603
+ plugins: [
1604
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1605
+ new workbox.expiration.ExpirationPlugin({
1606
+ maxEntries: 50,
1607
+ maxAgeSeconds: 60 * 60, // 1h
1608
+ }),
1609
+ ],
1610
+ networkTimeoutSeconds: 3,
1611
+ })
1612
+ )
1613
+
1614
+ // ====== IMAGES OPTIMIS\xC9ES (Next.js Image Optimization) ======
1615
+ workbox.routing.registerRoute(
1616
+ ({ request, url }) =>
1617
+ request.destination === 'image' || url.pathname.startsWith('/_next/image'),
1618
+ new workbox.strategies.CacheFirst({
1619
+ cacheName: 'next-images-cache',
1620
+ plugins: [
1621
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1622
+ new workbox.expiration.ExpirationPlugin({
1623
+ maxEntries: 100,
1624
+ maxAgeSeconds: 30 * 24 * 60 * 60, // 30 jours
1625
+ }),
1626
+ ],
1627
+ })
1628
+ )
1629
+
1630
+ // ====== FONTS ======
1631
+ workbox.routing.registerRoute(
1632
+ ({ request }) => request.destination === 'font',
1633
+ new workbox.strategies.CacheFirst({
1634
+ cacheName: 'next-fonts-cache',
1635
+ plugins: [
1636
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1637
+ new workbox.expiration.ExpirationPlugin({
1638
+ maxEntries: 30,
1639
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
1640
+ }),
1641
+ ],
1642
+ })
1643
+ )
1644
+
1645
+ // ====== STYLES & SCRIPTS (Non-fingerprinted) ======
1646
+ workbox.routing.registerRoute(
1647
+ ({ request }) =>
1648
+ request.destination === 'style' || request.destination === 'script',
1649
+ new workbox.strategies.StaleWhileRevalidate({
1650
+ cacheName: 'next-assets-cache',
1651
+ plugins: [
1652
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1653
+ new workbox.expiration.ExpirationPlugin({
1654
+ maxEntries: 60,
1655
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 jours
1656
+ }),
1657
+ ],
1658
+ })
1659
+ )
1660
+
1661
+ // ====== API ROUTES (/api/**) ======
1662
+ workbox.routing.registerRoute(
1663
+ ({ url, request }) =>
1664
+ request.method === 'GET' && url.pathname.startsWith('/api/'),
1665
+ new workbox.strategies.NetworkFirst({
1666
+ cacheName: 'next-api-cache',
1667
+ plugins: [
1668
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1669
+ new workbox.expiration.ExpirationPlugin({
1670
+ maxEntries: 50,
1671
+ maxAgeSeconds: 10 * 60, // 10 mins
1672
+ }),
1673
+ ],
1674
+ networkTimeoutSeconds: 5,
1675
+ })
1676
+ )
1677
+
1678
+ // ====== GRAPHQL ======
1679
+ workbox.routing.registerRoute(
1680
+ ({ url }) => url.pathname === '/graphql',
1681
+ new workbox.strategies.NetworkFirst({
1682
+ cacheName: 'next-graphql-cache',
1683
+ plugins: [
1684
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1685
+ new workbox.expiration.ExpirationPlugin({
1686
+ maxEntries: 30,
1687
+ maxAgeSeconds: 5 * 60, // 5 mins
1688
+ }),
1689
+ ],
1690
+ networkTimeoutSeconds: 4,
1691
+ })
1692
+ )
1693
+
1694
+ // ====== OFFLINE FALLBACK ======
1695
+ // Fallback pour pages non trouv\xE9es en offline
1696
+ const offlineFallbackPage = '/offline.html'
1697
+ workbox.routing.setCatchHandler(async ({ event }) => {
1698
+ if (event.request.destination === 'document') {
1699
+ return caches.match(offlineFallbackPage)
1700
+ }
1701
+ return Response.error()
1702
+ })
1703
+
1704
+ // ====== BROADCAST CACHE UPDATE ======
1705
+ // Notifier le client quand le cache est mis \xE0 jour
1706
+ workbox.core.clientsClaim()
1707
+ self.skipWaiting()
1708
+ }
1709
+ `;
1710
+
1711
+ // src/service-worker/nuxt-ssr.ts
1712
+ var nuxtSsrServiceWorkerTemplate = `
1713
+ // Load Workbox from CDN
1714
+ importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.4.0/workbox-sw.js')
1715
+
1716
+ // Ensure Workbox is loaded
1717
+ if (typeof workbox !== 'undefined') {
1718
+ // Precache des assets statiques critiques
1719
+ workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
1720
+
1721
+ // ====== NUXT STATIQUES (_nuxt/dist) ======
1722
+ // CacheFirst - Assets fingerprinted
1723
+ workbox.routing.registerRoute(
1724
+ ({ url }) => url.pathname.startsWith('/_nuxt/'),
1725
+ new workbox.strategies.CacheFirst({
1726
+ cacheName: 'nuxt-static-cache',
1727
+ plugins: [
1728
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1729
+ new workbox.expiration.ExpirationPlugin({
1730
+ maxEntries: 100,
1731
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
1732
+ }),
1733
+ ],
1734
+ })
1735
+ )
1736
+
1737
+ // ====== PAGES HTML (SSR DYNAMIQUE) ======
1738
+ workbox.routing.registerRoute(
1739
+ ({ request }) => request.mode === 'navigate',
1740
+ new workbox.strategies.NetworkFirst({
1741
+ cacheName: 'nuxt-pages-cache',
1742
+ plugins: [
1743
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1744
+ new workbox.expiration.ExpirationPlugin({
1745
+ maxEntries: 50,
1746
+ maxAgeSeconds: 24 * 60 * 60, // 24h
1747
+ }),
1748
+ ],
1749
+ networkTimeoutSeconds: 5,
1750
+ })
1751
+ )
1752
+
1753
+ // ====== PAYLOAD EXTRACTION (Nuxt content/data API) ======
1754
+ // Pour Nuxt Content ou endpoints g\xE9n\xE9r\xE9s
1755
+ workbox.routing.registerRoute(
1756
+ ({ url }) =>
1757
+ url.pathname.startsWith('/__payload') ||
1758
+ url.pathname.startsWith('/_payload'),
1759
+ new workbox.strategies.NetworkFirst({
1760
+ cacheName: 'nuxt-payload-cache',
1761
+ plugins: [
1762
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1763
+ new workbox.expiration.ExpirationPlugin({
1764
+ maxEntries: 50,
1765
+ maxAgeSeconds: 60 * 60, // 1h
1766
+ }),
1767
+ ],
1768
+ networkTimeoutSeconds: 3,
1769
+ })
1770
+ )
1771
+
1772
+ // ====== HYBRID RENDERING (Nuxt Islands) ======
1773
+ // Pour les composants islands isomorphes
1774
+ workbox.routing.registerRoute(
1775
+ ({ url }) => url.pathname.startsWith('/__nuxt_island'),
1776
+ new workbox.strategies.NetworkFirst({
1777
+ cacheName: 'nuxt-islands-cache',
1778
+ plugins: [
1779
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1780
+ new workbox.expiration.ExpirationPlugin({
1781
+ maxEntries: 60,
1782
+ maxAgeSeconds: 30 * 60, // 30 mins
1783
+ }),
1784
+ ],
1785
+ networkTimeoutSeconds: 4,
1786
+ })
1787
+ )
1788
+
1789
+ // ====== IMAGES ======
1790
+ workbox.routing.registerRoute(
1791
+ ({ request, url }) =>
1792
+ request.destination === 'image' || url.pathname.startsWith('/_image'),
1793
+ new workbox.strategies.CacheFirst({
1794
+ cacheName: 'nuxt-images-cache',
1795
+ plugins: [
1796
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1797
+ new workbox.expiration.ExpirationPlugin({
1798
+ maxEntries: 100,
1799
+ maxAgeSeconds: 30 * 24 * 60 * 60, // 30 jours
1800
+ }),
1801
+ ],
1802
+ })
1803
+ )
1804
+
1805
+ // ====== FONTS ======
1806
+ workbox.routing.registerRoute(
1807
+ ({ request }) => request.destination === 'font',
1808
+ new workbox.strategies.CacheFirst({
1809
+ cacheName: 'nuxt-fonts-cache',
1810
+ plugins: [
1811
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1812
+ new workbox.expiration.ExpirationPlugin({
1813
+ maxEntries: 30,
1814
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
1815
+ }),
1816
+ ],
1817
+ })
1818
+ )
1819
+
1820
+ // ====== STYLES & SCRIPTS ======
1821
+ workbox.routing.registerRoute(
1822
+ ({ request }) =>
1823
+ request.destination === 'style' || request.destination === 'script',
1824
+ new workbox.strategies.StaleWhileRevalidate({
1825
+ cacheName: 'nuxt-assets-cache',
1826
+ plugins: [
1827
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1828
+ new workbox.expiration.ExpirationPlugin({
1829
+ maxEntries: 60,
1830
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 jours
1831
+ }),
1832
+ ],
1833
+ })
1834
+ )
1835
+
1836
+ // ====== API ROUTES (/api/**) ======
1837
+ workbox.routing.registerRoute(
1838
+ ({ url, request }) =>
1839
+ request.method === 'GET' && url.pathname.startsWith('/api/'),
1840
+ new workbox.strategies.NetworkFirst({
1841
+ cacheName: 'nuxt-api-cache',
1842
+ plugins: [
1843
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1844
+ new workbox.expiration.ExpirationPlugin({
1845
+ maxEntries: 50,
1846
+ maxAgeSeconds: 10 * 60, // 10 mins
1847
+ }),
1848
+ ],
1849
+ networkTimeoutSeconds: 5,
1850
+ })
1851
+ )
1852
+
1853
+ // ====== GRAPHQL ======
1854
+ workbox.routing.registerRoute(
1855
+ ({ url }) => url.pathname === '/graphql',
1856
+ new workbox.strategies.NetworkFirst({
1857
+ cacheName: 'nuxt-graphql-cache',
1858
+ plugins: [
1859
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1860
+ new workbox.expiration.ExpirationPlugin({
1861
+ maxEntries: 30,
1862
+ maxAgeSeconds: 5 * 60, // 5 mins
1863
+ }),
1864
+ ],
1865
+ networkTimeoutSeconds: 4,
1866
+ })
1867
+ )
1868
+
1869
+ // ====== OFFLINE FALLBACK ======
1870
+ const offlineFallbackPage = '/offline.html'
1871
+ workbox.routing.setCatchHandler(async ({ event }) => {
1872
+ if (event.request.destination === 'document') {
1873
+ return caches.match(offlineFallbackPage)
1874
+ }
1875
+ return Response.error()
1876
+ })
1877
+
1878
+ // ====== BROADCAST CACHE UPDATE ======
1879
+ workbox.core.clientsClaim()
1880
+ self.skipWaiting()
1881
+ }
1882
+ `;
1883
+
1884
+ // src/service-worker/remix-ssr.ts
1885
+ var remixSsrServiceWorkerTemplate = `
1886
+ // Load Workbox from CDN
1887
+ importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.4.0/workbox-sw.js')
1888
+
1889
+ // Ensure Workbox is loaded
1890
+ if (typeof workbox !== 'undefined') {
1891
+ // Precache des assets statiques critiques
1892
+ workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
1893
+
1894
+ // ====== REMIX STATIQUES (/build) ======
1895
+ // CacheFirst - Assets fingerprinted
1896
+ workbox.routing.registerRoute(
1897
+ ({ url }) => url.pathname.startsWith('/build/'),
1898
+ new workbox.strategies.CacheFirst({
1899
+ cacheName: 'remix-static-cache',
1900
+ plugins: [
1901
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1902
+ new workbox.expiration.ExpirationPlugin({
1903
+ maxEntries: 100,
1904
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
1905
+ }),
1906
+ ],
1907
+ })
1908
+ )
1909
+
1910
+ // ====== PAGES HTML (SSR DYNAMIQUE) ======
1911
+ workbox.routing.registerRoute(
1912
+ ({ request }) => request.mode === 'navigate',
1913
+ new workbox.strategies.NetworkFirst({
1914
+ cacheName: 'remix-pages-cache',
1915
+ plugins: [
1916
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1917
+ new workbox.expiration.ExpirationPlugin({
1918
+ maxEntries: 50,
1919
+ maxAgeSeconds: 24 * 60 * 60, // 24h
1920
+ }),
1921
+ ],
1922
+ networkTimeoutSeconds: 5,
1923
+ })
1924
+ )
1925
+
1926
+ // ====== REMIX RESOURCE ROUTES (/resource/**) ======
1927
+ workbox.routing.registerRoute(
1928
+ ({ url }) => url.pathname.startsWith('/resource/'),
1929
+ new workbox.strategies.NetworkFirst({
1930
+ cacheName: 'remix-resources-cache',
1931
+ plugins: [
1932
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1933
+ new workbox.expiration.ExpirationPlugin({
1934
+ maxEntries: 50,
1935
+ maxAgeSeconds: 60 * 60, // 1h
1936
+ }),
1937
+ ],
1938
+ networkTimeoutSeconds: 4,
1939
+ })
1940
+ )
1941
+
1942
+ // ====== IMAGES ======
1943
+ workbox.routing.registerRoute(
1944
+ ({ request, url }) =>
1945
+ request.destination === 'image',
1946
+ new workbox.strategies.CacheFirst({
1947
+ cacheName: 'remix-images-cache',
1948
+ plugins: [
1949
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1950
+ new workbox.expiration.ExpirationPlugin({
1951
+ maxEntries: 100,
1952
+ maxAgeSeconds: 30 * 24 * 60 * 60, // 30 jours
1953
+ }),
1954
+ ],
1955
+ })
1956
+ )
1957
+
1958
+ // ====== FONTS ======
1959
+ workbox.routing.registerRoute(
1960
+ ({ request }) => request.destination === 'font',
1961
+ new workbox.strategies.CacheFirst({
1962
+ cacheName: 'remix-fonts-cache',
1963
+ plugins: [
1964
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1965
+ new workbox.expiration.ExpirationPlugin({
1966
+ maxEntries: 30,
1967
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
1968
+ }),
1969
+ ],
1970
+ })
1971
+ )
1972
+
1973
+ // ====== STYLES & SCRIPTS ======
1974
+ workbox.routing.registerRoute(
1975
+ ({ request }) =>
1976
+ request.destination === 'style' || request.destination === 'script',
1977
+ new workbox.strategies.StaleWhileRevalidate({
1978
+ cacheName: 'remix-assets-cache',
1979
+ plugins: [
1980
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1981
+ new workbox.expiration.ExpirationPlugin({
1982
+ maxEntries: 60,
1983
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 jours
1984
+ }),
1985
+ ],
1986
+ })
1987
+ )
1988
+
1989
+ // ====== API ROUTES (/api/**) ======
1990
+ workbox.routing.registerRoute(
1991
+ ({ url, request }) =>
1992
+ request.method === 'GET' && url.pathname.startsWith('/api/'),
1993
+ new workbox.strategies.NetworkFirst({
1994
+ cacheName: 'remix-api-cache',
1995
+ plugins: [
1996
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
1997
+ new workbox.expiration.ExpirationPlugin({
1998
+ maxEntries: 50,
1999
+ maxAgeSeconds: 10 * 60, // 10 mins
2000
+ }),
2001
+ ],
2002
+ networkTimeoutSeconds: 5,
2003
+ })
2004
+ )
2005
+
2006
+ // ====== GRAPHQL ======
2007
+ workbox.routing.registerRoute(
2008
+ ({ url }) => url.pathname === '/graphql',
2009
+ new workbox.strategies.NetworkFirst({
2010
+ cacheName: 'remix-graphql-cache',
2011
+ plugins: [
2012
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2013
+ new workbox.expiration.ExpirationPlugin({
2014
+ maxEntries: 30,
2015
+ maxAgeSeconds: 5 * 60, // 5 mins
2016
+ }),
2017
+ ],
2018
+ networkTimeoutSeconds: 4,
2019
+ })
2020
+ )
2021
+
2022
+ // ====== OFFLINE FALLBACK ======
2023
+ const offlineFallbackPage = '/offline.html'
2024
+ workbox.routing.setCatchHandler(async ({ event }) => {
2025
+ if (event.request.destination === 'document') {
2026
+ return caches.match(offlineFallbackPage)
2027
+ }
2028
+ return Response.error()
2029
+ })
2030
+
2031
+ // ====== BROADCAST CACHE UPDATE ======
2032
+ workbox.core.clientsClaim()
2033
+ self.skipWaiting()
2034
+ }
2035
+ `;
2036
+
2037
+ // src/service-worker/sveltekit-ssr.ts
2038
+ var svelteKitSsrServiceWorkerTemplate = `
2039
+ // Load Workbox from CDN
2040
+ importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.4.0/workbox-sw.js')
2041
+
2042
+ // Ensure Workbox is loaded
2043
+ if (typeof workbox !== 'undefined') {
2044
+ // Precache des assets statiques critiques
2045
+ workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
2046
+
2047
+ // ====== SVELTEKIT STATIQUES (/_app) ======
2048
+ // CacheFirst - Assets fingerprinted
2049
+ workbox.routing.registerRoute(
2050
+ ({ url }) => url.pathname.startsWith('/_app/'),
2051
+ new workbox.strategies.CacheFirst({
2052
+ cacheName: 'sveltekit-static-cache',
2053
+ plugins: [
2054
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2055
+ new workbox.expiration.ExpirationPlugin({
2056
+ maxEntries: 100,
2057
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
2058
+ }),
2059
+ ],
2060
+ })
2061
+ )
2062
+
2063
+ // ====== PAGES HTML (SSR DYNAMIQUE) ======
2064
+ workbox.routing.registerRoute(
2065
+ ({ request }) => request.mode === 'navigate',
2066
+ new workbox.strategies.NetworkFirst({
2067
+ cacheName: 'sveltekit-pages-cache',
2068
+ plugins: [
2069
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2070
+ new workbox.expiration.ExpirationPlugin({
2071
+ maxEntries: 50,
2072
+ maxAgeSeconds: 24 * 60 * 60, // 24h
2073
+ }),
2074
+ ],
2075
+ networkTimeoutSeconds: 5,
2076
+ })
2077
+ )
2078
+
2079
+ // ====== LAYOUT & COMPONENT DATA ======
2080
+ // Pour les donn\xE9es de layout et composants
2081
+ workbox.routing.registerRoute(
2082
+ ({ url }) =>
2083
+ url.pathname.startsWith('/__data/') ||
2084
+ url.pathname.endsWith('.json'),
2085
+ new workbox.strategies.NetworkFirst({
2086
+ cacheName: 'sveltekit-data-cache',
2087
+ plugins: [
2088
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2089
+ new workbox.expiration.ExpirationPlugin({
2090
+ maxEntries: 50,
2091
+ maxAgeSeconds: 60 * 60, // 1h
2092
+ }),
2093
+ ],
2094
+ networkTimeoutSeconds: 4,
2095
+ })
2096
+ )
2097
+
2098
+ // ====== IMAGES ======
2099
+ workbox.routing.registerRoute(
2100
+ ({ request }) => request.destination === 'image',
2101
+ new workbox.strategies.CacheFirst({
2102
+ cacheName: 'sveltekit-images-cache',
2103
+ plugins: [
2104
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2105
+ new workbox.expiration.ExpirationPlugin({
2106
+ maxEntries: 100,
2107
+ maxAgeSeconds: 30 * 24 * 60 * 60, // 30 jours
2108
+ }),
2109
+ ],
2110
+ })
2111
+ )
2112
+
2113
+ // ====== FONTS ======
2114
+ workbox.routing.registerRoute(
2115
+ ({ request }) => request.destination === 'font',
2116
+ new workbox.strategies.CacheFirst({
2117
+ cacheName: 'sveltekit-fonts-cache',
2118
+ plugins: [
2119
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2120
+ new workbox.expiration.ExpirationPlugin({
2121
+ maxEntries: 30,
2122
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 1 an
2123
+ }),
2124
+ ],
2125
+ })
2126
+ )
2127
+
2128
+ // ====== STYLES & SCRIPTS ======
2129
+ workbox.routing.registerRoute(
2130
+ ({ request }) =>
2131
+ request.destination === 'style' || request.destination === 'script',
2132
+ new workbox.strategies.StaleWhileRevalidate({
2133
+ cacheName: 'sveltekit-assets-cache',
2134
+ plugins: [
2135
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2136
+ new workbox.expiration.ExpirationPlugin({
2137
+ maxEntries: 60,
2138
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 jours
2139
+ }),
2140
+ ],
2141
+ })
2142
+ )
2143
+
2144
+ // ====== API ROUTES (/api/**) ======
2145
+ workbox.routing.registerRoute(
2146
+ ({ url, request }) =>
2147
+ request.method === 'GET' && url.pathname.startsWith('/api/'),
2148
+ new workbox.strategies.NetworkFirst({
2149
+ cacheName: 'sveltekit-api-cache',
2150
+ plugins: [
2151
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2152
+ new workbox.expiration.ExpirationPlugin({
2153
+ maxEntries: 50,
2154
+ maxAgeSeconds: 10 * 60, // 10 mins
2155
+ }),
2156
+ ],
2157
+ networkTimeoutSeconds: 5,
2158
+ })
2159
+ )
2160
+
2161
+ // ====== GRAPHQL ======
2162
+ workbox.routing.registerRoute(
2163
+ ({ url }) => url.pathname === '/graphql',
2164
+ new workbox.strategies.NetworkFirst({
2165
+ cacheName: 'sveltekit-graphql-cache',
2166
+ plugins: [
2167
+ new workbox.cacheableResponse.CacheableResponsePlugin({ statuses: [0, 200] }),
2168
+ new workbox.expiration.ExpirationPlugin({
2169
+ maxEntries: 30,
2170
+ maxAgeSeconds: 5 * 60, // 5 mins
2171
+ }),
2172
+ ],
2173
+ networkTimeoutSeconds: 4,
2174
+ })
2175
+ )
2176
+
2177
+ // ====== OFFLINE FALLBACK ======
2178
+ const offlineFallbackPage = '/offline.html'
2179
+ workbox.routing.setCatchHandler(async ({ event }) => {
2180
+ if (event.request.destination === 'document') {
2181
+ return caches.match(offlineFallbackPage)
2182
+ }
2183
+ return Response.error()
2184
+ })
2185
+
2186
+ // ====== BROADCAST CACHE UPDATE ======
2187
+ workbox.core.clientsClaim()
2188
+ self.skipWaiting()
2189
+ }
2190
+ `;
2191
+
1550
2192
  // src/service-worker/index.ts
1551
2193
  function getServiceWorkerTemplate(type) {
1552
2194
  const templates = {
@@ -1563,7 +2205,11 @@ function getServiceWorkerTemplate(type) {
1563
2205
  "django-spa": djangoSpaServiceWorkerTemplate,
1564
2206
  "django-api": djangoApiServiceWorkerTemplate,
1565
2207
  "flask-spa": flaskSpaServiceWorkerTemplate,
1566
- "flask-api": flaskApiServiceWorkerTemplate
2208
+ "flask-api": flaskApiServiceWorkerTemplate,
2209
+ "next-ssr": nextSsrServiceWorkerTemplate,
2210
+ "nuxt-ssr": nuxtSsrServiceWorkerTemplate,
2211
+ "remix-ssr": remixSsrServiceWorkerTemplate,
2212
+ "sveltekit-ssr": svelteKitSsrServiceWorkerTemplate
1567
2213
  };
1568
2214
  const content = templates[type];
1569
2215
  if (!content) {
@@ -1589,43 +2235,45 @@ function getAvailableTemplateTypes() {
1589
2235
  "django-spa",
1590
2236
  "django-api",
1591
2237
  "flask-spa",
1592
- "flask-api"
2238
+ "flask-api",
2239
+ "next-ssr",
2240
+ "nuxt-ssr",
2241
+ "remix-ssr",
2242
+ "sveltekit-ssr"
1593
2243
  ];
1594
2244
  }
1595
2245
  function determineTemplateType(architecture, framework) {
1596
- if (framework === "WordPress" || framework === "WooCommerce") {
2246
+ const f = framework?.toLowerCase() ?? "";
2247
+ if (f === "wordpress" || f === "woocommerce") {
1597
2248
  return "wordpress";
1598
2249
  }
1599
- if (framework === "Drupal" || framework === "Joomla" || framework === "Magento" || framework === "Shopify" || framework === "PrestaShop") {
2250
+ if (f === "drupal" || f === "joomla" || f === "magento" || f === "shopify" || f === "prestashop") {
1600
2251
  return "php";
1601
2252
  }
1602
- if (framework === "Symfony") {
2253
+ if (f === "symfony") {
1603
2254
  return architecture === "spa" ? "symfony-spa" : "symfony-api";
1604
2255
  }
1605
- if (framework === "CodeIgniter" || framework === "CakePHP" || framework === "Yii" || framework === "Laminas") {
2256
+ if (f === "codeigniter" || f === "cakephp" || f === "yii" || f === "laminas") {
1606
2257
  return "php";
1607
2258
  }
1608
- if (framework === "Laravel") {
1609
- if (architecture === "spa") {
1610
- return "laravel-spa";
1611
- }
1612
- if (architecture === "ssr") {
1613
- return "laravel-ssr";
1614
- }
2259
+ if (f === "laravel") {
2260
+ if (architecture === "spa") return "laravel-spa";
2261
+ if (architecture === "ssr") return "laravel-ssr";
1615
2262
  return "laravel-api";
1616
2263
  }
1617
- if (framework === "Django") {
2264
+ if (f === "django") {
1618
2265
  return architecture === "spa" ? "django-spa" : "django-api";
1619
2266
  }
1620
- if (framework === "Flask") {
2267
+ if (f === "flask") {
1621
2268
  return architecture === "spa" ? "flask-spa" : "flask-api";
1622
2269
  }
1623
- if (architecture === "spa") {
1624
- return "spa";
1625
- }
1626
- if (architecture === "ssr") {
1627
- return "ssr";
1628
- }
2270
+ if (f === "nextjs" && architecture === "ssr") return "next-ssr";
2271
+ if (f === "nuxt" && architecture === "ssr") return "nuxt-ssr";
2272
+ if (f === "remix" && architecture === "ssr") return "remix-ssr";
2273
+ if (f === "sveltekit" && architecture === "ssr") return "sveltekit-ssr";
2274
+ if (f === "astro" && architecture === "ssr") return "ssr";
2275
+ if (architecture === "spa") return "spa";
2276
+ if (architecture === "ssr") return "ssr";
1629
2277
  return "static";
1630
2278
  }
1631
2279
 
@@ -1643,11 +2291,15 @@ var placeholder = true;
1643
2291
  laravelApiServiceWorkerTemplate,
1644
2292
  laravelSpaServiceWorkerTemplate,
1645
2293
  laravelSsrServiceWorkerTemplate,
2294
+ nextSsrServiceWorkerTemplate,
2295
+ nuxtSsrServiceWorkerTemplate,
1646
2296
  phpServiceWorkerTemplate,
1647
2297
  placeholder,
2298
+ remixSsrServiceWorkerTemplate,
1648
2299
  spaServiceWorkerTemplate,
1649
2300
  ssrServiceWorkerTemplate,
1650
2301
  staticServiceWorkerTemplate,
2302
+ svelteKitSsrServiceWorkerTemplate,
1651
2303
  symfonyApiServiceWorkerTemplate,
1652
2304
  symfonySpaServiceWorkerTemplate,
1653
2305
  wordpressServiceWorkerTemplate