הידור מתקדם

סקירה כללית

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

במדריך הזה נסביר איך רמת האוסף ADVANCED_OPTIMIZATIONS פועלת ומה אפשר לעשות כדי לוודא שהקוד שלכם עובד לאחר הידור האפליקציה ADVANCED_OPTIMIZATIONS. הוא גם מציג את הקונספט של ה-exter: סמל שמוגדר בקוד חיצוני לקוד שמעובד על ידי המהדר.

לפני קריאת המדריך הזה, כדאי שתכירו את התהליך של הידור JavaScript עם אחד הכלים מהדר סגירה (ממשק המשתמש של מהדר), ממשק ה-API של שירות המהדר או אפליקציית המהדר).

הערה לגבי טרמינולוגיה: הדגל --compilation_level בשורת הפקודה תומך בקיצורים המקובלים יותר ב-ADVANCED וב-SIMPLE, וכן ב-ADVANCED_OPTIMIZATIONS וב-SIMPLE_OPTIMIZATIONS המדויקים יותר. המסמך משתמש בצורה ארוכה יותר, אבל אפשר להחליף בין השמות האלה בשורת הפקודה.

  1. דחיסה טובה יותר
  2. איך מפעילים את ADVANCED_LDIMIZATIONS
  3. למה כדאי לשים לב בעת שימוש ב-ADVANCED_PEIMIZATIONS
    1. הסרת קוד שברצונך לשמור
    2. שמות נכס לא עקביים
    3. הכנת שני חלקים של קוד בנפרד
    4. הפניות מנותקות בין קוד שנערך לבין קוד שלא עבר קומפילציה

דחיסה טובה יותר

בעזרת רמת האיסוף של ברירת המחדל ב-SIMPLE_OPTIMIZATIONS, מהדר סגירה מבצע הקטנה של JavaScript על ידי שינוי שמות של משתנים מקומיים. עם זאת, יש סמלים אחרים, מלבד משתנים מקומיים, שאפשר לקצר, ויש דרכים לכווץ קוד מלבד שינוי שמות של סמלים. הידור עם ADVANCED_OPTIMIZATIONS מנצל את כל האפשרויות של כיווץ הקוד.

משווים בין הפלט של SIMPLE_OPTIMIZATIONS לבין ADVANCED_OPTIMIZATIONS של הקוד הבא:

function unusedFunction(note) {
  alert(note['text']);
}

function displayNoteTitle(note) {
  alert(note['title']);
}

var flowerNote = {};
flowerNote['title'] = "Flowers";
displayNoteTitle(flowerNote);

הידור עם SIMPLE_OPTIMIZATIONS מקצר את הקוד כך:

function unusedFunction(a){alert(a.text)}function displayNoteTitle(a){alert(a.title)}var flowerNote={};flowerNote.title="Flowers";displayNoteTitle(flowerNote);

הידור עם ADVANCED_OPTIMIZATIONS מקצר את הקוד באופן מלא כך:

alert("Flowers");

שני הסקריפטים האלה מפיקים התראה המציינת את "Flowers", אבל הסקריפט השני קטן בהרבה.

ברמה ADVANCED_OPTIMIZATIONS יש יותר מקיצור של שמות משתנים בכמה דרכים, כולל:

  • שינוי שמות אגרסיבי יותר:

    כשמשתמשים בשילוב עם SIMPLE_OPTIMIZATIONS, אפשר לשנות את השם של הפרמטרים note של הפונקציות displayNoteTitle() ו-unusedFunction() בלבד, כי אלו המשתנים היחידים בסקריפט שהם מקומיים לפונקציה. ADVANCED_OPTIMIZATIONS גם משנה את השם של המשתנה הגלובלי flowerNote.

  • הסרת קוד מת:

    עריכה עם ADVANCED_OPTIMIZATIONS מסירה את הפונקציה unusedFunction() לגמרי, כי היא אף פעם לא נקראת בקוד.

  • פונקציה בתוך השורה:

    אוסף עם הערך ADVANCED_OPTIMIZATIONS מחליף את הקריאה ל-displayNoteTitle() ב-alert() שמרכיבים את גוף הפונקציה. ההחלפה הזו של קריאה לפונקציה בגוף הטקסט נקראת "inline". אם הפונקציה הייתה מסובכת יותר או מורכבת יותר, הטבעה עשויה לשנות את ההתנהגות של הקוד, אבל מהדר החסימות קובע שבמקרה הזה הטבעה בטוחה וחוסכת מקום. השילוב עם ADVANCED_OPTIMIZATIONS מאפשר גם להציב קבועים קבועים ומשתנים מסוימים, כאשר הוא קובע שניתן לעשות זאת בצורה בטוחה.

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

