"높은 사용자 경험을 제공하기 위한 웹 앱의 진화"
{
"short_name": "앱 아이콘 이름",
"name": "하단 설치 배너에 표기될 이름 & 앱에서 검색시 키워드",
"icons": [
{
"src": "dist/images/icons.icon-32x32.png",
"type": "images/png",
"size": "32x32"
},
{}
],
"background_color": "#1E88E5",
"display": "standalone",
"start_url": "./"
}
<link rel="manifest" href="/mainfest.json" />
Chrome > 검색(개발자도구) > Application 에서 Manifest내용을 확인 할 수 있습니다.
해당 웹 사이트가 모바일 화면에서 표시될 아이콘 이미지 지정
{
"icons": [
{
"src": "images/touch/icon-128x128.png",
"type": "image/png",
"size": "128x128"
},
{
"src": "images/touch/icon-152x152.png",
"type": "image/png",
"size": "152x152"
},
{
"src": "images/touch/icon-192x192.png",
"type": "image/png",
"size": "192x192"
}
]
}
<link rel="apple-touch-icon" href="touch-icon-iphone.png" />
<link rel="apple-touch-icon" sizes="152x152" href="touch-icon-ipad.png" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="touch-icon-iphone-retina.png"
/>
<link
rel="apple-touch-icon"
sizes="167x167"
href="touch-icon-ipad-retina.png"
/>
{ "background_color": "#FFF" }
dp: 다양한 모바일 화면 크기에 동일한 비율로 출력되게 하는 픽셀단위
{ "start_url": "./" }
{ "start_url": "index.html?q=hello" }
{ "display": "standalone" }
<meta name="apple-mobile-web-app-capable" content="yes" />
{ "theme-color": "#0093FB" }
{ "orientation": "landscap" }
Install Banner 동작 조건
beforeinstallprompt로 설치 배너의 표시 시기를 지연하거나 disable가능
let defferedPrompt;
//설치 가능한지 확인
window.addEventListener("beforeinstallprompt", (e) => {
e.preventDefault();
defferedPrompt = e;
});
//특정 버튼 클릭 시에 앱 설치
btn.addEventListener("click", (e) => {
defferedPrompt.prompt();
defferedPrompt.userChoice.then((res) => {
if (res === "accepted") {
console.log("The app has been installed");
}
defferedPromts = null;
});
});
브라우저와 서버 사이에 미들웨어 역할을 하는 스크립트 입니다.
❗️다른 영역에 있는 자바스크립트 파일!!
중계서버: 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터는 응용 프로그램을 가리킨다.
//index.html
//service worker 등록하기
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("sw.js")
.then(() => {
console.log("Okey!");
})
.catch((error) => {
cosole.log("FAIL", error);
});
}
//sw.js
const CACHE_NAME = "pwa-offline-v1"; //캐쉬를 담을 파일명 정의
const filesToCache = [
//❗️sw-toolbox 사용가능
//캐쉬 할 웹 자원들 목록
"/", //index.html을 담당
"/public/css/styles.css",
"/public/images/banner.png",
"/public/images/manifest.png",
"/public/images/pwa.png",
];
// 서비스 워커 설치 (웹 자원 캐싱)
self.addEventListener("install", (event) => {
console.dir(event);
event.waitUntil(
//끝나기 전까지는 이벤트가 끝나지 않는다.
//caches 브라우져 예약어
caches
.open(CACHE_NAME)
.then((cache) => {
//캐쉬를 열고 접근 할 수 있는 캐쉬를 얻을 수 있다.
//캐쉬에 넣어라
return cache.addAll(filesToCache);
})
.catch((error) => {
return console.log(error);
})
);
});
self: 서비스 워커파일에서 window를 바라 보게 됩니다.
self.addEventListener("fetch", (event) => {
console.log("fetch", event.request);
event.respondWith(
caches
.match(event.request) //fetch request를 보내는 내용
//값이 있다면 캐쉬 내용을 전달 하고
//없다면 fetch 요청을 보내서 자원을 요청한다.
.then((response) => response || fetch(event.request))
.catch(console.error)
);
});
기존에 실행 중인 서비스워커와 사이즈를 비교하여 1바이트라도 차이가 나면 새 것의 워커로 간주 한다.
// 불필요한 캐쉬 제거
self.addEventListener("activate", (event) => {
const newCacheList = [CACHE_NAME];
event.waitUntil(
//promise를 리턴 하기 전짜기 동작을 보당 해준다.
caches
.keys()
.then((cacheList) => {
return Promise.all(
cacheList.map((cacheName) => {
if (newCacheList.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
.catch(console.error)
);
});
# install
npm i -D sw-precache
npm i -g sw-precache
//cache할 내용
module.exports = {
staticFileGlobs: [
"index.html",
"manifest.json",
"public/css/*.css",
"public/images/**.*",
],
};
//package.json
{
"scripts": {
"pre": "sw-precache --config sw-config.js"
}
}
// sevice-worker.js 파일이 생성됨을 확인 할 수 있다.
npm i -D sw-precache-webpack-plugin
//webpack.config.js
const path = require("path");
const SWPrecacheWebpackPlugin = require("sw-precache-webpack-plugin");
module.exports = {
mode: "none",
entry: {
main: path.resolve(__dirname, "public/js/app.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "bundles.js",
publicPath: "/dist/",
},
plugins: [
new SWPrecacheWebpackPlugin({
cacheId: "pwa-online-v4",
filename: "service-worker.js",
staticFileGlobs: [
"index.html",
"manifest.json",
"public/css/*.css",
"public/images/**.*",
],
mergeStaticsConfig: true,
}),
],
};