AMP页面向ServiceWorker发送postMessage的可行方案咨询
Solution for Sending postMessage from an AMP Page to a ServiceWorker
Great question! AMP's security sandbox does restrict direct access to the navigator.serviceWorker API from regular page scripts, but there are reliable workarounds to send postMessage for your cache initialization needs. Here's what you need to do:
1. Ensure Proper ServiceWorker Registration with amp-install-serviceworker
First, confirm you've correctly set up the amp-install-serviceworker component in your AMP page—this is required to register your ServiceWorker in AMP's constrained environment. Example code:
<amp-install-serviceworker src="/sw.js" data-iframe-src="/install-sw.html" <!-- Fallback for browsers that don't support SW directly in AMP --> layout="nodisplay"> </amp-install-serviceworker>
Note: The data-iframe-src points to a simple HTML page that handles SW registration for older browsers; for modern browsers, AMP will register the SW directly.
2. Use amp-script to Send Messages to the ServiceWorker
AMP blocks direct access to navigator.serviceWorker from regular inline scripts, but the amp-script component allows you to run trusted, restricted JavaScript that can access this API. Here's how to implement it:
Step 2.1: Add the amp-script Component to Your AMP Page
<!-- Add this meta tag if using inline script (replace the hash with your script's SHA-256 hash) --> <meta name="amp-script-src" content="sha256-YOUR_SCRIPT_HASH_HERE"> <amp-script layout="container" type="text/javascript"> AMP.ready().then(() => { // Check if an active ServiceWorker controller exists const swController = navigator.serviceWorker.controller; if (swController) { // Send your cache initialization message swController.postMessage({ action: 'update-cache', filesToAdd: ['/new-styles.css', '/hero-image.jpg'], filesToRemove: ['/old-script.js'] }); } else { // Wait for the ServiceWorker to activate if it's still in the waiting state navigator.serviceWorker.addEventListener('controllerchange', () => { const newController = navigator.serviceWorker.controller; if (newController) { newController.postMessage({ action: 'update-cache', filesToAdd: ['/new-styles.css', '/hero-image.jpg'], filesToRemove: ['/old-script.js'] }); } }); } }); </amp-script>
Important: For inline amp-script, you need to generate a SHA-256 hash of your script content and add it to the amp-script-src meta tag. AMP will block the script if this hash isn't present.
Step 2.2: Handle the Message in Your ServiceWorker
In your ServiceWorker file (sw.js), listen for the message event to process the cache update request:
self.addEventListener('message', (event) => { if (event.data?.action === 'update-cache') { // Open your target cache caches.open('my-app-cache-v1').then(async (cache) => { // Add new files to the cache await cache.addAll(event.data.filesToAdd); // Remove old files from the cache for (const file of event.data.filesToRemove) { await cache.delete(file); } // Optional: Send a confirmation back to the AMP page event.source.postMessage({ status: 'cache-updated' }); }); } });
Key Notes to Avoid Pitfalls
- HTTPS Requirement: ServiceWorkers only work over HTTPS (localhost is exempt for testing).
- ServiceWorker Activation: If your SW is newly registered, it might be in a "waiting" state. You can either prompt the user to refresh, or call
self.skipWaiting()in your SW'sinstallevent to activate it immediately. amp-scriptRestrictions: External scripts used withamp-scriptmust be hosted on the same origin as your AMP page, or added to AMP's trusted script list. Inline scripts require the SHA hash as mentioned.
内容的提问来源于stack exchange,提问作者ekans

