Mapas de origem: rápido e fácil





O mecanismo de Mapas de Origem é usado para mapear os códigos-fonte do programa para scripts gerados em suas bases. Apesar de o tópico não ser novo e de vários artigos já terem sido escritos sobre ele (por exemplo, este , este e este ), alguns aspectos ainda precisam ser esclarecidos. O artigo apresentado é uma tentativa de organizar e sistematizar tudo o que é conhecido sobre este tópico de forma concisa e acessível.



O artigo discute os Mapas de origem em relação ao desenvolvimento do cliente no ambiente de navegadores populares (por exemplo, Google Chrome DevTools), embora seu escopo não esteja vinculado a nenhum idioma ou ambiente específico. A principal fonte de Mapas de Origem é, obviamente, o padrão , embora ainda não tenha sido adotado (status - proposta), mas, no entanto, é amplamente suportado pelos navegadores.



O trabalho no Maps Source começou no final dos anos 2000, com a primeira versão sendo criada para o plug-in Firebug Closure Inspector. A segunda versão foi lançada em 2010 e continha alterações em termos de redução do tamanho do arquivo de mapa. A terceira versão foi desenvolvida como parte de uma colaboração entre Google e Mozilla e proposta em 2011 (última revisão em 2013).



Atualmente, existe uma situação no ambiente de desenvolvimento do cliente em que o código-fonte quase nunca é integrado diretamente à página da Web, mas passa por várias etapas de processamento: minificação, otimização, concatenação, além disso, o próprio código-fonte pode ser escrito em linguagens que exigem transpilação ... Nesse caso, para fins de depuração, você precisa de um mecanismo que permita observar no depurador exatamente o código de origem legível por humanos.



Mapas de origem requer os seguintes arquivos:



  • o arquivo JavaScript gerado real
  • o conjunto de arquivos de origem usado para criá-lo
  • arquivo de mapeamento, mapeando-os um ao outro


Arquivo de mapa



Todo o trabalho do Source Maps é baseado em um arquivo de mapa, que pode ser assim:



{
    "version":3,
    "file":"index.js",
    "sourceRoot":"",
    "sources":["../src/index.ts"],
    "names":[],
    "mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,SAAS,SAAS;IACd,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;",
    "sourcesContent": []
}


