Understanding Caching in PocketPages
PocketPages uses content-based fingerprinting for static assets and development-mode cache busters to ensure efficient caching while maintaining quick updates during development.
Asset Fingerprinting
How It Works
- During startup, PocketPages computes SHA-256 fingerprints for all static assets
- The
asset()
helper embeds these fingerprints into filenames - The router dynamically matches fingerprinted URLs to their actual files
<!-- Template -->
<img src="<%= asset('logo.png') %>">
<!-- Output -->
<img src="logo.abc123de.png">
File Resolution
PocketPages resolves asset paths relative to the current template:
pb_hooks/pages/
feature/
index.ejs # asset('image.png') → /feature/image.[hash].png
image.png
products/
details.ejs # asset('style.css') → /products/style.[hash].css
style.css
Development vs Production
Development Mode
When an asset doesn't exist in development:
<!-- Template -->
<img src="<%= asset('missing.png') %>">
<!-- Development Output -->
<img src="missing.png?_r=1234567890">
Production Mode
When an asset doesn't exist in production:
<!-- Template -->
<img src="<%= asset('missing.png') %>">
<!-- Production Output -->
<img src="missing.png">
Best Practices
Keep Assets in Pages Directory
pb_hooks/pages/ images/ # Global images get fingerprinted logo.png feature/ header.jpg # Local images get fingerprinted index.ejs
Use Relative Paths for Local Assets
<!-- Local assets use relative paths --> <img src="<%= asset('header.jpg') %>"> <!-- Global assets use absolute paths --> <img src="<%= asset('/images/logo.png') %>">
Verify Assets Exist
- Missing assets won't get fingerprinted
- Development mode will show cache busters
- Production mode will serve un-fingerprinted paths
CDN Integration
Cloudflare Example
Fingerprinted assets work well with CDNs:
First request:
/images/logo.abc123de.png
- CDN misses, fetches from origin
- Origin matches
abc123de
tologo.png
- CDN caches response indefinitely
Content update:
- File changes, new hash
xyz789fg
- Template outputs
/images/logo.xyz789fg.png
- CDN misses, fetches new version
- Old version naturally expires
- File changes, new hash
Cache Control Headers
/** @type {import('pocketpages').MiddlewareLoaderFunc} */
module.exports = function (api) {
const { response } = api
// Set cache headers for static assets
response.header('Cache-Control', 'public, max-age=31536000')
return {}
}
Complete Example
<!DOCTYPE html>
<html>
<head>
<!-- CSS with fingerprinting -->
<link rel="stylesheet" href="<%= asset('css/styles.css') %>">
<!-- Favicon with fingerprinting -->
<link rel="icon" href="<%= asset('/favicon.png') %>">
</head>
<body>
<!-- Local image -->
<img src="<%= asset('header.jpg') %>" alt="Header">
<!-- Global image -->
<img src="<%= asset('/images/logo.png') %>" alt="Logo">
<!-- JavaScript with fingerprinting -->
<script src="<%= asset('js/app.js') %>"></script>
</body>
</html>
Important Notes
- Fingerprinting requires files to exist in pages directory
- Development mode helps identify missing assets
- CDNs can cache fingerprinted assets indefinitely
- Use middleware to set cache control headers
- Relative paths for local assets, absolute for global