גישה ליצירת סטנדרטים לתרחישים נפוצים לדוגמה של התאמה לדפוסים.
רקע
ניתוב הוא חלק חשוב בכל אפליקציית אינטרנט. בבסיסו, ניתוב כולל קבלת כתובת URL, החלת התאמה לתבנית או לוגיקה אחרת ספציפית לאפליקציה, ובדרך כלל הצגת תוכן אינטרנט על סמך התוצאה. אפשר להטמיע ניתוב במספר דרכים: לפעמים זה קוד שפועל בשרת וממפה נתיב לקבצים בדיסק, או לוגיקה באפליקציה של דף יחיד שמחכה לשינויים במיקום הנוכחי ויוצרת קטע DOM תואם להצגה.
אין תקן מוגדר אחד, אבל מפתחי אתרים נטו לשימוש בסינטקס נפוץ להבעת תבניות ניתוב של כתובות URL, שיש להן הרבה דמיון ל-regular expressions
, אבל עם תוספות ספציפיות לדומיין כמו אסימונים להתאמה לפלחי נתיב.
התחביר הזה (או משהו דומה מאוד לו) משמש בפלטפורמות פופולריות בצד השרת כמו Express ו-Ruby on Rails, ומפתחי JavaScript יכולים להשתמש במודולים כמו path-to-regexp
או regexpparam
כדי להוסיף את הלוגיקה הזו לקוד שלהם.
URLPattern
הוא תוסף לפלטפורמת האינטרנט שמבוסס על הבסיס שנוצר על ידי המסגרות האלה. המטרה שלו היא לסטנדרטיזציה של תחביר של תבניות ניתוב, כולל תמיכה בתווים כלליים לחיפוש, בקבוצות אסימונים בעלות שם, בקבוצות של ביטויים רגולריים ובמפעילי קבוצות. מכונות URLPattern
שנוצרות באמצעות התחביר הזה יכולות לבצע משימות ניתוב נפוצות, כמו התאמה לכתובות URL מלאות או לכתובת URL pathname
, ולהחזיר מידע על ההתאמות של האסימון והקבוצה.
יתרון נוסף של התאמת כתובות URL ישירות בפלטפורמת האינטרנט הוא שאפשר לשתף תחביר משותף עם ממשקי API אחרים שגם צריכים להתאים לכתובות URL.
תמיכה בדפדפנים ו-polyfills
URLPattern
מופעל כברירת מחדל ב-Chrome וב-Edge מגרסה 95 ואילך.
הספרייה urlpattern-polyfill
מאפשרת להשתמש בממשק URLPattern
בדפדפנים או בסביבות כמו Node, שבהן אין תמיכה מובנית. אם אתם משתמשים ב-polyfill, חשוב להשתמש בזיהוי תכונות כדי לוודא שאתם טוענים אותו רק אם אין תמיכה בסביבה הנוכחית. אחרת, תאבדו את אחת מהיתרונות העיקריים של URLPattern
: העובדה שבסביבות התמיכה לא צריך להוריד ולנתח קוד נוסף כדי להשתמש בו.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
תאימות תחביר
אחד העקרונות המנחים של URLPattern
הוא להימנע מיצירת משהו חדש לגמרי. אם אתם כבר מכירים את התחביר של הניתוב ב-Express או ב-Ruby on Rails, לא תצטרכו ללמוד שום דבר חדש. עם זאת, בגלל ההבדלים הקלים בין התחבירים בספריות ניתוב פופולריות, היה צריך לבחור משהו בתור התחביר הבסיסי, והמעצבים של URLPattern
החליטו להשתמש בתחביר התבניות מ-path-to-regexp
(אבל לא בממשק ה-API שלו) כנקודת ההתחלה.
ההחלטה הזו התקבלה לאחר התייעצות מעמיקה עם המנהל הנוכחי של path-to-regexp
.
הדרך הטובה ביותר להכיר את הליבה של התחביר הנתמך היא לעיין במסמכי התיעוד של path-to-regexp
. אפשר לקרוא את המסמכים שמיועדים לפרסום ב-MDN באתר הנוכחי שלהם ב-GitHub.
תכונות נוספות
התחביר של URLPattern
הוא קבוצה רחבה יותר מזו שנתמכת ב-path-to-regexp
, כי URLPattern
תומך בתכונה נדירה בספריות ניתוב: התאמה של מקורות, כולל תווים כלליים לחיפוש בשמות מארחים. רוב ספריות הניתוב האחרות מטפלות רק בpathname, ולפעמים בחלק של החיפוש או ה-hash בכתובת ה-URL. הם אף פעם לא צריכים לבדוק את החלק של המקור בכתובת ה-URL, כי הם משמשים רק לניתוב מאותו מקור באפליקציית אינטרנט עצמאית.
התייחסות למקורות פותחת את הדלת לתרחישי שימוש נוספים, כמו ניתוב בקשות ממקורות שונים בתוך פונקציית הטיפול באירועים fetch
של service worker. אם אתם מנווטים רק כתובות URL מאותו מקור, תוכלו להתעלם מהתכונה הנוספת הזו ולהשתמש ב-URLPattern
כמו בספריות אחרות.
דוגמאות
בניית התבנית
כדי ליצור URLPattern
, מעבירים למבנה ה-constructor מחרוזות או אובייקט שהמאפיינים שלו מכילים מידע על התבנית שרוצים להתאים אליה.
העברת אובייקט מספקת את השליטה הברורה ביותר לגבי התבנית שבה צריך להשתמש כדי להתאים לכל רכיב של כתובת ה-URL. בצורתה המפורטת ביותר, הקוד יכול להיראות כך:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
אם מציינים מחרוזת ריקה לנכס, תהיה התאמה רק אם החלק התואם של כתובת ה-URL לא מוגדר. התו הכללי לחיפוש *
יתאים לכל ערך בחלק מסוים של כתובת ה-URL.
ב-constructor יש כמה קיצורי דרך לשימוש פשוט יותר. השמטה מוחלטת של search
ו-hash
, או של מאפיינים אחרים, זהה להגדרתם כתובת ה-wildcard '*'
. אפשר לפשט את הדוגמה שלמעלה כך:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
קיצור דרך נוסף: אפשר לספק את כל המידע על המקור בנכס יחיד, baseURL
, שמובילה אל
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
כל הדוגמאות האלה מבוססות על ההנחה שהתרחיש לדוגמה שלכם כולל מקורות תואמים. אם אתם רוצים להתאים רק לחלקים האחרים של כתובת ה-URL, לא כולל המקור (כמו שקורה בתרחישים רבים של ניתוב 'מסורתי' למקור יחיד), תוכלו להשמיט את פרטי המקור לגמרי ולספק רק שילוב כלשהו של המאפיינים pathname
, search
ו-hash
. כמו קודם, נכסים שהושמטו יטופלו כאילו הוגדרו לדפוס התו הכללי לחיפוש *
.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
במקום להעביר אובייקט ל-constructor, אפשר לספק מחרוזת אחת או שתיים. אם מציינים מחרוזת אחת, היא צריכה לייצג תבנית מלאה של כתובת URL, כולל פרטי התבנית שמשמשים להתאמה למקור. אם מציינים שתי מחרוזות, המחרוזת השנייה משמשת כ-baseURL
והמחרוזת הראשונה נחשבת ביחס לבסיס הזה.
בין שמספקים מחרוזת אחת ובין ששתיים, ה-constructor של URLPattern
ינתח את תבנית כתובת ה-URL המלאה, יחלק אותה לרכיבי כתובת URL וימפה כל חלק מהתבנית הגדולה יותר לרכיב המתאים. כלומר, מתחת לפני השטח, כל URLPattern
שנוצר באמצעות מחרוזות מיוצג בסופו של דבר באותו אופן כמו URLPattern
מקביל שנוצר באמצעות אובייקט. ה-constructor של המחרוזות הוא רק קיצור דרך, למי שמעדיף ממשק פחות מפורט.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
כשמשתמשים במחרוזות כדי ליצור URLPattern
, יש כמה דברים שחשוב לזכור.
השמטת מאפיין כשמשתמשים באובייקט כדי ליצור את URLPattern
שווה ערך למתן תו כללי לחיפוש *
למאפיין הזה. כשמבצעים ניתוח של דפוס מחרוזת כתובת ה-URL המלאה, אם חסר ערך באחד מרכיבי כתובת ה-URL, המערכת מתייחסת אליו כאילו המאפיין של הרכיב הוגדר כ-''
, שיתאים רק כשהרכיב הזה ריק.
כשמשתמשים במחרוזות, צריך לכלול את תוו המשתנה הלא ידוע באופן מפורש אם רוצים להשתמש בו ב-URLPattern
שנוצר.
// p1 and p2 are equivalent.
const p1 = new URLPattern('/foo', location.origin);
const p2 = new URLPattern({
protocol: location.protocol,
hostname: location.hostname,
pathname: '/foo',
search: '',
hash: '',
});
// p3 and p4 are equivalent.
const p3 = new URLPattern('/foo?*#*', location.origin);
const p4 = new URLPattern({
protocol: location.protocol,
hostname: location.hostname,
pathname: '/foo',
});
חשוב גם לזכור שניתוח של תבנית מחרוזת לרכיביה עשוי להיות לא ברור. יש תווים, כמו :
, שמופיעים בכתובות URL, אבל יש להם גם משמעות מיוחדת בתחביר של התאמת התבניות. כדי להימנע מהמצב הזה, המאגר (constructor) של URLPattern
מניח שכל אחד מהתווים המיוחדים האלה הוא חלק מתבנית, ולא חלק מכתובת ה-URL. אם רוצים שתו מסוים שיכול להתפרש כחלק מכתובת ה-URL יפורש כחלק ממנה, צריך להשתמש ב-escape \` character. For example, the literal URL
about:blankshould be escaped as
'about\:blank'` כשהוא מסופק כמחרוזת.
שימוש בקו ביטול הנעילה
אחרי שיוצרים URLPattern
, יש שתי אפשרויות לשימוש בו. השיטות test()
ו-exec()
מקבלות את אותו קלט ומשתמשות באותו אלגוריתם כדי לבדוק אם יש התאמה, וההבדל ביניהן הוא רק בערך המוחזר. test()
מחזירה את הערך true
אם יש התאמה לקלט הנתון, ואת הערך false
במקרים אחרים.
הפונקציה exec()
מחזירה מידע מפורט על ההתאמה, יחד עם קבוצות לחילוץ, או את הערך null
אם אין התאמה. בדוגמאות הבאות מוצג שימוש ב-exec()
, אבל אפשר להחליף את test()
בכל אחת מהן אם רוצים רק ערך חזרה בוליאני פשוט.
אחת מהדרכים להשתמש בשיטות test()
ו-exec()
היא להעביר מחרוזות.
בדומה למה שה-constructor תומך בו, אם מציינים מחרוזת אחת, היא צריכה להיות כתובת URL מלאה, כולל המקור. אם מציינים שתי מחרוזות, המחרוזת השנייה נחשבת כערך של baseURL
והמחרוזת הראשונה נבדקת ביחס לבסיס הזה.
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
const result = p.exec('https://example.com/foo/cat.jpg');
// result will contain info about the successful match.
// const result = p.exec('/foo/cat.jpg', 'https://example.com')
// is equivalent, using the baseURL syntax.
const noMatchResult = p.exec('https://example.com/bar');
// noMatchResult will be null.
לחלופין, אפשר להעביר את אותו סוג אובייקט שה-constructor תומך בו, עם מאפיינים שמוגדרים רק לחלקים של כתובת ה-URL שחשוב לכם להתאים.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
כשמשתמשים ב-exec()
ב-URLPattern
שמכיל תווים כלליים לחיפוש או אסימונים, הערך המוחזר יספק מידע על הערכים התואמים בכתובת ה-URL שהוזנה. כך תוכלו לחסוך את הצורך לנתח את הערכים האלה בעצמכם.
const p = new URLPattern({
hostname: ':subdomain.example.com',
pathname: '/*/:image.jpg'
});
const result = p.exec('https://imagecdn1.example.com/foo/cat.jpg');
// result.hostname.groups.subdomain will be 'imagecdn1'
// result.pathname.groups[0] will be 'foo', corresponding to *
// result.pathname.groups.image will be 'cat'
קבוצות אנונימיות וקבוצות בעלות שם
כשמעבירים מחרוזת של כתובת URL לפונקציה exec()
, מקבלים בחזרה ערך שמציין אילו קטעים התאימו לכל הקבוצות של התבנית.
לערך המוחזר יש מאפיינים שתואמים לרכיבים של URLPattern
, כמו pathname
. לכן, אם קבוצה הוגדרה כחלק מחלק pathname
של URLPattern
, ההתאמות נמצאות ב-pathname.groups
של ערך ההחזרה. ההתאמות מיוצגות באופן שונה בהתאם לכך שהתבנית התואמת הייתה קבוצה אנונימית או קבוצה בעלת שם.
אפשר להשתמש באינדיקטורים של מערכי נתונים כדי לגשת לערכים של התאמה אנונימית לדפוס.
אם יש כמה דפוסים אנונימיים, האינדקס 0
ייצג את הערך התואם לדפוס שמשמאל ביותר, והאינדקסים 1
ואינדקסים נוספים ישמשו לדפוסים הבאים.
כשמשתמשים בקבוצות בעלות שם בתבנית, ההתאמות יוצגו כמאפיינים ששמותיהם תואמים לשמות של כל קבוצה.
תמיכה ב-Unicode ותקינה
URLPattern
תומך בתווי Unicode בכמה דרכים שונות.
קבוצות בעלות שם, כמו
:café
, יכולות להכיל תווים של Unicode. הכללים שחלים על מזהי JavaScript תקינים חלים על קבוצות בעלות שם.טקסט בתוך תבנית יקודר באופן אוטומטי לפי אותם כללים שמשמשים לקידוד כתובות URL של הרכיב הספציפי הזה. תווי Unicode ב-
pathname
יקודרו לפי אחוזים, כך שתבניתpathname
כמו/café
תהפוך באופן אוטומטי ל-/caf%C3%A9
. תווי Unicode ב-hostname
מקודדים באופן אוטומטי באמצעות Punycode, ולא באמצעות קידוד אחוזים.קבוצות של ביטויים רגולריים חייבות להכיל רק תווים מסוג ASCII. תחביר הביטוי הרגולרי מקשה על קידוד אוטומטי של תווים ב-Unicode בקבוצות האלה, וגם לא בטוח לעשות זאת. אם רוצים להתאים תו של Unicode בקבוצה של ביטוי רגולרי, צריך לבצע קידוד אחוזים ידני, למשל
(caf%C3%A9)
כדי להתאים ל-café
.
בנוסף לקידוד של תווים ב-Unicode, URLPattern
מבצע גם נורמליזציה של כתובות URL. לדוגמה, הערך /foo/./bar
ברכיב pathname
ימוקם ב-/foo/bar
המקביל.
אם אתם לא בטוחים איך תבנית קלט מסוימת עברה נורמליזציה, תוכלו לבדוק את המופע שנוצר של URLPattern
באמצעות DevTools של הדפדפן.
סיכום של כל המידע
הדוגמה של Glitch שמוטמעת בהמשך ממחישה תרחיש לדוגמה של שימוש ב-URLPattern
בתוך fetch event handler
של שירות העבודה, שממפה דפוסים ספציפיים לפונקציות אסינכררוניות שיכולות ליצור תגובה לבקשות מהרשת. אפשר להחיל את העקרונות שבדוגמאות האלה גם על תרחישים אחרים של ניתוב, בצד השרת או בצד הלקוח.
משוב ותוכניות עתידיות
הפונקציונליות הבסיסית של URLPattern
הגיעה ל-Chrome ול-Edge, אבל אנחנו מתכננים להוסיף עוד תכונות. יש היבטים מסוימים של URLPattern
שעדיין נמצאים בפיתוח, ויש כמה שאלות פתוחות לגבי התנהגויות ספציפיות שעדיין אפשר לשפר. אנחנו ממליצים לנסות את URLPattern
ולשלוח משוב באמצעות דיווח על בעיה ב-GitHub.
תמיכה ביצירת תבניות
בספרייה path-to-regexp
יש פונקציה compile() function
שמשנה את התנהגות הניתוב. הפונקציה compile()
מקבלת תבנית וערכים למשתני placeholder של האסימון, ומחזירה מחרוזת של נתיב כתובת URL עם ההחלפה של הערכים האלה.
אנחנו מקווים להוסיף את האפשרות הזו ל-URLPattern בעתיד, אבל היא לא נכללת בהיקף של הגרסה הראשונית.
הפעלת תכונות עתידיות בפלטפורמת האינטרנט
בהנחה ש-URLPattern
יהפוך לחלק קבוע בפלטפורמת האינטרנט, תכונות אחרות שיכולות להפיק תועלת מהניתוב או מהתאמת התבניות יוכלו להתבסס עליו כעל רכיב פרימיטיבי.
אנחנו ממשיכים לדון בשימוש ב-URLPattern
בתכונות מוצעות כמו התאמת דפוסים ברמת ה-service worker, אפליקציות PWA כמנהלי קבצים ואחזור מראש ספקולטיבי.
תודות
במסמך ההסבר המקורי מופיעה רשימה מלאה של תודות.