progressive-web-app – skill Khác cho agent AI
Xây dựng Progressive Web App (PWA) với hỗ trợ offline, khả năng cài đặt và chiến lược cache. Kích hoạt khi người dùng nhắc đến PWA, service worker, web app manifest, Workbox, 'thêm vào màn hình chính', hoặc muốn web app hoạt động offline, có cảm giác như ứng dụng gốc hoặc có thể cài đặt.
Cài skill progressive-web-app bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/progressive-web-app-4458d.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /progressive-web-app – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/progressive-web-app-4458d.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $progressive-web-app – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/progressive-web-app-4458d.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /progressive-web-app – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/progressive-web-app-4458d.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /progressive-web-app – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Progressive Web Apps (PWAs)
Overview
A Progressive Web App is a web application that uses modern browser capabilities to deliver a fast, reliable, and installable experience — even on unreliable networks. Common building blocks (install criteria vary by browser) are:
1. HTTPS — Required in production for service workers to register (localhost is exempt for development).
2. Web App Manifest (manifest.json) — Makes the app installable and defines its appearance on device home screens.
3. Service Worker (sw.js) — A background script that intercepts network requests, manages caches, and enables offline functionality.
When to Use This Skill
- Use when the user wants their web app to work offline or on unreliable networks.
- Use when building a mobile-first web project where users should be able to install the app to their home screen.
- Use when the user asks about caching strategies, service workers, or improving web app performance and resilience.
- Use when the user mentions Workbox, web app manifests, background sync, or push notifications for the web.
- Use when the user asks "can my website be installed like an app?" or "how do I make my site work offline?" — even if they don't use the word PWA.
Deliverables Checklist
This example layout uses the following files; these exact filenames are not a universal PWA requirement:
- [ ]
index.html— Links manifest, registers service worker - [ ]
manifest.json— Full app metadata and icon set - [ ]
sw.js— Service worker with install, activate, and fetch handlers - [ ]
app.js— Main app logic with SW registration and install prompt handling - [ ]
offline.html— Fallback page shown when navigation fails offline (required by this example's cache.addAll list, not by the PWA standard)
---
Step 1: Web App Manifest (manifest.json)
Defines how the app appears when installed. Must be linked from <head> via <link rel="manifest">.
{
"name": "My Awesome PWA",
"short_name": "MyPWA",
"description": "A fast, offline-capable Progressive Web App.",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "portrait-primary",
"background_color": "#ffffff",
"theme_color": "#0055ff",
"icons": [
{
"src": "/assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
],
"screenshots": [
{
"src": "/assets/screenshots/desktop.png",
"sizes": "1280x720",
"type": "image/png",
"form_factor": "wide"
}
]
}Key fields:
display:standalonehides browser UI;minimal-uishows minimal controls;browseris standard tab.purpose: "maskable"on icons enables adaptive icons on Android (safe zone matters — keep content in center 80%).screenshotsis optional but required for Chrome's enhanced install dialog on desktop.
---
Step 2: HTML Shell (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Awesome PWA</title>
<!-- PWA manifest -->
<link rel="manifest" href="/manifest.json">
<!-- Theme color for browser chrome -->
<meta name="theme-color" content="#0055ff">
<!-- iOS-specific (Safari doesn't fully use manifest) -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="MyPWA">
<link rel="apple-touch-icon" href="/assets/icons/icon-192x192.png">
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<div id="app">
<header><h1>My PWA</h1></header>
<main id="content">Loading...</main>
<!-- Optional: install button, hidden by default -->
<button id="install-btn" hidden>Install App</button>
</div>
<script src="/app.js"></script>
</body>
</html>---
Step 3: Service Worker Registration & Install Prompt (app.js)
// ─── Service Worker Registration ───────────────────────────────────────────
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
const registration = await navigator.serviceWorker.register('/sw.js');
console.log('[App] SW registered, scope:', registration.scope);
} catch (err) {
console.error('[App] SW registration failed:', err);
}
});
}
// ─── Install Prompt (Add to Home Screen) ───────────────────────────────────
let deferredPrompt;
const installBtn = document.getElementById('install-btn'); // may be null if omitted
// Capture the browser's install prompt — it fires before the browser's own UI
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault(); // Stop automatic mini-infobar on mobile
deferredPrompt = e;
if (installBtn) installBtn.hidden = false; // Show your custom install button
});
if (installBtn) {
installBtn.addEventListener('click', async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log('[App] Install outcome:', outcome);
deferredPrompt = null;
installBtn.hidden = true;
});
}
// Fires when the app is installed (via browser or your button)
window.addEventListener('appinstalled', () => {
console.log('[App] PWA installed successfully');
if (installBtn) installBtn.hidden = true;
});---
Step 4: Service Worker (sw.js)
Cache Versioning (critical — always increment on deploy)
const CACHE_VERSION = 'v1';
const CACHE_PREFIX = 'my-pwa-'; // Unique to this app and deployment scope.
const STATIC_CACHE = `${CACHE_PREFIX}static-${CACHE_VERSION}`;
const DYNAMIC_CACHE = `${CACHE_PREFIX}dynamic-${CACHE_VERSION}`;
// Files to pre-cache during install (the "App Shell")
const APP_SHELL = [
'/',
'/index.html',
'/styles.css',
'/app.js',
'/assets/icons/icon-192x192.png',
'/offline.html', // Fallback page shown when network is unavailable
];The hand-written strategies are teaching sketches. Coordinate updates before skipWaiting/clients.claim to avoid old-page/new-worker incompatibility. Bound cache size/retention, preserve other apps' caches, and tie background revalidation to event.waitUntil with rejection handling.
Install — Pre-cache the App Shell
self.addEventListener('install', (event) => {
console.log('[SW] Installing...');
event.waitUntil(
caches.open(STATIC_CACHE).then((cache) => {
console.log('[SW] Pre-caching app shell');
return cache.addAll(APP_SHELL);
})
);
// Activate immediately without waiting for old SW to die
self.skipWaiting();
});Activate — Clean Up Old Caches
self.addEventListener('activate', (event) => {
console.log('[SW] Activating...');
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name.startsWith(CACHE_PREFIX) && name !== STATIC_CACHE && name !== DYNAMIC_CACHE)
.map((name) => {
console.log('[SW] Deleting old cache:', name);
return caches.delete(name);
})
);
})
);
// Take control of all pages immediately
self.clients.claim();
});Fetch — Caching Strategies
Choose the right strategy per resource type:
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// Only handle GET requests from our own origin
if (request.method !== 'GET' || url.origin !== location.origin) return;
// Explicit public resources only. Never cache authenticated/user-specific
// HTML or API responses by URL; cache contents can survive logout/account changes.
if (!APP_SHELL.includes(url.pathname)) return;
// Strategy A: Cache-First (for static assets — fast, tolerates stale)
if (url.pathname.match(/\.(css|js|png|jpg|svg|woff2)$/)) {
event.respondWith(cacheFirst(request));
return;
}
// Strategy B: Network-First (for HTML pages — fresh, falls back to cache)
if (request.headers.get('Accept')?.includes('text/html')) {
event.respondWith(networkFirst(request));
return;
}
// API caching is intentionally omitted; default to network-only for private data.
});
// ─── Strategy Implementations ──────────────────────────────────────────────
async function cacheFirst(request) {
const cached = await caches.match(request);
if (cached) return cached;
try {
const response = await fetch(request);
const cache = await caches.open(STATIC_CACHE);
if (response.ok && response.type !== "opaque") await cache.put(request, response.clone());
return response;
} catch {
// Nothing useful to fall back to for assets
return new Response('Asset unavailable of… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- project-brief – Project Detail Optimizer. Dùng khi làm việc với một câu, ghi chú sơ bộ hoặc bản brief dự…
- projection-patterns – Xây dựng read model và projection từ event stream. Dùng khi triển khai phía read của…
- projects-work-management – Sổ đăng ký dự án: người phụ trách, nhóm, mức ưu tiên, tỷ lệ tiến độ, mốc quan trọng, sản…
- prometheus-grafana – Thiết lập thu thập và trực quan hóa metric với Prometheus và Grafana.
- promotion-upgrade-requests – Sổ đăng ký thăng chức: vai trò và cấp bậc hiện tại cùng đề xuất, lý do, điểm OKR và hành…
- protocol-reverse – Dịch ngược (reverse engineering) được ủy quyền đối với giao thức nhị phân tùy chỉnh…
- public-relations – Khi người dùng cần hỗ trợ về quan hệ công chúng, truyền thông earned media, đưa tin báo…
- purchase-accounting – Sổ mua hàng: nhà cung cấp, hóa đơn, tổng tiền, VAT và TDS, số tiền phải trả ròng, tài…