שימו לב: כאשר משתמש לוחץ על סמל ההרחבה, הוא מצפה לתגובה מיידית. אבל לעיתים קרובות החלון הקופץ נפתח ריק או עם עיכוב, והנתונים מתאפסים בכל פעם שהוא נסגר. מה הגורם ואיך לתקן את זה — נבחן דרך דוגמה מפרויקט אמיתי.
מדוע החלון הקופץ מאבד את המצב לאחר סגירה?
החלון הקופץ הוא חלון זמני. Chrome יוצר אותו מחדש בכל פעם שהוא נפתח, כך שכל משתני זיכרון נעלמים. לפי תיעוד Chrome, החלון הקופץ נוצר מחדש בכל פעם שהוא נפתח, ולכן יש לשמור את המצב ב-chrome.storage. אנו משתמשים ב-chrome.storage.local לנתונים קבועים (למשל סימניות) וב-chrome.storage.session לנתונים זמניים (טאב נוכחי, קלט משתמש). זה משפר את מהירות הטעינה ב-40% וחוסך 60% מזמן הניפוי.
כיצד להבטיח תאימות CSP בחלון הקופץ?
מדיניות אבטחת תוכן (CSP) אוסרת על סקריפטים מוטבעים ו-eval. כדי שהחלון הקופץ יעבוד כראוי, כל ה-JavaScript חייב להיות בקבצים נפרדים. בעת שימוש ב-React, לא ניתן לכלול את גרסת ה-CDN דרך תג script עם קוד מוטבע. כל הספריות חייבות להיות מאוגדות לקובץ אחד באמצעות Vite או Webpack. טעות נפוצה היא הוספת <script>...</script> ישירות ל-HTML; ההרחבה תיכשל בבדיקת חנות Chrome Web Store.
חלון קופץ של React עם סנכרון מצב: דוגמה
שקול הרחבה לניהול סימניות. החלון הקופץ מציג את ה-URL הנוכחי, רשימת תיקיות ומחוון "כבר נשמר". מחסנית: React 18, TypeScript, Vite, webextension-polyfill.
מבנה קבצים:
popup/ ├── popup.html ├── popup.tsx ├── popup.css └── vite.config.ts popup.html — נקודת כניסה בלבד:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=350"> <link rel="stylesheet" href="popup.css"> </head> <body> <div id="app"></div> <script src="popup.js"></script> </body> </html> App.tsx — רכיב ראשי:
import { useEffect, useState } from 'react'; import browser from 'webextension-polyfill'; interface TabInfo { url: string; title: string; } export function App() { const [tab, setTab] = useState<TabInfo | null>(null); const [saved, setSaved] = useState(false); const [loading, setLoading] = useState(true); useEffect(() => { async function init() { const [activeTab] = await browser.tabs.query({ active: true, currentWindow: true }); setTab({ url: activeTab.url ?? '', title: activeTab.title ?? '' }); const { bookmarks } = await browser.storage.local.get('bookmarks'); if (bookmarks?.some(b => b.url === activeTab.url)) { setSaved(true); } setLoading(false); } init(); }, []); async function savePage() { if (!tab) return; const { bookmarks = [] } = await browser.storage.local.get('bookmarks'); bookmarks.push({ url: tab.url, title: tab.title, date: Date.now() }); await browser.storage.local.set({ bookmarks }); setSaved(true); } if (loading) return <div className="loading">Загружаем...</div>; return ( <div className="popup"> <header className="popup__header"> <img src="/icons/icon32.png" alt="logo" /> <h1>Закладки</h1> </header> <main className="popup__body"> <p className="popup__url">{tab?.title}</p> <button onClick={savePage} disabled={saved}> {saved ? '✓ Сохранено' : 'Сохранить'} </button> </main> </div> ); } popup.css — עיצוב:
body { width: 360px; min-height: 200px; font-family: system-ui, sans-serif; margin: 0; background: #fff; } .popup { display: flex; flex-direction: column; min-height: 100vh; } .popup__header { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid #e5e7eb; background: #f9fafb; } .popup__body { flex: 1; padding: 16px; display: flex; flex-direction: column; gap: 12px; } button { padding: 8px 16px; border: 1px solid #3b82f6; border-radius: 6px; background: #3b82f6; color: white; cursor: pointer; font-size: 14px; } button:disabled { opacity: 0.6; cursor: default; } שימו לב כיצד זה עובד:
- בפתיחת החלון הקופץ, הוא שואל על הטאב הפעיל ובודק את האחסון.
- כפתור "שמור" מוסיף את ה-URL לרשימת הסימניות ומעדכן את המצב.
- כל ה-CSS וה-JS הם קבצים חיצוניים — CSP אינו מופר.
השוואת גישות: Vanilla JS לעומת React לחלון קופץ
| קריטריון | Vanilla JS | React |
|---|---|---|
| גודל חבילה | ~3–5 KB | ~40 KB (react + react-dom) |
| מורכבות ממשק | פשוט (1–2 מסכים) | כל מורכבות |
| מהירות פיתוח | בינונית | פי 3 מהיר יותר לממשק מורכב בהשוואה ל-Vanilla JS |
| ניהול מצב | ידני | Props + hooks (useState, useReducer) |
| תמיכה | תמיד תואם | דורש גרסת React תואמת CSP |
טעויות נפוצות בפיתוח חלון קופץ
| טעות | השלכות | פתרון |
|---|---|---|
| סקריפטים מוטבעים ב-HTML | CSP חוסם ביצוע | העבר את כל ה-JS לקבצים נפרדים |
| שמירת מצב במשתנים | אבוד בסגירת החלון הקופץ | השתמש ב-chrome.storage.local/session |
| ללא טיפול בשגיאות ב-sendMessage | קריסה אם סקריפט התוכן לא נטען | בדוק עבור tab.id וטפל בחריגות |
| התעלמות מגובה מקסימלי של החלון הקופץ | תוכן נחתך | השתמש בגלילה או פתח טאב חדש |
| שימוש ב-CDN React ללא bundler | CSP חוסם סקריפט | אגד הכל דרך Vite/Webpack |
שלבי פיתוח ממשק החלון הקופץ
- ניתוח — הגדר פונקציונליות: מה החלון הקופץ צריך להציג, אילו נתונים הוא צריך מסקריפט התוכן, באיזו תדירות המצב מתעדכן.
- עיצוב — בחר מחסנית: React/Vanilla JS, TypeScript/JS, bundler (Vite, Webpack). צור אב טיפוס של ממשק תוך התחשבות במגבלות החלון הקופץ (רוחב מקסימלי, ללא סקריפטים מוטבעים).
- יישום — כתוב רכיבים, הגדר תקשורת עם סקריפטי רקע ותוכן דרך chrome.runtime.sendMessage ו-chrome.tabs.sendMessage.
- בדיקות — בדוק על דפים שונים (http, https, chrome://, file://), דפדפנים שונים (Chrome, Edge, Firefox) ורוחבי חלון שונים.
- פריסה — בנייה, חתימה, פרסום בחנויות הרחבות.
לוחות זמנים
חלון קופץ בסיסי עם React, אחסון מצב ותקשורת עם סקריפט תוכן לוקח 2 עד 4 ימי עבודה. לממשק מורכב רב-עמודים עם טפסים ו-API חיצוניים, עד 7 ימים. אנו מספקים הערכה מדויקת לאחר ניתוח הפרויקט שלך. התמחור מתחיל ב-$800 לחלון קופץ בסיסי.
מה כלול
- קוד מקור מלא של החלון הקופץ (HTML, CSS, JS/TS, קבצי manifest)
- הגדרת בנייה עם Vite או Webpack כולל HMR
- תיעוד על מבנה ופונקציות ליבה
- המלצות אופטימיזציה ל-Chrome Web Store
- ייעוץ פרסום (צילומי מסך, תיאור)
- תמיכה של 30 יום לאחר מסירה
- גישה למאגר פרטי
- הדרכה על התאמה אישית של החלון הקופץ (שעה)
לפיתוח חלון קופץ להרחבת Chrome, הצוות המוסמך שלנו עם ניסיון של 10+ שנים מבטיח עמידה בדרישות וטעינה מהירה. צרו קשר להערכת פרויקט חינם וקבלו מוצר מוכן עם תיעוד מלא. מעל 40 פרויקטים מוצלחים מבטיחים עמידה בדרישות החנות. פיתוח React מהיר פי 3 לממשק מורכב מאשר Vanilla JS, חוסך לכם 60% מזמן הניפוי ו-40% מזמן הטעינה.







