URLPattern מביא ניתוב לפלטפורמת האינטרנט

גישה לסטנדרטיזציה של תרחישים נפוצים של התאמת דפוסים.

רקע

ניתוב הוא חלק מרכזי בכל אפליקציית אינטרנט. הניתוב מבוסס בעיקרו על לקיחת כתובת URL, החלה של התאמת דפוסים או לוגיקה אחרת ספציפית לאפליקציה, ובדרך כלל הצגת תוכן מהאינטרנט על סמך התוצאה. הניתוב יכול להתבצע בכמה דרכים: לפעמים אותו קוד שרץ בשרת שממפה נתיב לקבצים בדיסק, או לוגיקה באפליקציה בדף יחיד שבהמתנה לשינויים במיקום הנוכחי ויוצר קטע DOM תואם לתצוגה.

אמנם אין סטנדרט מוחלט, אבל מפתחי אתרים השתמשו בתחביר נפוץ לביטויים של דפוסי ניתוב של כתובות URL, שיש להם הרבה במשותף עם regular expressions, אבל עם כמה תוספות ספציפיות לדומיין, כמו אסימונים לפלחי נתיב תואמים. מסגרות פופולריות בצד השרת, כמו Express ו-Ruby on Rails, משתמשות בתחביר הזה (או משהו שקרוב מאוד אליו), ומפתחי JavaScript יכולים להשתמש במודולים כמו path-to-regexp או regexpparam כדי להוסיף את הלוגיקה הזו לקוד שלהם.

URLPattern הוא תוספת לפלטפורמת האינטרנט, שמבוססת על הבסיס שנוצר על ידי המסגרות האלה. המטרה היא לתקן תחביר של דפוסי ניתוב, כולל תמיכה בתווים כלליים לחיפוש, קבוצות אסימונים בעלי שם, קבוצות של ביטויים רגולריים ומשנים של קבוצות. מכונות URLPattern שנוצרו עם התחביר הזה יכולות לבצע משימות ניתוב נפוצות, כמו התאמה לכתובות URL מלאות או לכתובת URL pathname, ולהחזיר מידע על ההתאמות של האסימון ושל הקבוצה.

יתרון נוסף של התאמה של כתובות URL ישירות בפלטפורמת האינטרנט הוא שאפשר לשתף תחביר נפוץ עם ממשקי API אחרים שגם הם צריכים להתאים לכתובות URL.

תמיכה בדפדפנים ו-Polyfills

הדפדפן URLPattern מופעל כברירת מחדל בגרסאות 95 ואילך של Chrome ו-Edge.

הספרייה 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 תומך בתכונה לא נפוצה בין ספריות ניתוב: התאמה של מקורות, כולל תווים כלליים לחיפוש בשמות מארחים. רוב ספריות הניתוב האחרות מטפלות רק בשם הנתיב, ומדי פעם גם בחלק החיפוש או ה-hash של כתובת ה-URL. הם אף פעם לא צריכים לבדוק את החלק המקורי של כתובת URL, כי הם משמשים רק לניתוב מקור זהה באפליקציית אינטרנט עצמאית.

התייחסות למקורות פותחת את הדלת לתרחישים נוספים, כמו ניתוב בקשות ממקורות שונים בתוך הגורם המטפל באירועים fetch של service worker. אם אתם מפנים רק כתובות URL מאותו מקור, אפשר להתעלם בפועל מהתכונה הנוספת הזו ולהשתמש ב-URLPattern כמו בספריות אחרות.

דוגמאות

בניית התבנית

כדי ליצור URLPattern, צריך להעביר את הבנאי שלו מחרוזות או אובייקט שהמאפיינים שלו מכילים מידע על התבנית להתאמה.

העברת אובייקט מציעה את השליטה המפורשת ביותר על הדפוס שבו יש להשתמש להתאמה לכל רכיב של כתובת אתר. באופן המפורט ביותר, זה יכול להיראות כך

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
  search: '*',
  hash: '*',
});

