๐ฆ plugin-pwa
Docusaurus Plugin to add PWA support using Workbox. This plugin generates a Service Worker in production build only, and allows you to create fully PWA-compliant documentation site with offline and installation support.
Installationโ
- npm
- Yarn
- pnpm
npm install --save @docusaurus/plugin-pwa
yarn add @docusaurus/plugin-pwa
pnpm add @docusaurus/plugin-pwa
Configurationโ
Create a PWA manifest at ./static/manifest.json
.
Modify docusaurus.config.js
with a minimal PWA config, like:
export default {
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)',
},
],
},
],
],
};
Progressive Web Appโ
์๋น์ค ์์ปค๋ฅผ ์ค์นํ๋ ๊ฒ๋ง์ผ๋ก ์ฌ๋ฌ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์
์ด PWA๊ฐ ๋๋ ๊ฑด ์๋๋๋ค. You'll need to at least include a Web App Manifest and have the correct tags in <head>
(Options > pwaHead).
After deployment, you can use Lighthouse to run an audit on your site.
For a more exhaustive list of what it takes for your site to be a PWA, refer to the PWA Checklist
App installation supportโ
์ฌ๋ฌ๋ถ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ํ๋ค๋ฉด ๋ํ์ฌ์ฐ๋ฃจ์ค ์ฌ์ดํธ๋ฅผ ์ฑ์ฒ๋ผ ์ค์นํ ์ ์์ต๋๋ค.
์ฑ ์ค์น๋ฅผ ์ง์ํ๋ ค๋ฉด HTTPS ํ๋กํ ์ฝ์ ์ฌ์ฉํด์ผ ํ๋ฉฐ ์ ํจํ ๋งค๋ํ์คํธ๊ฐ ํ์ํฉ๋๋ค.
Offline mode (precaching)โ
์๋น์ค ์์ปค ์ฌ์ ์บ์ฑ์ ์ฌ์ฉํด ๋ํ์ฌ์ฐ๋ฃจ์ค ์ฌ์ดํธ๋ฅผ ์คํ๋ผ์ธ์์ ์ฌ์ฉ์๊ฐ ํ์ํ ์ ์์ต๋๋ค.
The workbox-precaching page explains the idea:
์๋น์ค ์์ปค์ ๊ธฐ๋ฅ ์ค ํ๋๋ก ์๋น์ค ์์ปค ์ค์น ์ ์บ์ ์ฒ๋ฆฌํ ํ์ผ ๋ฌถ์์ ์ ์ฅํด๋์ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค๊ฐ ์ฌ์ฉ๋๊ธฐ ์ ์ ์ฝํ ์ธ ๋ฅผ ์บ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ "์ฌ์ ์บ์ฑ"์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
์ด๋ ๊ฒ ์ฒ๋ฆฌํ๋ ์ด์ ๋ ๊ฐ๋ฐ์์๊ฒ ์บ์๋ฅผ ์ ์ดํ ์ ์๋ ๊ถํ์ ์ฃผ๊ธฐ ์ํจ์ ๋๋ค. ๊ฐ๋ฐ์๋ ์บ์๋ฅผ ์ธ์ ๋ง๋ค๊ณ ์ผ๋ง๋ ์ค๋ ๋ณด๊ดํ ์ง ๊ฒฐ์ ํ ์ ์์ ๋ฟ ์๋๋ผ ๋คํธ์ํฌ๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ์๋น์ค๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ฆ ์คํ๋ผ์ธ์์ ๋์ํ ์ ์๋ ์น ์ฑ์ ๋ง๋ค ์ ์๋ค๋ ๊ฒ๋๋ค.
Workbox๋ API๋ฅผ ๋จ์ํํ๊ณ ํจ์จ์ ์ผ๋ก ํ์ํ ํ์ผ์ ๋ด๋ ค๋ฐ์ ์ ์๊ฒ ๋ง๋ค์ด ์ฌ์ ์บ์ฑ ์์ ์ ์ฝ๊ฒ ์ ๊ทผํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์คํ๋ผ์ธ ๋ชจ๋๋ ์ฌ์ดํธ๊ฐ ์ฑ์ผ๋ก ์ค์น๋๋ฉด ํ์ฑํ๋ฉ๋๋ค. See the offlineModeActivationStrategies
option for details.
์ฌ์ดํธ ์ฌ์ ์บ์ฑ ์ดํ์ ์๋น์ค ์์ปค๋ ๋ฐฉ๋ฌธ์์๊ฒ ์บ์๋ ์๋ต์ ์ ๊ณตํฉ๋๋ค. ์๋ก์ด ๋น๋๊ฐ ์๋ก์ด ์๋น์ค ์์ปค์ ํจ๊ป ๋ฐฐํฌ๋๋ฉด ์๋ก์ด ์ฑ์ด ์ค์น๋๊ณ ๋๊ธฐ ์ํ๋ก ์ด๋ํ๊ฒ ๋ฉ๋๋ค. ๋๊ธฐ ์ํ์ ๋ค์ด๊ฐ๋ฉด ๋ฆฌ๋ก๋ ํ์
์ด ํ์๋๊ณ ์ฌ์ฉ์์๊ฒ ์๋ก์ด ์ฝํ
์ธ ๋ฅผ ์ํด ํ์ด์ง๋ฅผ ๋ฆฌ๋ก๋ํ ๊ฒ์ธ์ง ๋ฌผ์ด๋ด
๋๋ค. Until the user either clears the application cache or clicks the reload
button on the popup, the service worker will continue serving the old content.
์คํ๋ผ์ธ ๋ชจ๋๋ ์ฌ์ ์บ์ฑ์ ์ฌ์ดํธ์ ๋ชจ๋ ์ ์ ์ ๋ฏธ๋ฆฌ ๋ด๋ ค๋ฐ์์ผ ํ๋ฉฐ ๋ถํ์ํ ๋์ญํญ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ชจ๋ ์ข ๋ฅ์ ์ฌ์ดํธ์์ ๋ฌด์กฐ๊ฑด ํด๋น ๊ธฐ๋ฅ์ ํ์ฑํํ๋ ๊ฑด ์ข์ ์๊ฐ์ ์๋๋๋ค.
Optionsโ
debug
โ
- Type:
boolean
- Default:
false
์๋์ ๊ฐ์ ๋๋ฒ๊ทธ ๋ชจ๋๋ฅผ ์ค์ ํฉ๋๋ค.
- Workbox ๋ก๊ทธ
- ์ถ๊ฐ์ ์ธ ๋ํ์ฌ์ฐ๋ฃจ์ค ๋ก๊ทธ
- ์ต์ ํ๋์ง ๋ชปํ SW ํ์ผ ์ถ๋ ฅ
- ์์ค๋งต
offlineModeActivationStrategies
โ
- Type:
('appInstalled' | 'mobile' | 'saveData'| 'queryString' | 'always')[]
- Default:
['appInstalled', 'queryString', 'standalone']
์คํ๋ผ์ธ ๋ชจ๋๋ฅผ ์ ์ฉํ ์ํ์ ๋ํ ์ต์ ์ ์ค์ ํฉ๋๋ค.
appInstalled
: activates for users having installed the site as an app (not 100% reliable)standalone
: activates for users running the app as standalone (often the case once a PWA is installed)queryString
: activates if queryString containsofflineMode=true
(convenient for PWA debugging)mobile
: activates for mobile users (width <= 996px
)saveData
: activates for users withnavigator.connection.saveData === true
always
: activates for all users
์ฃผ์ํด์ ์ฌ์ฉํด์ฃผ์ธ์. ์ผ๋ถ ์ฌ์ฉ์๋ ์คํ๋ผ์ธ ๋ชจ๋๋ก ์ฌ์ฉํ๋๋ก ๊ฐ์ ๋๋ ๊ฒ์ ์ซ์ดํ ์๋ ์์ต๋๋ค.
ํ์ด์ง๊ฐ ์์ ์ ์ธ ํํ๋ก PWA ๋ ๋๋ง์ ์ฒ๋ฆฌํ๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
The appinstalled
event has been removed from the specification, and the navigator.getInstalledRelatedApps()
API is only supported in recent Chrome versions and require related_applications
declared in the manifest.
The standalone
strategy is a nice fallback to activate the offline mode (at least when running the installed app).
injectManifestConfig
โ
Workbox options to pass to workbox.injectManifest()
. ํ๋ฆฌ์บ์ฑ์ ์ ์ฉํ๊ณ ์คํ๋ผ์ธ์์ ์ฌ์ฉํ ์ ์๋ ์ ์
์ ์ง์ ์ค์ ํ ์ ์์ต๋๋ค.
- Type:
InjectManifestOptions
- Default:
{}
export default {
plugins: [
[
'@docusaurus/plugin-pwa',
{
injectManifestConfig: {
manifestTransforms: [
//...
],
modifyURLPrefix: {
//...
},
// We already add regular static assets (HTML, images...) to be available offline
// You can add more files according to your needs
globPatterns: ['**/*.{pdf,docx,xlsx}'],
// ...
},
},
],
],
};
pwaHead
โ
- Type:
({ tagName: string; [attributeName: string]: string })[]
- Default:
[]
Array of objects containing tagName
and key-value pairs for attributes to inject into the <head>
tag. ๊ธฐ์ ์ ์ผ๋ก ์ด๋ค head ํ๊ทธ ๋ ์ฝ์
ํ ์ ์์ง๋ง ์ฌ๋ฌ๋ถ์ ์ฌ์ดํธ PWA์ ์ ํฉํ ํ๊ทธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ด์์ ์
๋๋ค. ์๋ ๋ชฉ๋ก์ ์ฌ๋ฌ๋ถ์ ์ฑ์ ์ ํฉํ ํ๊ทธ ๋ชฉ๋ก์
๋๋ค.
export default {
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());
}
The module should have a default
function export, and receives some params.
swRegister
โ
- Type:
string | false
- Default:
'docusaurus-plugin-pwa/src/registerSW.js'
์ฑ์ด ์คํํ๊ธฐ ์ ์ ๋ฑ๋ก์ด ์ฒ๋ฆฌ๋๋๋ก ๋ํ์ฌ์ฐ๋ฃจ์ค ์ฑ ์์ ํญ๋ชฉ์ ์ถ๊ฐํฉ๋๋ค. The default registerSW.js
file is enough for simple registration.
Passing false
will disable registration entirely.
Manifest exampleโ
๋ํ์ฌ์ฐ๋ฃจ์ค ์ฌ์ดํธ ๋งค๋ํ์คํธ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
{
"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"
}
]
}
Customizing reload popupโ
The @theme/PwaReloadPopup
component is rendered when a new service worker is waiting to be installed, and we suggest a reload to the user. You can swizzle this component and implement your own UI. It will receive an onReload
callback as props, which should be called when the reload
button is clicked. ๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ ์๋น์ค ์์ปค์๊ฒ ์ค์น๋ฅผ ์งํํ๊ณ ํ์ด์ง๋ฅผ ๋ฆฌ๋ก๋ํ๋๋ก ์ ๋ฌํฉ๋๋ค.
The default theme includes an implementation for the reload popup and uses Infima Alerts.
Your component can render null
, but this is not recommended: users won't have a way to get up-to-date content.