איך להפעיל את ADVANCED_LDIMIMZATIONS

בממשק המשתמש של Cloud Compiler API, בשירות ה-API של השירות ובאפליקציה, קיימות שיטות שונות להגדרת compilation_level בתור ADVANCED_OPTIMIZATIONS.

איך מפעילים את ADVANCED_OPIMIZATIONS בממשק המשתמש של הכלי לעריכת חסימות

כדי להפעיל את ADVANCED_OPTIMIZATIONS בממשק המשתמש של מהדר סגירה, יש ללחוץ על לחצן הבחירה 'מתקדם'.

איך מפעילים את ADVANCED_OPTIMIZATIONS ב-Clsure Compiler Service API

כדי להפעיל את ADVANCED_OPTIMIZATIONS ב-Closion Service Compiler API, צריך לכלול פרמטר בקשה בשם compilation_level עם הערך ADVANCED_OPTIMIZATIONS, כמו בתוכנית python הבאה:

#!/usr/bin/python2.4

import httplib, urllib, sys

params = urllib.urlencode([
    ('code_url', sys.argv[1]),
    ('compilation_level', 'ADVANCED_OPTIMIZATIONS'),
    ('output_format', 'text'),
    ('output_info', 'compiled_code'),
  ])

headers = { "Content-type": "application/x-www-form-urlencoded" }
conn = httplib.HTTPSConnection('closure-compiler.appspot.com')
conn.request('POST', '/compile', params, headers)
response = conn.getresponse()
data = response.read()
print data
conn.close()

איך מפעילים את ADVANCED_OPTIMIZATIONS באפליקציה מהדר סגירה

כדי להפעיל את ADVANCED_OPTIMIZATIONS באפליקציית מהדר סגירה, יש לכלול את הדגל של שורת הפקודה --compilation_level ADVANCED_OPTIMIZATIONS, כמו בפקודה הבאה:

java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js hello.js

למה צריך לשקול שימוש ב-ADVANCED_PEIMIZATIONS

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

הסרת קוד שברצונך להשאיר

אם תרכיבו רק את הפונקציה הבאה באמצעות ADVANCED_OPTIMIZATIONS, הכלי להשלמת סגירה יוצר פלט ריק:

function displayNoteTitle(note) {
  alert(note['myTitle']);
}

מכיוון שהפונקציה אף פעם לא נקראת ב-JavaScript שמעבירים אל המהדר, ההנחה של מהדר ההנחה מניחה שאין צורך בקוד הזה!

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

עם זאת, אם גיליתם שהכלי לאישור חסימות מסיר את הפונקציות שאתם רוצים לשמור, יש שתי דרכים למנוע זאת:

  • מעבירים את הפונקציות לפונקציה לקוד שמעובד על ידי מהדר סגירה.
  • יש לכלול את הפרטים החיצוניים של הפונקציות שרוצים לחשוף.

בחלקים הבאים אנחנו מפרטים כל אפשרות בפירוט.

פתרון: העברת הקריאות לפונקציה אל הקוד שעברו עיבוד על ידי מהדר הסגירה

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

הפתרון הפשוט ביותר לבעיה הזו הוא להרכיב את הפונקציות שלכם יחד עם החלק של התוכנה שמפעיל את הפונקציות האלה. לדוגמה, מהדר סגירה לא יסיר את displayNoteTitle() כאשר הוא כולל את התוכנית:

function displayNoteTitle(note) {
  alert(note['myTitle']);
}
displayNoteTitle({'myTitle': 'Flowers'});

הפונקציה displayNoteTitle() לא הוסרה במקרה הזה, כי מהדר סגירה רואה שהיא נקראת.

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

פתרון: הוספת תוספים לפונקציות שאתם רוצים לחשוף

מידע נוסף על הפתרון הזה מופיע בהמשך ובדף מידע על ייצוא וייצוא.

שמות נכס לא עקביים

