我在从零构建 Firefox 新标签页扩展时学到的 5 条经验
Source: Dev.to
manifest_version: 3 迁移大体顺畅,但需注意 Service Worker 的陷阱
Firefox 现在支持 Manifest V3,我决定全力拥抱。大多数功能都能直接使用——声明式内容脚本、新的权限模型、更简洁的后台处理。
但 Service Worker 有一个关键限制:它们在 30 秒后会进入非活动状态。对于需要定期刷新天气数据的新标签页扩展来说,这一点很重要。
解决方案: 在每次打开新标签页时获取天气数据,而不是在持久后台计划中获取。将结果缓存到 localStorage,仅在缓存数据超过 10 分钟时才刷新。
async function getWeather() {
const cached = JSON.parse(localStorage.getItem('weatherCache') || '{}');
const now = Date.now();
if (cached.data && (now - cached.timestamp) fetchWeatherByCoords(pos.coords),
(err) => {
// err.code === 1: User denied
// err.code === 2: Position unavailable
// err.code === 3: Timeout
showManualCityInput(
err.code === 1
? 'Location blocked — enter your city manually'
: 'Could not detect location'
);
},
{ timeout: 5000, maximumAge: 3600000 }
);
扩展中的暗色模式检测其实相当优雅
在扩展中实现暗/亮模式切换非常直接。你可以直接使用 prefers-color-scheme,并且还能持久化用户偏好。
// Auto-detect system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
// Apply theme
function applyTheme(dark) {
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
localStorage.setItem('theme', dark ? 'dark' : 'light');
}
// Listen for system changes
prefersDark.addEventListener('change', (e) => applyTheme(e.matches));
// On load: check user preference first, then system
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
applyTheme(savedTheme === 'dark');
} else {
applyTheme(prefersDark.matches);
}
用户会获得“即开即用”的体验(匹配系统设置),同时还能自行覆盖。
AMO 审核实际上相当快速(而且有人性)
我原本以为 Firefox 附加组件(AMO)审核会拖上好几周。实际体验出乎意料地好:
- 首次审核: 大约 3 天
- 审稿人反馈: 具体且可操作(他们指出了我未注意到的一个
eval()调用) - 后续审核: 大约 1 天
审稿人指出我使用 innerHTML 来设置时钟时间值(即使数据是内部的,也存在不必要的 DOM 风险),并要求改用 textContent。理由充分。
加速审核的技巧:
- 编写干净、可读的代码
- 将权限最小化,仅保留必需的权限
- 避免远程代码执行
- 不使用混淆
- 如果进行压缩,提供 source map
结果
完成上述工作后,我发布了 Weather & Clock Dashboard ——它是开源的(MIT 许可证),不需要账号,且真的很实用。
如果你正在构建 Firefox 扩展,开发者体验实际上相当扎实。API 文档近年来有了显著提升,Mozilla 开发者社区也非常热心。
使用技术:纯 HTML/CSS/JS · 无构建步骤 · MIT 许可证