Finalidade das funções externas
Externas são declarações que informam ao Compiler de nomes os nomes dos símbolos que não devem ser renomeados durante a compilação avançada. Eles são chamados de "exteriores" porque geralmente são definidos por código fora da compilação, como um código nativo ou bibliotecas de terceiros. Por esse motivo, muitas vezes, as funções externas também têm anotações de tipo, para que o Compiler Compiler possa verificar o uso desses símbolos.
Em geral, é melhor pensar "externamente" como um contrato de API entre o implementador e os consumidores de algum código compilado. As externas definem o que o implementador promete fornecer e o que os consumidores podem depender de usar. Ambas as partes precisam de uma cópia do contrato.
As funções externas são semelhantes aos arquivos principais em outras linguagens.
Sintaxe de funções externas
Externas são arquivos que se parecem muito com o JavaScript normal anotado para o Compile Compiler. A principal diferença é que o conteúdo nunca é impresso como parte da saída compilada. Portanto, nenhum dos valores é significativo, apenas os nomes e tipos.
Veja abaixo um exemplo de arquivo externo para uma biblioteca simples.
// 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) {};
A sinalização --externs
Geralmente, a anotação @externs
é a melhor maneira de informar
ao compilador que um arquivo contém funções externas. Esses arquivos podem ser incluídos
como arquivos de origem normais usando a sinalização de linha de comando --js
.
No entanto, há outra maneira mais antiga de especificar arquivos externos. A
sinalização de linha de comando --externs
pode ser usada para transmitir arquivos
externos explicitamente. Esse método não é recomendado.
Como usar funções externas
As funções externas acima podem ser consumidas da seguinte maneira.
/** * @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; }
Como incluir funções externas com a API Frontend Compiler
Tanto o aplicativo Frontend Compiler quanto a API Frontend Compiler permitem declarações externas. No entanto, a IU do serviço do Frontend Compiler não fornece um elemento de interface para especificar arquivos externos.
Há três maneiras de enviar uma declaração externa para o serviço Compile Compiler:
-
Transmita um arquivo que contenha a anotação
@externs
como um arquivo de origem. -
Transmita o JavaScript para o serviço Compile Compiler no parâmetro
js_externs
. -
Transmita o URL de um arquivo JavaScript ao serviço do Frontend Compiler
no parâmetro
externs_url
.
A única diferença entre usar js_externs
e
externs_url
é como o JavaScript é comunicado ao
serviço de fechamento de fechamento.
Finalidade das exportações
As exportações são outro mecanismo para dar nomes consistentes a símbolos após a compilação. Elas são menos úteis do que as externas e muitas vezes são confusas. Para todos os casos, exceto os simples, é melhor evitar.
As exportações dependem do fato de o Frontend Compiler não modificar literais de string. Ao atribuir um objeto a uma propriedade nomeada usando um literal, ele ficará disponível por esse nome de propriedade, mesmo após a compilação.
Veja abaixo um exemplo simples.
/** * @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 você estiver usando a biblioteca outro tipo, as exportações também poderão ser declaradas com as
funções goog.exportSymbol
e goog.exportProperty
.
Veja mais informações na documentação da Biblioteca Encerramento dessas funções. No entanto, esteja ciente de que eles oferecem compatibilidade especial para compilador e serão totalmente transformados na saída compilada.
Problemas com exportações
As exportações são diferentes das externas, porque criam apenas um alias exposto para os consumidores consultarem. No código compilado, o símbolo exportado ainda será renomeado. Por esse motivo, os símbolos exportados precisam ser constantes, já que a reatribuição deles no seu código faria com que o alias exposto apontasse para o nome errado.
Essa sutileza na renomeação é especialmente complicada em relação às propriedades da instância exportadas.
Em teoria, as exportações podem permitir um tamanho de código menor em comparação com funções externas, já que nomes longos ainda podem ser alterados para códigos menores dentro do código. Na prática, essas melhorias geralmente são muito pequenas e não justificam a confusão das exportações.
As exportações também não oferecem uma API para os consumidores seguirem o comportamento dos clientes externos. Em comparação com as exportações, as externas não documentam os símbolos que você pretende expor, os tipos deles e oferecem um lugar para adicionar informações de uso. Além disso, se os consumidores também estiverem usando o Frontend Compiler, eles vão precisar de esgotamentos para a compilação.