العناصر الخارجية وعمليات التصدير

الغرض من تحويل أطراف خارجية

الاستثناءات هي تصريحات تخبر Closure Compiler بأسماء الرموز التي يجب عدم إعادة تسميتها أثناء التجميع المتقدّم. ويُطلق عليها أسماء خارجية لأنّ هذه الرموز غالبًا ما يتم تحديدها باستخدام رمز خارج نطاق التجميع، مثل رموز برمجية أصلية أو مكتبات تابعة لجهات خارجية. ولهذا السبب، غالبًا ما يكون للخارجيين نوع من التعليقات التوضيحية، وذلك حتى يتمكّن محوّل الإغلاق من التحقق من استخدامك لهذه الرموز.

بشكل عام، من الأفضل اعتبار العناصر الخارجية عقدًا لواجهة برمجة التطبيقات بين منفّذ التنفيذ ومستهلكي جزء من الرمز البرمجي. تحدّد المصادر الخارجية ما يتعهد به منفّذ التنفيذ بتقديم البيانات وما يمكن أن يعتمد عليه المستهلكون. يحتاج كلا الطرفين إلى نسخة من العقد.

تتشابه الامتدادات مع ملفات العناوين بلغات أخرى.

بنية خارج النظام

حوسبة الملفات الخارجية هي ملفات تشبه إلى حد كبير ملفات JavaScript العادية التي تم التعليق عليها في Closure Compiler. ويتمثل الاختلاف الرئيسي في أن المحتوى لا تتم طباعته مطلقًا كجزء من الإخراج المجمَّع، لذلك ليس لأي من القيم أي دلالة، بل تمثّل الأسماء والأنواع فقط.

في ما يلي مثال على ملف Externs لمكتبة بسيطة.

// 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،

ومع ذلك، هناك طريقة أخرى قديمة لتحديد ملفات EXtern. يمكن استخدام علامة سطر الأوامر --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;
}
    

كيفية تضمين العناصر الخارجية باستخدام واجهة برمجة تطبيقات خدمة Closure Compiler

يسمح كل من تطبيق Closure Compiler وواجهة برمجة تطبيقات خدمة Closure Compiler بتصريحات خارجية. ومع ذلك، لا توفّر واجهة مستخدم خدمة Closure Compiler عنصر واجهة لتحديد ملفات خارجية.

هناك ثلاث طرق لإرسال بيان بالطلبات الخارجية إلى خدمة Closure Compiler:

  • مرر ملفًا يحتوي على التعليق التوضيحي @externs كملف مصدر.
  • تمرير JavaScript إلى خدمة Closure Compiler في المَعلمة js_externs
  • تمرير عنوان URL لملف JavaScript إلى خدمة Closure Compiler في المَعلمة externs_url

الاختلاف الوحيد بين استخدام js_externs واستخدام externs_url هو كيفية توصيل JavaScript إلى خدمة Closure Compiler.

الغرض من عمليات التصدير

عمليات التصدير هي آلية أخرى لإعطاء الرموز أسماء متسقة بعد التجميع. وهي أقل إفادة من تلك التي تكون خارج نطاق النظام، وغالبًا ما تكون مربكة. ويُفضّل تجنّبها في جميع الحالات باستثناء الحالات البسيطة.

تعتمد عمليات التصدير على حقيقة أن محول القراءة لا يُعدِّل القيم الحرفية للسلسلة. من خلال تعيين عنصر إلى خاصية مسماة باستخدام قيمة حرفية، سيكون الكائن متاحًا من خلال اسم الخاصية هذا حتى بعد التجميع.

في ما يلي مثال بسيط.

/**
 * @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;
    

إذا كنت تستخدم "مكتبة الإغلاق"، يمكن أيضًا إدراج عمليات التصدير باستخدام الدالتين goog.exportSymbol وgoog.exportProperty.

يمكنك الاطّلاع على المزيد من المعلومات في مستندات مكتبة الإغلاق الخاصة بهذه الدوال. يُرجى العِلم أنّه يتوفّر لها دعم خاص للمحول البرمجي وسيتم تحويلها بالكامل في المخرجات المجمَّعة.

مشاكل متعلقة بعمليات التصدير

تختلف عمليات التصدير عن العناصر الخارجية في أنها لا تنشئ إلا اسمًا مستعارًا مكشوفًا للمستهلكين للرجوع إليه. ضمن الرمز المجمّع، سيظل من الممكن إعادة تسمية الرمز الذي تم تصديره. ولهذا السبب، يجب أن تكون الرموز المُصدَّرة ثابتة، لأن إعادة ضبطها في الرمز سيؤدي إلى الإشارة إلى الاسم المستعار المكشوف.

هذه درجة الدقة في إعادة التسمية معقدة بشكل خاص في ما يتعلق بخصائص المثيلات التي تم تصديرها.

من الناحية النظرية، يمكن أن تسمح عمليات التصدير بحجم رمز أصغر مقارنةً بالبرامج الخارجية، حيث يمكن تغيير الأسماء الطويلة إلى أسماء أقصر ضمن الرمز. من الناحية العملية، غالبًا ما تكون هذه التحسينات بسيطة جدًا، ولا تبرر الارتباك الذي تسببه عمليات التصدير.

ولا توفّر عمليات التصدير أيضًا واجهة برمجة تطبيقات للمستهلكين لاتّباعها بالطريقة نفسها التي تتّبعها الأنظمة الخارجية. بالمقارنة مع عمليات التصدير، توثق عمليات التصدير الخارجية الرموز التي تنوي عرضها وأنواعها وتمنحك مكانًا لإضافة معلومات الاستخدام. بالإضافة إلى ذلك، إذا كان المستهلكون يستخدمون أيضًا Closure Compiler، سيحتاجون إلى الاستعانة بمصادر خارجية ليتم جمعها.