求助:Service Worker拦截主题样式表时Fetch事件未触发
解决Service Worker拦截样式请求失败&主题闪烁问题
咱们一步一步拆解你遇到的问题,核心是三个关键点导致fetch事件没触发,以及初始闪烁的优化方案:
1. Service Worker作用域不匹配(最关键的原因)
你注册SW的路径是{{ site.baseurl }}/assets/sw.js,默认情况下,Service Worker的作用域是它所在的目录(也就是/assets/)。这意味着它只能控制路径以/assets/开头的页面和请求,而你的页面在/postmortem/002这类非/assets/路径下,完全不在SW的控制范围内,自然不会触发fetch事件。
修复方案:
注册SW时显式指定作用域为站点根路径(覆盖所有页面):
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('{{ site.baseurl }}/assets/sw.js', { scope: '{{ site.baseurl }}/' // 确保作用域覆盖整个站点 }).then(function() { console.log("Service Worker Registered"); }); }
2. Fetch事件回调的代码错误
你的SW代码里有两处致命错误,导致即使触发了fetch事件也无法正常工作:
- 字符串判断包含应该用
includes(),不是contains()(contains()是DOM元素的方法,字符串没有这个API) - 创建新Request时用了未定义的
request变量,应该是event.request - 必须调用
event.respondWith()告诉SW你要接管这个请求的响应,否则SW会直接走默认请求流程
修正后的fetch事件代码:
this.addEventListener('fetch', function(event) { console.log(event.request.url); if (event.request.url.includes('/bulmaswatch/')) { // 必须调用event.respondWith来接管响应逻辑 event.respondWith( localforage.getItem('theme') .then(function(theme) { if (theme === 'kb-dark-theme') { const darkThemeUrl = event.request.url.replace('bulmaswatch/default/', 'bulmaswatch/superhero/'); const darkThemeRequest = new Request(darkThemeUrl, { method: event.request.method, headers: event.request.headers, mode: event.request.mode, // 保留原请求的mode,不要硬写same-origin(跨域请求mode是cors) credentials: event.request.credentials, redirect: event.request.redirect }); return fetch(darkThemeRequest); } return fetch(event.request); }) ); } });
3. Prefetch资源的加载时机不对
你给bulma样式加了rel="stylesheet prefetch",prefetch是浏览器在页面加载完成后空闲时预取资源,用于未来导航,不是当前页面立即使用的资源。这会导致当前页面的样式加载请求可能在SW激活前就完成了,或者根本不会触发SW的fetch拦截。
修复方案:
把link标签的rel改成普通的stylesheet,确保样式是当前页面的关键资源,会被SW拦截:
<link id="bulma-theme" rel="stylesheet" href="//unpkg.com/bulmaswatch/default/bulmaswatch.min.css">
额外优化:彻底避免初始闪烁
即使SW配置正确,第一次加载页面时SW可能还没完成激活,还是会出现白色闪烁。可以在<head>里加一段内联脚本,在样式表加载前就读取主题状态并修改href:
<script> // 内联脚本会在页面解析时立即执行,比外部脚本和SW更早 const savedTheme = localStorage.getItem('theme') || 'default'; const themeLink = document.getElementById('bulma-theme'); if (savedTheme === 'kb-dark-theme') { themeLink.href = themeLink.href.replace('bulmaswatch/default/', 'bulmaswatch/superhero/'); } // 再注册SW if ('serviceWorker' in navigator) { navigator.serviceWorker.register('{{ site.baseurl }}/assets/sw.js', { scope: '{{ site.baseurl }}/' }).then(function() { console.log("Service Worker Registered"); }); } </script>
按照以上步骤修改后,SW的fetch事件应该能正常触发,主题切换的闪烁问题也能彻底解决。
内容的提问来源于stack exchange,提问作者Thatkookooguy
相关产品推荐
相关产品推荐

