App Shell Architecture
debt(d5/e7/b7/t5)
Closest to 'specialist tool catches it' (d5). Lighthouse (cited in detection_hints.tools) audits PWA best practices and can flag missing service worker caching and slow first paint. Workbox can help verify caching strategies. These are specialist tools, not default linters — without them, the absence of an app shell pattern would only be noticed through manual performance testing or user complaints.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix says to cache the shell in a service worker and have PHP serve data via JSON APIs with JavaScript rendering content. For a traditional PHP-rendered site, this means restructuring the entire rendering pipeline: separating stable UI chrome from dynamic content, introducing a service worker, converting server-side rendering to API-based content delivery, and adding JavaScript-based content injection. This touches templates, routing, controllers, and frontend assets — a cross-cutting architectural change.
Closest to 'strong gravitational pull' (b7). Once app shell architecture is adopted, every future feature must respect the shell/content separation. New UI elements must be classified as shell (cached) or dynamic (API-fetched). The service worker cache versioning strategy must be maintained across deploys. Every navigation pattern, every new page, and every layout change is shaped by this architectural decision. It applies to the entire web context and fundamentally changes how the application delivers content.
Closest to 'notable trap' (t5). The misconception field explicitly states developers believe 'app shell architecture requires a SPA framework' — this is a well-documented gotcha that causes teams to dismiss the pattern for PHP-rendered sites when it's actually a caching strategy implementable with any frontend. Additionally, common_mistakes show several non-obvious pitfalls: including dynamic content in the shell, making the shell too large, and not versioning the cache. These are traps a competent developer new to the concept would likely fall into, but they're learnable documented gotchas rather than catastrophic contradictions.
Also Known As
TL;DR
Explanation
The App Shell model separates the application shell (header, navigation, skeleton layout) from the content. The shell is cached by the service worker on first visit — subsequent visits render the shell instantly from cache (< 100ms) while content fetches from the network. Benefits: reliable fast first paint, works offline for the shell, and progressively enhances with content. Implemented with Service Worker precaching. Works well for: SPAs, PWAs, and any app with a consistent chrome around changing content. Not suited for: content-first sites where every page has a unique layout.
Common Misconception
Why It Matters
Common Mistakes
- Including dynamic content in the app shell — the shell should only contain stable UI chrome.
- No fallback for content fetch failure — offline shell with no content is a bad experience without a fallback page.
- Shell too large — cache only the critical rendering path, not the entire application.
- Not versioning the shell cache — stale shells serve outdated UI after deploys.
Code Examples
// No shell caching — full page re-download on every visit:
// index.html: 45KB (header + nav + content + footer all mixed)
// On 3G: 4 second first paint, every visit
// Offline: nothing works
// Service worker precaches the shell:
const SHELL = [
'/shell.html', // Minimal HTML skeleton
'/app.css', // Critical styles
'/app.js', // Core JS
'/icons/logo.svg',
];
self.addEventListener('install', e => {
e.waitUntil(caches.open('shell-v2').then(c => c.addAll(SHELL)));
});
self.addEventListener('fetch', e => {
// Serve shell instantly from cache:
if (SHELL.includes(new URL(e.request.url).pathname)) {
e.respondWith(caches.match(e.request));
}
// Content: network first, cache fallback
});