Geralmente, o nome do arquivo de mapa é composto pelo nome do script ao qual ele pertence, com a adição da extensão ".map", bundle.js - bundle.js.map. Este é um arquivo json comum com os seguintes campos:



  • "Versão" - versão do Mapas de Origem;
  • "Arquivo" - (opcionalmente) o nome do arquivo gerado, ao qual o arquivo de mapa atual pertence;
  • "SourceRoot" - prefixo (opcional) para caminhos para arquivos de origem;
  • "Fontes" - uma lista de caminhos para os arquivos de origem (resolvidos da mesma maneira que os endereços src da tag de script, você pode usar file: //.);
  • "Nomes" - uma lista de nomes de variáveis ​​e funções que foram alteradas no arquivo gerado;
  • "Mapeamentos" - coordenadas de mapeamento de variáveis ​​e funções dos arquivos de origem para um arquivo gerado no formato Base64 VLQ;
  • "SourcesContent" - (opcional) no caso de um arquivo de mapa independente, uma lista de linhas, cada uma das quais contém o texto fonte do arquivo a partir das fontes;


Baixar mapas de origem



Para que o navegador carregue o arquivo de mapa, um dos seguintes métodos pode ser usado:



  • O arquivo JavaScript veio com um cabeçalho HTTP: SourceMap: <url> (o X-SourceMap anteriormente obsoleto: <url> foi usado anteriormente)
  • o arquivo JavaScript gerado possui um comentário especial como:


//# sourceMappingURL=<url> ( CSS /*# sourceMappingURL=<url> */)


Assim, após carregar o arquivo de mapa, o navegador puxa as fontes do campo "sources" e, usando os dados no campo "mappings", as exibe no script gerado. Na guia DevTools de fontes, você pode encontrar as duas opções.



O arquivo: // pseudoprotocol pode ser usado para especificar o caminho. Além disso, o conteúdo do arquivo de mapa codificado em base64 pode ser incluído no <url>. Na terminologia do Webpack, os Mapas de Origem como esses são chamados de mapas de origem embutidos.



//# sourceMappingURL=data:application/json;charset=utf-8;base64,<source maps Base64 code>


Erros de carregamento de mapas de origem
, map- -, Network DevTools. , map-, Console DevTools : «DevTools failed to load SourceMap: ...». , : «Could not load content for ...».



Arquivos de mapa independentes



O código dos arquivos de origem pode ser incluído diretamente no arquivo de mapa no campo "sourcesContent"; se esse campo estiver presente, não será necessário fazer o download separadamente. Nesse caso, os nomes dos arquivos em "fontes" não refletem seu endereço real e podem ser completamente arbitrários. É por isso que, na guia Fontes do DevTools, você pode ver "protocolos" tão estranhos: webpack: //, ng: //, etc.



Mapeamentos



A essência do mecanismo de mapeamento é que as coordenadas (linha / coluna) dos nomes de variáveis ​​e funções no arquivo gerado são mapeadas para as coordenadas no arquivo de código-fonte correspondente. Para que o mecanismo de exibição funcione, são necessárias as seguintes informações:



(# 1) número da linha no arquivo gerado;

(# 2) número da coluna no arquivo gerado;

(# 3) índice da fonte em "fontes";

(# 4) número da linha de origem;

(# 5) número da coluna de origem;



Todos esses dados estão no campo "mapeamentos", cujo valor é uma cadeia longa com uma estrutura especial e valores codificados no Base64 VLQ.



A linha é dividida por ponto e vírgula (;) em seções correspondentes às linhas no arquivo gerado (# 1).



Cada seção é separada por vírgulas (,) em segmentos, cada um dos quais pode conter 1,4 ou 5 valores:



  • o número da coluna no arquivo gerado (# 2);
  • índice de origem em "fontes" (nº 3);
  • número da linha de origem (nº 4);
  • número da coluna de origem (nº 5);
  • índice do nome da variável / função da lista de nomes;


Os valores dos números de linha e coluna são relativos, indicam o deslocamento em relação às coordenadas anteriores e apenas o primeiro desde o início do arquivo ou seção.



Cada valor é um número Base64 VLQ. VLQ (quantidade de comprimento variável) é o princípio de codificar um número arbitrariamente grande usando um número arbitrário de blocos binários de comprimento fixo.



O Source Maps usa blocos de seis bits, ordenados de baixo para alto. O sexto bit mais significativo de cada bloco (bit de continuação) é reservado, se estiver definido, o atual é seguido pelo próximo bloco relacionado ao mesmo número, se for limpo, a sequência está concluída.



Como os mapas de origem devem ter um sinal, o bit de sinal também é reservado para ele, mas apenas no primeiro bloco da sequência. Como esperado, um bit de sinal definido significa um número negativo.



Assim, se um número pode ser codificado com um único bloco, ele não pode ser o módulo 15 (1111 2 ), uma vez que no primeiro bloco de seis bits da sequência dois bits são reservados: o bit de continuação sempre será limpo, o bit de sinal será definido dependendo do sinal do número.



Os blocos VLQ de seis bits são mapeados para a codificação Base64, onde cada sequência de seis bits é mapeada para um caractere ASCII específico.







Decodificamos o número mE. Inversa a ordem, a parte menos significativa da última - Em. Decodificamos os números de Base64: E - 000100, m - 100110. No primeiro, descartamos o bit de continuação mais alto e dois zeros à esquerda - 100. No segundo, descartamos os bits de maior continuidade e baixo sinal (o bit de sinal é limpo - o número é positivo) - 0011. Como resultado, obtemos 100 0011 2 , que corresponde ao decimal 67.



É possível na direção oposta, codificar 41. Seu código binário é 101001 2, dividimos em dois blocos: a parte superior é 10, a parte mais jovem (sempre com 4 bits) é 1001. Adicione o bit de continuação mais significativo (limpo) à parte superior e os três zeros à esquerda - 000010. Adicione o bit de continuação mais significativo (conjunto) à parte inferior e o bit de sinal baixo (limpo - um número positivo) é 110010. Codificamos os números em Base64: 000010 - C, 110010 - y. Invertemos a ordem e, como resultado, obtemos yC.



A biblioteca com o mesmo nome é muito útil para trabalhar com o VLQ .



All Articles