אוסף ההידור של 'סגירה' אף פעם לא משנה את 'מחרוזת' של מחרוזות בקוד, בלי קשר לרמת ההידור שבה אתם משתמשים. כלומר, השילוב עם ADVANCED_OPTIMIZATIONS מתייחס לנכסים שונים בהתאם לקוד הגישה שלהם, באמצעות מחרוזת. אם תשלבו הפניות ממחרוזות לנכס עם הפניות של תחביר נקודה, שם של מהדק סגירה משנה את השם של חלק מההפניות לנכס הזה, אבל לא של אחרות. כתוצאה מכך, סביר להניח שהקוד שלכם לא יפעל כמו שצריך.

לדוגמה, צריך להשתמש בקוד הבא:

function displayNoteTitle(note) {
  alert(note['myTitle']);
}
var flowerNote = {};
flowerNote.myTitle = 'Flowers';

alert(flowerNote.myTitle);
displayNoteTitle(flowerNote);

שתי ההצהרות האחרונות בקוד המקור הזה עושות בדיוק את אותו הדבר. עם זאת, כשדוחסים את הקוד עם ADVANCED_OPTIMIZATIONS, אפשר לקבל:

var a={};a.a="Flowers";alert(a.a);alert(a.myTitle);

ההצהרה האחרונה בקוד הדחוס יוצרת שגיאה. השם של ההפניה הישירה לנכס myTitle שונה ל-a, אבל ההפניה המצוטטת ל-myTitle בתוך הפונקציה displayNoteTitle לא השתנתה. כתוצאה מכך, ההצהרה האחרונה מתייחסת לנכס myTitle שכבר לא קיים.

פתרון: לשמור על עקביות בשמות הנכסים

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

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

הכנת שני חלקים של קוד בנפרד

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

לדוגמה, נניח שיישום מחולק לשני חלקים: חלק שמאחזר נתונים, וחלק שמציג נתונים.

הנה הקוד לאחזור הנתונים:

function getData() {
  // In an actual project, this data would be retrieved from the server.
  return {title: 'Flower Care', text: 'Flowers need water.'};
}

הנה הקוד להצגת הנתונים:

var displayElement = document.getElementById('display');
function displayData(parent, data) {
  var textElement = document.createTextNode(data.text);
  parent.appendChild(textElement);
}
displayData(displayElement, getData());

אם תנסו להדר את שני קטעי הקוד האלה בנפרד, תיתקלו בכמה בעיות. תחילה, מהדר החסימות מסיר את הפונקציה getData() מהסיבות שמפורטות בהסרת הקוד שרוצים לשמור. שנית, מהדר סגירה יוצר שגיאה חמורה בעת עיבוד הקוד שמציג את הנתונים.

input:6: ERROR - variable getData is undefined
displayData(displayElement, getData());

מכיוון שלדור המהדר אין גישה לפונקציה getData() בזמן ההידור של הקוד שמציג את הנתונים, הוא מתייחס ל-getData כ"לא מוגדר".

פתרון: עריכת כל הקוד לדף אחד

כדי להבטיח הידור מתאים, הרכב את כל הקוד של דף יחד ברכיב הידור אחד. מהדר סגירה יכול לקבל קובצי JavaScript ומחרוזות JavaScript מרובות כקלט, כדי שתוכלו להעביר ביחד את קוד הספרייה וקוד אחר בבקשת הידור אחת.

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

הפניות קטועות בין קוד שנוצר לבין קוד ללא הידור

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

חשוב לזכור שהקטע "קוד לא מורכב" כולל כל קוד שמועבר לפונקציה eval() כמחרוזת. מהדר סגירה לא משנה אף פעם ליטרל מחרוזות בקוד, אז מהדר סגירה לא משנה מחרוזות שהועברו להצהרות eval().

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

לפני שתמשיכו, כדאי להכיר את המידע החיצוני והייצוא.

פתרון קריאה לקוד חיצוני מקוד הידור: עריכה עם תוספות

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

דוגמאות נפוצות לכך הן ממשקי API כמו OpenSocial API ו-Google Maps API. לדוגמה, אם הקוד שלכם מבצע קריאה לפונקציה OpenSocial opensocial.newDataRequest(), ללא הפונקציות החיצוניות, מהדר הסגירה יהפוך את הקריאה הזו ל-a.b().

פתרון לקריאת קוד שהורכב מקוד חיצוני: הטמעת רכיבים חיצוניים

אם יש לכם קוד JavaScript שמשמש אתכם כספרייה, כדאי להשתמש בכלי מהדר סגירה כדי לכווץ רק את הספרייה, ובמקביל לאפשר לקוד לא מעובד להפעיל פונקציות בספרייה.

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

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

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

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

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