תוספות וייצוא

מטרה של תוספות

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

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

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

התחביר של קטעי הטקסט החיצוני

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

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

// The `@externs` annotation is the best way to indicate a file contains externs.

/**
 * @fileoverview Public API of my_math.js.
 * @externs
 */

// Externs often declare global namespaces.

const myMath = {};

// Externs can declare functions, most importantly their names.

/**
 * @param {number} x
 * @param {number} y
 * @return {!myMath.DivResult}
 */
myMath.div = function(x, y) {};  // Note the empty body.

// Externs can contain type declarations, such as classes and interfaces.

/** The result of an integer division. */
myMath.DivResult = class {

  // Constructors are special; member fields can be declared in their bodies.

  constructor() {
    /** @type {number} */
    this.quotient;
    /** @type {number} */
    this.remainder;
  }

  // Methods can be declared as usual; their bodies are meaningless though.

  /** @return {!Array<number>} */
  toPair() {}

};

// Fields and methods can also be declared using prototype notation.

/**
 * @override
 * @param {number=} radix
 */
myMath.DivResult.prototype.toString = function(radix) {};
    

הדגל --externs

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

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

שימוש בתוספים

ניתן לצרוך את התוכן החיצוני מלמעלה.

/**
 * @fileoverview Do some math.
 */

/**
 * @param {number} x
 * @param {number} y
 * @return {number}
 */
export function greatestCommonDivisor(x, y) {
  while (y != 0) {
    const temp = y;
    // `myMath` is a global, it and `myMath.div` are never renamed.
    const result = myMath.div(x, y);
    // `remainder` is also never renamed on instances of `DivResult`.
    y = result.remainder;
    x = temp;
  }
  return x;
}
    

איך לכלול תוספים עם ממשק ה-API של Cloud Compiler Service

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

יש שלוש דרכים לשלוח הצהרה חיצונית אל השירות 'מהדר סגירה':

  • העברת קובץ שמכיל את ההערה @externs כקובץ מקור.
  • מעבירים את JavaScript לשירות מהדר סגירה בפרמטר js_externs.
  • צריך להעביר את כתובת ה-URL של קובץ JavaScript לשירות 'הסגר' בפרמטר externs_url.

ההבדל היחיד בין השימוש ב-js_externs לבין השימוש ב-externs_url הוא האופן שבו JavaScript מועבר לשירות מהדר הסגירה.

מטרת הייצוא

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

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

הנה דוגמה פשוטה:

/**
 * @fileoverview Do some math.
 */

// Note that the concept of module exports is totally unrelated.

/** @return {number} */
export function myFunction() {
  return 5;
}

// This assignment ensures `myFunctionAlias` will be a global alias exposing `myFunction`,
// even after compilation.

window['myFunctionAlias'] = myFunction;
    

אם משתמשים ב-Clot Library, ניתן להצהיר על פעולות ייצוא גם באמצעות הפונקציות goog.exportSymbol ו-goog.exportProperty.

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

בעיות בייצוא

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

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

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

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