ציון מחרוזת ריקה למאפיין תואם רק אם החלק התואם בכתובת ה-URL לא מוגדר. התו הכללי לחיפוש * יתאים לכל ערך עבור חלק נתון של כתובת ה-URL.

ה-constructor מציע מספר קיצורי דרך לשימוש פשוט יותר. השמטה מלאה של search ו-hash, או כל מאפיין אחר, מקבילה להגדרתם לתו הכללי לחיפוש '*'. אפשר לפשט את הדוגמה הזו

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'});

כחלופה להעברת אובייקט למבנה, ניתן לספק מחרוזת אחת או שתיים. אם מציינים מחרוזת אחת, היא צריכה לייצג דפוס URL מלא, כולל מידע על התבנית להתאמת המקור. במקרה שמספקים שתי מחרוזות, המחרוזת השנייה תשמש כ-baseURL והמחרוזת הראשונה תיחשב ביחס לבסיס הזה.

גם אם מזינים מחרוזת אחת או שתיים, הבונה של URLPattern ינתח את הדפוס המלא של כתובת ה-URL, יפצל אותה לרכיבי כתובת ה-URL וימפה כל חלק מהתבנית הגדולה יותר לרכיב המתאים. המשמעות היא שמתחת לפני השטח, כל URLPattern שנוצר עם מחרוזות מיוצג באופן זהה ל-URLPattern מקביל שנוצר עם אובייקט. בונה המחרוזות הוא רק קיצור דרך, למי שמעדיפים ממשק פחות ארוך.

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, אבל יש להם גם משמעות מיוחדת בתחביר של התאמת התבניות. כדי למנוע את אי-הבהירות הזו, הבנאי URLPattern מניח שכל התווים המיוחדים האלה הם חלק מדפוס ולא חלק מכתובת ה-URL. אם אתם רוצים שתווים לא יהיו ברורים כחלק מכתובת ה-URL, הקפידו להשתמש בתו בריחה (escape) עם הערך \` character. For example, the literal URLabout: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 של הדפדפן.

סיכום של כל המידע

ההדגמה של תקלה שמוטמעת בהמשך ממחישה מקרה שימוש עיקרי של URLPattern בתוך fetch event handler של קובץ שירות (service worker), למיפוי תבניות ספציפיות לפונקציות אסינכרוניות שיכולות ליצור תגובה לבקשות ברשת. את המושגים בדוגמה הזו אפשר ליישם גם בתרחישי ניתוב אחרים, בצד השרת ובצד הלקוח.

משוב ותוכניות עתידיות

למרות שהפונקציונליות הבסיסית של URLPattern הגיעה גם ל-Chrome ול-Edge, אנחנו מתכננים להוסיף עוד תוספות. היבטים מסוימים של URLPattern עדיין נמצאים בפיתוח, ויש כמה שאלות פתוחות לגבי התנהגויות ספציפיות שעדיין אפשר לחדד אותן. אנחנו ממליצים לנסות את URLPattern ולשלוח משוב על בעיה ב-GitHub.

תמיכה ביצירת תבניות

הספרייה path-to-regexp מספקת רכיב compile() function שהופך בפועל את התנהגות הניתוב. הפונקציה compile() מקבלת את התבנית והערכים של ה-placeholders של האסימון, ומחזירה מחרוזת לנתיב כתובת ה-URL עם הערכים האלה.

אנחנו מקווים להוסיף את המאפיין הזה ל-URLPattern בעתיד, אבל הוא לא נכלל בגרסה הראשונית.

הפעלת תכונות עתידיות של פלטפורמת אינטרנט

בהנחה ש-URLPattern הופך לחלק מבוסס של פלטפורמת האינטרנט, תכונות אחרות שעשויות להפיק תועלת מהתאמת ניתוב או מהתאמת דפוסים יכולות להתבסס על זה כפרימיטיבית.

אנחנו מקיימים דיונים לגבי השימוש ב-URLPattern בתכונות מוצעות כמו התאמת תבניות להיקף של Service Worker, PWA כרכיבי handler של קבצים, ושליפה מראש ספקולטיבית.

אישורים

רשימת התודות המלאה מופיעה במסמך ההסבר המקורי.