π¦ plugin-pwa
Workboxλ₯Ό μ¬μ©ν΄ PWA μ§μμ μΆκ°ν μ μλ λνμ¬μ°λ£¨μ€ νλ¬κ·ΈμΈμ λλ€. μ ν λΉλμλ§ μλΉμ€ μ컀λ₯Ό λ§λ€μ΄μ£Όλ νλ¬κ·ΈμΈμ λλ€. μ΄λ₯Ό ν΅ν΄ μ€νλΌμΈμμ μ€νν μ μκ³ μ€μΉλ μ§μνλ μμ ν PWA νΈν λ¬Έμλ₯Ό λ§λ€ μ μμ΅λλ€.
μ€μΉβ
- npm
- Yarn
- pnpm
npm install --save @docusaurus/plugin-pwa
yarn add @docusaurus/plugin-pwa
pnpm add @docusaurus/plugin-pwa
μ€μ β
./static/manifest.json
νμΌμ PWA 맀λνμ€νΈλ₯Ό μμ±ν©λλ€.
docusaurus.config.js
μ νμν PWA μ€μ μ μΆκ°ν©λλ€.
module.exports = {
plugins: [
[
'@docusaurus/plugin-pwa',
{
debug: true,
offlineModeActivationStrategies: [
'appInstalled',
'standalone',
'queryString',
],
pwaHead: [
{
tagName: 'link',
rel: 'icon',
href: '/img/docusaurus.png',
},
{
tagName: 'link',
rel: 'manifest',
href: '/manifest.json', // your PWA manifest
},
{
tagName: 'meta',
name: 'theme-color',
content: 'rgb(37, 194, 160)',
},
],
},
],
],
};
νλ‘κ·Έλ μλΈ μΉ μ±β
μλΉμ€ μ컀λ₯Ό μ€μΉνλ κ²λ§μΌλ‘ μ¬λ¬λΆμ μ ν리μΌμ΄μ
μ΄ PWAκ° λλ 건 μλλλ€. μ΅μν μΉ μ± λ§€λνμ€νΈλ₯Ό κ°μ§κ³ μμ΄μΌ νλ©° <head>
νκ·Έ μμ μ μ ν νκ·Έκ° ν¬ν¨λμ΄ μμ΄μΌ ν©λλ€ (Options > pwaHead).
λ°°ν¬ νμλ Lighthouseλ₯Ό μ¬μ©ν΄ μ¬λ¬λΆμ μ¬μ΄νΈλ₯Ό μ κ²ν μ μμ΅λλ€.
μ¬λ¬λΆμ μ¬μ΄νΈκ° PWAκ° λκΈ° μν΄ νμν μ’ λ μμΈν λ΄μ©μ PWA 체ν¬λ¦¬μ€νΈλ₯Ό μ°Έκ³ νμΈμ.
μ± μ€μΉ μ§μβ
μ¬λ¬λΆμ λΈλΌμ°μ κ° μ§μνλ€λ©΄ λνμ¬μ°λ£¨μ€ μ¬μ΄νΈλ₯Ό μ±μ²λΌ μ€μΉν μ μμ΅λλ€.
μ± μ€μΉλ₯Ό μ§μνλ €λ©΄ HTTPS νλ‘ν μ½μ μ¬μ©ν΄μΌ νλ©° μ ν¨ν 맀λνμ€νΈκ° νμν©λλ€.
μ€νλΌμΈ λͺ¨λ(precaching)β
μλΉμ€ μ컀 μ¬μ μΊμ±μ μ¬μ©ν΄ λνμ¬μ°λ£¨μ€ μ¬μ΄νΈλ₯Ό μ€νλΌμΈμμ μ¬μ©μκ° νμν μ μμ΅λλ€.
workbox-precaching νμ΄μ§μμ μλμ κ°μ΄ μ€λͺ νκ³ μμ΅λλ€.
μλΉμ€ μ컀μ κΈ°λ₯ μ€ νλλ‘ μλΉμ€ μ컀 μ€μΉ μ μΊμ μ²λ¦¬ν νμΌ λ¬Άμμ μ μ₯ν΄λμ μ μμ΅λλ€. μλΉμ€ μμ»€κ° μ¬μ©λκΈ° μ μ μ½ν μΈ λ₯Ό μΊμ μ²λ¦¬νκΈ° λλ¬Έμ "μ¬μ μΊμ±"μ΄λΌκ³ λΆλ¦ λλ€.
μ΄λ κ² μ²λ¦¬νλ μ΄μ λ κ°λ°μμκ² μΊμλ₯Ό μ μ΄ν μ μλ κΆνμ μ£ΌκΈ° μν¨μ λλ€. κ°λ°μλ μΊμλ₯Ό μΈμ λ§λ€κ³ μΌλ§λ μ€λ 보κ΄ν μ§ κ²°μ ν μ μμ λΏ μλ λΌ λ€νΈμν¬λ₯Ό κ±°μΉμ§ μκ³ λΈλΌμ°μ μμ λ°λ‘ μλΉμ€λ₯Ό μ 곡ν μ μμ΅λλ€. μ¦ μ€νλΌμΈμμ λμν μ μλ μΉ μ±μ λ§λ€ μ μλ€λ κ²λλ€.
Workboxλ APIλ₯Ό λ¨μννκ³ ν¨μ¨μ μΌλ‘ νμν νμΌμ λ΄λ €λ°μ μ μκ² λ§λ€μ΄ μ¬μ μΊμ± μμ μ μ½κ² μ κ·Όν μ μλλ‘ μ§μν©λλ€.
κΈ°λ³Έμ μΌλ‘ μ€νλΌμΈ λͺ¨λλ μ¬μ΄νΈκ° μ±μΌλ‘ μ€μΉλλ©΄ νμ±νλ©λλ€. μμΈν λ΄μ©μ offlineModeActivationStrategies
μ΅μ
μ€λͺ
μ μ°Έκ³ νμΈμ.
μ¬μ΄νΈ μ¬μ μΊμ± μ΄νμ μλΉμ€ μ컀λ λ°©λ¬Έμμκ² μΊμλ μλ΅μ μ 곡ν©λλ€. μλ‘μ΄ λΉλκ° μλ‘μ΄ μλΉμ€ μ컀μ ν¨κ» λ°°ν¬λλ©΄ μλ‘μ΄ μ±μ΄ μ€μΉλκ³ λκΈ° μνλ‘ μ΄λνκ² λ©λλ€. λκΈ° μνμ λ€μ΄κ°λ©΄ 리λ‘λ νμ
μ΄ νμλκ³ μ¬μ©μμκ² μλ‘μ΄ μ½ν
μΈ λ₯Ό μν΄ νμ΄μ§λ₯Ό 리λ‘λν κ²μΈμ§ λ¬Όμ΄λ΄
λλ€. μ¬μ©μκ° μ ν리μΌμ΄μ
μΊμλ₯Ό μμ νκ±°λ νμ
μμ reload
λ²νΌμ ν΄λ¦ν λκΉμ§ μλΉμ€ μ컀λ κΈ°μ‘΄ μ½ν
μΈ λ₯Ό μ 곡ν©λλ€.
μ€νλΌμΈ λͺ¨λλ μ¬μ μΊμ±μ μ¬μ΄νΈμ λͺ¨λ μ μ μ 미리 λ΄λ €λ°μμΌ νλ©° λΆνμν λμνμ μ¬μ©ν μ μμ΅λλ€. λͺ¨λ μ’ λ₯μ μ¬μ΄νΈμμ 무쑰건 ν΄λΉ κΈ°λ₯μ νμ±ννλ 건 μ’μ μκ°μ μλλλ€.
μ΅μ β
debug
β
- Type:
boolean
- Default:
false
μλμ κ°μ λλ²κ·Έ λͺ¨λλ₯Ό μ€μ ν©λλ€.
- Workbox λ‘κ·Έ
- μΆκ°μ μΈ λνμ¬μ°λ£¨μ€ λ‘κ·Έ
- μ΅μ νλμ§ λͺ»ν SW νμΌ μΆλ ₯
- μμ€λ§΅
offlineModeActivationStrategies
β
- Type:
('appInstalled' | 'mobile' | 'saveData'| 'queryString' | 'always')[]
- Default:
['appInstalled', 'queryString', 'standalone']
μ€νλΌμΈ λͺ¨λλ₯Ό μ μ©ν μνμ λν μ΅μ μ μ€μ ν©λλ€.
appInstalled
: μ¬μ©μκ° μ¬μ΄νΈλ₯Ό μ±μΌλ‘ μ€μΉν κ²½μ° νμ±ν(100% μ λ’°ν μλ μμ΅λλ€)standalone
: μ¬μ©μκ° μ±μ λ 립μ μΌλ‘ μ€νν κ²½μ° νμ±ν(PWAκ° μ€μΉλ κ²½μ°)queryString
: queryStringμofflineMode=true
κ° ν¬ν¨λ κ²½μ° νμ±ν(PWA λλ²κΉ μ μ μ©ν©λλ€)mobile
: λͺ¨λ°μΌ μ¬μ©μμΈ κ²½μ° νμ±ν(width <= 996px
)saveData
:navigator.connection.saveData === true
λ‘ μ€μ ν κ²½μ° νμ±νalways
: λͺ¨λ μ¬μ©μ νμ±ν
μ£Όμν΄μ μ¬μ©ν΄μ£ΌμΈμ. μΌλΆ μ¬μ©μλ μ€νλΌμΈ λͺ¨λλ‘ μ¬μ©νλλ‘ κ°μ λλ κ²μ μ«μ΄ν μλ μμ΅λλ€.
λ§€μ° μμ μ μΈ λ°©μμΌλ‘ PWAλ₯Ό κ°μ§νλ κ²μ λΆκ°λ₯ν©λλ€.
appinstalled
μ΄λ²€νΈκ° μ€νμμ μ κ±°λλ©΄μ μ΅μ ν¬λ‘¬ λ²μ μμλ navigator.getInstalledRelatedApps()
APIλ§ μ§μνκ³ μμ΅λλ€. μ΄λ₯Ό μ¬μ©νλ €λ©΄ 맀λνμ€νΈμμ related_applications
λ₯Ό μ μΈν΄μ£Όμ΄μΌ ν©λλ€.
standalone
μ λ΅μ μ¬μ©νλ κ²μ΄ μ€νλΌμΈ λͺ¨λλ₯Ό νμ±ννλ μ’μ λμμ
λλ€(μ€μΉλ μ±μ μ€ννλ κ²½μ°).
injectManifestConfig
β
workbox.injectManifest()
μ μ λ¬ν Workbox μ΅μ
μ μ€μ ν©λλ€. ν리μΊμ±μ μ μ©νκ³ μ€νλΌμΈμμ μ¬μ©ν μ μλ μ μ
μ μ§μ μ€μ ν μ μμ΅λλ€.
- Type:
InjectManifestOptions
- Default:
{}
module.exports = {
plugins: [
[
'@docusaurus/plugin-pwa',
{
injectManifestConfig: {
manifestTransforms: [
//...
],
modifyURLPrefix: {
//...
},
// μΌλ°μ μΌλ‘ μ¬μ©νλ μ μ μ μ
(HTML, μ΄λ―Έμ§ λ±)μ μ€νλΌμΈμμ μ¬μ©ν μ μλλ‘
// κΈ°λ³Έμ μΌλ‘ μΆκ°νμ΅λλ€. μΆκ°λ‘ νμν νμΌλ§ μ€μ ν΄μ€λλ€.
globPatterns: ['**/*.{pdf,docx,xlsx}'],
// ...
},
},
],
],
};
pwaHead
β
- Type:
({ tagName: string; [attributeName: string]: string })[]
- Default:
[]
<head>
νκ·Έ λ΄μ μ½μ
ν tagName
κ³Ό ν€, κ° μμ ν¬ν¨νλ μ€λΈμ νΈ λ°°μ΄μ μ€μ ν©λλ€. κΈ°μ μ μΌλ‘ μ΄λ€ head νκ·Έ λ μ½μ
ν μ μμ§λ§ μ¬λ¬λΆμ μ¬μ΄νΈ PWAμ μ ν©ν νκ·Έλ₯Ό μ¬μ©νλ κ²μ΄ μ΄μμ μ
λλ€. μλ λͺ©λ‘μ μ¬λ¬λΆμ μ±μ μ ν©ν νκ·Έ λͺ©λ‘μ
λλ€.
module.exports = {
plugins: [
[
'@docusaurus/plugin-pwa',
{
pwaHead: [
{
tagName: 'link',
rel: 'icon',
href: '/img/docusaurus.png',
},
{
tagName: 'link',
rel: 'manifest',
href: '/manifest.json',
},
{
tagName: 'meta',
name: 'theme-color',
content: 'rgb(37, 194, 160)',
},
{
tagName: 'meta',
name: 'apple-mobile-web-app-capable',
content: 'yes',
},
{
tagName: 'meta',
name: 'apple-mobile-web-app-status-bar-style',
content: '#000',
},
{
tagName: 'link',
rel: 'apple-touch-icon',
href: '/img/docusaurus.png',
},
{
tagName: 'link',
rel: 'mask-icon',
href: '/img/docusaurus.svg',
color: 'rgb(37, 194, 160)',
},
{
tagName: 'meta',
name: 'msapplication-TileImage',
content: '/img/docusaurus.png',
},
{
tagName: 'meta',
name: 'msapplication-TileColor',
content: '#000',
},
],
},
],
],
};
swCustom
β
- Type:
string | undefined
- Default:
undefined
Workboxμ μ μ©ν κ·μΉ μΆκ° μ μ μ©ν μ€μ μ λλ€. μλΉμ€ μ컀μ λͺ¨λ κΈ°λ₯κ³Ό ν¨κ» Workbox λΌμ΄λΈλ¬λ¦¬μ κ°λ ₯ν μΆκ° κΈ°λ₯μ μ¬μ©ν μ μμ΅λλ€. νΈλμ€νμΌλ μ½λμ΄λ©° μ΅μ ES6+ ꡬ문μ μ¬μ©ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄ μΈλΆ κ²½λ‘μ μλ νμΌμ μΊμνλ κ²½μ°μλ μλμ κ°μ΄ μ¬μ©ν©λλ€.
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
// default fn export receiving some useful params
export default function swCustom(params) {
const {
debug, // :boolean
offlineMode, // :boolean
} = params;
// Cache responses from external resources
registerRoute((context) => {
return [
/graph\.facebook\.com\/.*\/picture/,
/netlify\.com\/img/,
/avatars1\.githubusercontent/,
].some((regex) => context.url.href.match(regex));
}, new StaleWhileRevalidate());
}
λͺ¨λμ default
λ΄λ³΄λ΄κΈ° ν¨μλ₯Ό κ°μ§κ³ μμ΄μΌ νλ©° μΌλΆ 맀κ°λ³μλ₯Ό λ°μμΌ ν©λλ€.
swRegister
β
- Type:
string | false
- Default:
'docusaurus-plugin-pwa/src/registerSW.js'
μ±μ΄ μ€ννκΈ° μ μ λ±λ‘μ΄ μ²λ¦¬λλλ‘ λνμ¬μ°λ£¨μ€ μ± μμ νλͺ©μ μΆκ°ν©λλ€. κΈ°λ³Έ registerSW.js
νμΌμ κ°λ¨ν λ±λ‘μ μν μΆ©λΆν μ€μ μ ν¬ν¨ν©λλ€.
false
λ‘ μ€μ νλ©΄ λ±λ‘μ μ²λ¦¬ν μ μμ΅λλ€.
맀λνμ€νΈ μβ
λνμ¬μ°λ£¨μ€ μ¬μ΄νΈ 맀λνμ€νΈλ₯Ό μ°Έκ³ νμΈμ.
{
"name": "Docusaurus v2",
"short_name": "Docusaurus",
"theme_color": "#2196f3",
"background_color": "#424242",
"display": "standalone",
"scope": "./",
"start_url": "./index.html",
"related_applications": [
{
"platform": "webapp",
"url": "https://docusaurus.io/manifest.json"
}
],
"icons": [
{
"src": "img/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "img/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "img/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "img/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "img/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "img/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "img/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "img/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
μ¬μ©μ μ§μ μλ‘κ³ μΉ¨ νμ β
μλ‘μ΄ μλΉμ€ μμ»€κ° μ€μΉλκΈ°λ₯Ό κΈ°λ€λ¦΄ λ @theme/PwaReloadPopup
μ»΄ν¬λνΈκ° νμλλ©° μ¬μ©μμκ² λ¦¬λ‘λλ₯Ό μλ΄ν©λλ€. ν΄λΉ μ»΄ν¬λνΈλ₯Ό μ€μμ¦ν΄μ μ¬λ¬λΆλ§μ UIλ₯Ό ꡬνν μ μμ΅λλ€. reload
λ²νΌμ ν΄λ¦ν λ νΈμΆλμ΄μΌ νλ μμ±μΌλ‘ onReload
μ½λ°±μ μμ ν©λλ€. κ·Έλ¦¬κ³ κΈ°λ€λ¦¬κ³ μλ μλΉμ€ μ컀μκ² μ€μΉλ₯Ό μ§ννκ³ νμ΄μ§λ₯Ό 리λ‘λνλλ‘ μ λ¬ν©λλ€.
κΈ°λ³Έ ν λ§λ 리λ‘λ νμ μ΄ κ΅¬νλμ΄ μμΌλ©° Infima Alertsμ μ¬μ©ν©λλ€.
μ¬λ¬λΆμ μ»΄ν¬λνΈκ° null
μ λ λλ§ν μ μμ§λ§ κΆμ₯νμ§λ μμ΅λλ€. μ΄λ° κ²½μ° μ¬μ©μλ μ΅μ μ½ν
μΈ λ₯Ό μ»μ μ μμ΅λλ€.