๐ฆ plugin-pwa
Workbox๋ฅผ ์ฌ์ฉํด PWA ์ง์์ ์ถ๊ฐํ ์ ์๋ ๋ํ์ฌ์ฐ๋ฃจ์ค ํ๋ฌ๊ทธ์ธ์ ๋๋ค. ์ ํ ๋น๋์๋ง ์๋น์ค ์์ปค๋ฅผ ๋ง๋ค์ด์ฃผ๋ ํ๋ฌ๊ทธ์ธ์ ๋๋ค. ์ด๋ฅผ ํตํด ์คํ๋ผ์ธ์์ ์คํํ ์ ์๊ณ ์ค์น๋ ์ง์ํ๋ ์์ ํ PWA ํธํ ๋ฌธ์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
#
์ค์น- npm
- Yarn
npm install --save @docusaurus/plugin-pwa
yarn 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 ์ฒดํฌ๋ฆฌ์คํธ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
#
์ฑ ์ค์น ์ง์์ฌ๋ฌ๋ถ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ํ๋ค๋ฉด ๋ํ์ฌ์ฐ๋ฃจ์ค ์ฌ์ดํธ๋ฅผ ์ฑ์ฒ๋ผ ์ค์นํ ์ ์์ต๋๋ค.
note
์ฑ ์ค์น๋ฅผ ์ง์ํ๋ ค๋ฉด https ํ๋กํ ์ฝ์ ์ฌ์ฉํด์ผ ํ๋ฉฐ ์ ํจํ ๋งค๋ํ์คํธ๊ฐ ํ์ํฉ๋๋ค.
#
์คํ๋ผ์ธ ๋ชจ๋(precaching)์๋น์ค ์์ปค ์ฌ์ ์บ์ฑ์ ์ฌ์ฉํด ๋ํ์ฌ์ฐ๋ฃจ์ค ์ฌ์ดํธ๋ฅผ ์คํ๋ผ์ธ์์ ์ฌ์ฉ์๊ฐ ํ์ํ ์ ์์ต๋๋ค.
์ฌ์ ์บ์ฑ์ ๋ฌด์์ธ๊ฐ์?#
์๋น์ค ์์ปค์ ๊ธฐ๋ฅ ์ค ํ๋๋ก ์๋น์ค ์์ปค ์ค์น ์ ์บ์ ์ฒ๋ฆฌํ ํ์ผ ๋ฌถ์์ ์ ์ฅํด๋์ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค๊ฐ ์ฌ์ฉ๋๊ธฐ ์ ์ ์ฝํ ์ธ ๋ฅผ ์บ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ "์ฌ์ ์บ์ฑ"์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
์ด๋ ๊ฒ ์ฒ๋ฆฌํ๋ ์ด์ ๋ ๊ฐ๋ฐ์์๊ฒ ์บ์๋ฅผ ์ ์ดํ ์ ์๋ ๊ถํ์ ์ฃผ๊ธฐ ์ํจ์ ๋๋ค. ๊ฐ๋ฐ์๋ ์บ์๋ฅผ ์ธ์ ๋ง๋ค๊ณ ์ผ๋ง๋ ์ค๋ ๋ณด๊ดํ ์ง ๊ฒฐ์ ํ ์ ์์ ๋ฟ ์๋๋ผ ๋คํธ์ํฌ๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ์๋น์ค๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ฆ ์คํ๋ผ์ธ์์ ๋์ํ ์ ์๋ ์น ์ฑ์ ๋ง๋ค ์ ์๋ค๋ ๊ฒ๋๋ค.
Workbox๋ API๋ฅผ ๋จ์ํํ๊ณ ํจ์จ์ ์ผ๋ก ํ์ํ ํ์ผ์ ๋ด๋ ค๋ฐ์ ์ ์๊ฒ ๋ง๋ค์ด ์ฌ์ ์บ์ฑ ์์ ์ ์ฝ๊ฒ ์ ๊ทผํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์คํ๋ผ์ธ ๋ชจ๋๋ ์ฌ์ดํธ๊ฐ ์ฑ์ผ๋ก ์ค์น๋๋ฉด ํ์ฑํ๋ฉ๋๋ค. ์์ธํ ๋ด์ฉ์ offlineModeActivationStrategies
์ต์
์ค๋ช
์ ์ฐธ๊ณ ํ์ธ์.
์ฌ์ดํธ ์ฌ์ ์บ์ฑ ์ดํ์ ์๋น์ค ์์ปค๋ ๋ฐฉ๋ฌธ์์๊ฒ ์บ์๋ ์๋ต์ ์ ๊ณตํฉ๋๋ค. ์๋ก์ด ๋น๋๊ฐ ์๋ก์ด ์๋น์ค ์์ปค์ ํจ๊ป ๋ฐฐํฌ๋๋ฉด ์๋ก์ด ์ฑ์ด ์ค์น๋๊ณ ๋๊ธฐ ์ํ๋ก ์ด๋ํ๊ฒ ๋ฉ๋๋ค. ๋๊ธฐ ์ํ์ ๋ค์ด๊ฐ๋ฉด ๋ฆฌ๋ก๋ ํ์
์ด ํ์๋๊ณ ์ฌ์ฉ์์๊ฒ ์๋ก์ด ์ฝํ
์ธ ๋ฅผ ์ํด ํ์ด์ง๋ฅผ ๋ฆฌ๋ก๋ํ ๊ฒ์ธ์ง ๋ฌผ์ด๋ด
๋๋ค. ์ฌ์ฉ์๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์บ์๋ฅผ ์ญ์ ํ๊ฑฐ๋ ํ์
์์ reload
๋ฒํผ์ ํด๋ฆญํ ๋๊น์ง ์๋น์ค ์์ปค๋ ๊ธฐ์กด ์ฝํ
์ธ ๋ฅผ ์ ๊ณตํฉ๋๋ค.
caution
์คํ๋ผ์ธ ๋ชจ๋๋ ์ฌ์ ์บ์ฑ์ ์ฌ์ดํธ์ ๋ชจ๋ ์ ์ ์ ๋ฏธ๋ฆฌ ๋ด๋ ค๋ฐ์์ผ ํ๋ฉฐ ๋ถํ์ํ ๋์ญํญ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ชจ๋ ์ข ๋ฅ์ ์ฌ์ดํธ์์ ๋ฌด์กฐ๊ฑด ํด๋น ๊ธฐ๋ฅ์ ํ์ฑํํ๋ ๊ฑด ์ข์ ์๊ฐ์ ์๋๋๋ค.
#
์ต์ debug
#
- Type:
boolean
- Default:
false
์๋์ ๊ฐ์ ๋๋ฒ๊ทธ ๋ชจ๋๋ฅผ ์ค์ ํฉ๋๋ค.
- Workbox ๋ก๊ทธ
- ์ถ๊ฐ์ ์ธ ๋ํ์ฌ์ฐ๋ฃจ์ค ๋ก๊ทธ
- ์ต์ ํ๋์ง ๋ชปํ SW ํ์ผ ์ถ๋ ฅ
- ์์ค๋งต
offlineModeActivationStrategies
#
- Type:
Array<'appInstalled' | 'mobile' | 'saveData'| 'queryString' | 'always'>
- Default:
['appInstalled','queryString','standalone']
์คํ๋ผ์ธ ๋ชจ๋๋ฅผ ์ ์ฉํ ์ํ์ ๋ํ ์ต์ ์ ์ค์ ํฉ๋๋ค.
appInstalled
: ์ฌ์ฉ์๊ฐ ์ฌ์ดํธ๋ฅผ ์ฑ์ผ๋ก ์ค์นํ ๊ฒฝ์ฐ ํ์ฑํ(100% ์ ๋ขฐํ ์๋ ์์ต๋๋ค)standalone
: ์ฌ์ฉ์๊ฐ ์ฑ์ ๋ ๋ฆฝ์ ์ผ๋ก ์คํํ ๊ฒฝ์ฐ ํ์ฑํ(PWA๊ฐ ์ค์น๋ ๊ฒฝ์ฐ)queryString
: queryString์offlineMode=true
๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ ํ์ฑํ(PWA ๋๋ฒ๊น ์ ์ ์ฉํฉ๋๋ค)mobile
: ๋ชจ๋ฐ์ผ ์ฌ์ฉ์์ธ ๊ฒฝ์ฐ ํ์ฑํ(width <= 940px)saveData
:navigator.connection.saveData === true
๋ก ์ค์ ํ ๊ฒฝ์ฐ ํ์ฑํalways
: ๋ชจ๋ ์ฌ์ฉ์ ํ์ฑํ
caution
์ฃผ์ํด์ ์ฌ์ฉํด์ฃผ์ธ์. ์ผ๋ถ ์ฌ์ฉ์๋ ์คํ๋ผ์ธ ๋ชจ๋๋ก ์ฌ์ฉํ๋๋ก ๊ฐ์ ๋๋ ๊ฒ์ ์ซ์ดํ ์๋ ์์ต๋๋ค.
danger
๋งค์ฐ ์์ ์ ์ธ ๋ฐฉ์์ผ๋ก 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}'], // ... }, }, ], ],};
reloadPopup
#
- Type:
string | false
- Default:
'@theme/PwaReloadPopup'
ํ์ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ก๋ํ ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ์ค์ ํฉ๋๋ค. ์๋ก์ด ์๋น์ค ์์ปค๊ฐ ์ค์น๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆด ๋ ํ์ ์ด ํ์๋๋ฉฐ ์ฌ์ฉ์์๊ฒ ๋ฆฌ๋ก๋๋ฅผ ์๋ดํฉ๋๋ค.
false
๋ก ์ค์ ํ๋ฉด ํ์
์ด ํ์๋์ง ์์ง๋ง ๊ถ์ฅํ์ง๋ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์๊ฐ ์ต์ ์ปจํ
์ธ ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์์ฑ์ผ๋ก onReload
๋ฅผ ์ค์ ํ๋ฉด ์ฌ์ฉ์ ์ง์ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. onReload
์ฝ๋ฐฑํจ์๋ reload
๋ฒํผ ํด๋ฆญ ์ ํธ์ถ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ ์๋น์ค ์์ปค์๊ฒ ์ค์น๋ฅผ ์งํํ๊ณ ํ์ด์ง๋ฅผ ๋ฆฌ๋ก๋ํ๋๋ก ์ ๋ฌํฉ๋๋ค.
interface PwaReloadPopupProps { onReload: () => void;}
๊ธฐ๋ณธ ํ ๋ง๋ ๋ฆฌ๋ก๋ ํ์ ์ด ๊ตฌํ๋์ด ์์ผ๋ฉฐ Infima Alerts์ ์ฌ์ฉํฉ๋๋ค.
pwaHead
#
- Type:
Array<{ tagName: string } & Record<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 paramsexport 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" } ]}