Externes et exportations

Objets externes

Les externs sont des déclarations indiquant à Closure Compiler les noms des symboles qui ne doivent pas être renommés lors de la compilation avancée. Elles sont appelées externs, car ces symboles sont le plus souvent définis par du code situé en dehors de la compilation, tel qu'un code natif ou des bibliothèques tierces. C'est pourquoi les externs comportent souvent des annotations de type, afin que Closure Compiler puisse vérifier votre utilisation de ces symboles.

En général, il est préférable de considérer les externs comme un contrat d'API entre l'exécuteur et les consommateurs d'un extrait de code compilé. Les externs définissent ce que le responsable de la mise en œuvre promet de fournir et ce dont les consommateurs peuvent dépendre. Les deux côtés ont besoin d'une copie du contrat.

Les externs sont similaires aux fichiers d'en-tête des autres langues.

Syntaxe Externs

Les externs sont des fichiers très semblables aux annotations JavaScript normales pour Closure Compiler. La principale différence est que leur contenu n'est jamais imprimé dans le résultat compilé. Ainsi, aucune des valeurs n'a de sens, mais uniquement les noms et les types.

Vous trouverez ci-dessous un exemple de fichier d'externs pour une bibliothèque simple.

// 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) {};
    

L'indicateur --externs

En règle générale, l'annotation @externs est le meilleur moyen d'informer le compilateur qu'un fichier contient des externs. Ces fichiers peuvent être inclus en tant que fichiers sources normaux à l'aide de l'option de ligne de commande --js.

Toutefois, il existe une autre méthode plus ancienne pour spécifier des fichiers d'externs. L'option de ligne de commande --externs permet de transmettre explicitement des fichiers externes. Cette méthode n'est pas recommandée.

Utiliser des externs

Les externs de l'espace ci-dessus peuvent être consommés comme suit.

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

Inclure Externs avec l'API Closure Compiler Service

L'application Closure Compiler et l'API du service Closure Compiler autorisent les déclarations externes. Toutefois, l'interface utilisateur du service Closure Compiler ne fournit pas d'élément d'interface permettant de spécifier des fichiers externes.

Il existe trois manières d'envoyer une déclaration externe au service Closure Compiler:

  • Transmettez un fichier contenant l'annotation @externs en tant que fichier source.
  • Transmettez le code JavaScript au service Closure Compiler dans le paramètre js_externs.
  • Transmettez l'URL d'un fichier JavaScript au service Closure Compiler dans le paramètre externs_url.

La seule différence entre l'utilisation de js_externs et de externs_url est la manière dont le code JavaScript est communiqué au service Closure Compiler.

Objectif des exportations

Les exportations constituent un autre mécanisme permettant d'attribuer des noms cohérents aux symboles après la compilation. Ils sont moins utiles que des externs et déroutants. Il est préférable d'éviter ces cas simples, mais simples.

Les exportations reposent sur le fait que Closure Compiler ne modifie pas les littéraux de chaîne. En attribuant un objet à une propriété nommée à l'aide d'un littéral, l'objet est disponible via ce nom de propriété même après la compilation.

Vous trouverez ci-dessous un exemple simple.

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

Si vous utilisez la bibliothèque Closure Library, vous pouvez également déclarer les exportations à l'aide des fonctions goog.exportSymbol et goog.exportProperty.

Pour en savoir plus sur ces fonctions, consultez la documentation de la bibliothèque Closure. Toutefois, sachez qu'ils sont spécialement compatibles avec le compilateur et qu'ils seront complètement transformés dans la sortie compilée.

Problèmes liés aux exportations

Contrairement aux exportations, les exportations ne créent qu'un alias exposé que les consommateurs peuvent référencer. Dans le code compilé, le symbole exporté sera toujours renommé. Pour cette raison, les symboles exportés doivent être constants, car si vous les réattribuez dans le code, l'alias exposé pointe vers la mauvaise chose.

Cette subtilité dans le changement de nom est particulièrement compliquée en ce qui concerne les propriétés d'instance exportées.

En théorie, les exportations peuvent autoriser une taille de code inférieure à celle des externs, car les noms longs peuvent toujours être remplacés par des noms plus courts dans votre code. En pratique, ces améliorations sont souvent très mineures et ne justifient pas la confusion générée par les exportations.

Les exportations ne fournissent pas non plus d'API que les utilisateurs peuvent suivre de la même manière que les externs. Comparées aux exportations, les externs documentent les symboles que vous prévoyez d'exposer et leur type, et vous permettent d'ajouter des informations sur l'utilisation. De plus, si vos clients utilisent également Closure Compiler, des externs doivent être compilés.