Esterni ed esportazioni

Scopo dell'esterno

Le estensioni esterne sono dichiarazioni che indicano al componente Closure Compiler i nomi dei simboli che non devono essere rinominati durante la compilazione avanzata. Vengono definiti esterni perché questi simboli sono definiti più spesso da una porzione di codice esterna alla compilation, ad esempio un codice nativo o librerie di terze parti. Per questo motivo, le volte esterne hanno anche annotazioni di tipo, in modo che Closure Compiler possa controllare l'utilizzo di questi simboli.

In generale, la soluzione migliore è considerare un contratto API come un contratto tra l'implementatore e i consumatori di una porzione di codice compilato. I dettagli esterni definiscono ciò che l'implementatore promette di fornire e ciò che i consumatori possono fare affidamento sull'utilizzo. Le due parti hanno bisogno di una copia del contratto.

Le estensioni sono simili ai file di intestazione in altre lingue.

Sintassi esterna

Le estensioni sono file simili a quelli delle normali annotazioni JavaScript per Closure Compiler. La differenza principale è che i loro contenuti non vengono mai stampati come parte dell'output compilato, quindi nessuno dei valori è significativo, solo i nomi e i tipi.

Di seguito è riportato un esempio di un file esterno di una semplice libreria.

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

Bandiera --externs

In genere, l'annotazione @externs è il modo migliore per informare il compilatore che un file contiene elementi esterni. Questi file possono essere inclusi come normali file di origine utilizzando il flag della riga di comando --js,

Esiste un altro modo, meno recente, per specificare i file esterni. Il flag della riga di comando --externs può essere utilizzato per passare esplicitamente i file esterni. Questo metodo non è consigliato.

Utilizzo di esterni

Le destinazioni esterne riportate sopra possono essere utilizzate come segue.

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

Come includere gli esterni con l'API Closure Compiler Service

Sia l'applicazione Closure Compiler che l'API del servizio Closure Compiler consentono le dichiarazioni esterne. Tuttavia, l'UI del servizio Closure Compiler non fornisce un elemento dell'interfaccia per specificare i file esterni.

Esistono tre modi per inviare una dichiarazione esterna al servizio di compilazione Closure:

  • Passa un file contenente l'annotazione @externs come file di origine.
  • Passa JavaScript al servizio Closure Compiler nel parametro js_externs.
  • Passa l'URL di un file JavaScript al servizio Closure Compiler nel parametro externs_url.

L'unica differenza tra l'utilizzo di js_externs e l'utilizzo di externs_url è il modo in cui JavaScript viene comunicato al servizio Closure Compiler.

Scopo delle esportazioni

Le esportazioni sono un altro meccanismo per assegnare simboli a nomi coerenti dopo la compilazione. Sono meno utili degli esterni e spesso sono confusi. Per tutti i casi tranne quelli semplici, è meglio evitarli.

Le esportazioni si basano sul fatto che il componente Closure Compiler non modifica i valori letterali delle stringhe. L'assegnazione di un oggetto a una proprietà denominata tramite un valore letterale sarà disponibile tramite il nome della proprietà anche dopo la compilazione.

Di seguito è riportato un semplice esempio.

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

Se utilizzi la libreria di chiusura, le esportazioni possono anche essere dichiarate utilizzando le funzioni goog.exportSymbol e goog.exportProperty.

Ulteriori informazioni sono disponibili nella documentazione della libreria di chiusura di queste funzioni. Tuttavia, tieni presente che il loro supporto speciale viene compilato e trasformato completamente nell'output compilato.

Problemi con le esportazioni

Le esportazioni sono diverse dalle esterne, in quanto creano solo un alias esposto a cui i consumatori possono fare riferimento. All'interno del codice compilato, il simbolo esportato verrà comunque rinominato. Per questo motivo, i simboli esportati devono essere costanti, perché la loro riassegnazione nel codice potrebbe indirizzare l'alias esposto alla risorsa sbagliata.

Questa sottigliezza nella ridenominazione è particolarmente complicata rispetto alle proprietà delle istanze esportate.

In teoria, le esportazioni possono consentire dimensioni del codice inferiori rispetto alle estensioni esterne, poiché i nomi lunghi possono comunque essere modificati in quelli più brevi all'interno del codice. In pratica, questi miglioramenti sono spesso molto minori e non giustificare la confusione creata dalle esportazioni.

Inoltre, le esportazioni non forniscono un'API da seguire per i consumatori, così come le esportazioni mostrano i simboli che intendi esporre e i relativi tipi e ti consentono di aggiungere informazioni sull'utilizzo. Inoltre, se i tuoi consumatori utilizzano anche il componente Closure Compiler, dovranno compilare i campi esistenti.