Documentação
/

Solução de problemas

/

Evitando colisões de identificadores

Evitando colisões de identificadores entre arquivos ofuscados

Quando vários arquivos ofuscados por VM acabam no mesmo bundle, eles podem declarar o mesmo identificador de nível superior e derrubar a página no momento do parse. Veja por que isso acontece e como resolver.

O sintoma

O seu build roda sem problemas, mas o navegador lança um erro no parse, antes de o app iniciar:

Texto

Para ver quantos chunks declaram o nome do erro, conte os arquivos que contêm uma declaração dele:

Texto

-l lista cada arquivo correspondente uma única vez e -w corresponde apenas a palavras inteiras, então vmdX não é contado. var fica de fora porque repetir uma declaração var não é um erro por si só. Um resultado acima de 1 significa que o nome é declarado em mais de um chunk. Substitua vmd pelo nome da sua mensagem de erro.

Colisões de identificadores só importam quando as declarações compartilham um escopo. O mesmo nome repetido em módulos ou closures separados não prova uma colisão; o erro de parse acima prova.

Por que isso acontece

As predefinições VM usam mangled-shuffled como Identifier Names Generator. Ele percorre um alfabeto pequeno em uma ordem embaralhada e, com a ofuscação VM, todo global renomeado recebe um prefixo vm (adicionado antes de qualquer identifiersPrefix que você definir, então checkout_ vira vm_checkout_...). A ordem embaralhada fica em cache por processo, então arquivos ofuscados no mesmo processo, ou com o mesmo seed fixo, tiram nomes da mesma sequência - o primeiro global de cada arquivo tem o mesmo nome, o segundo tem outro nome em comum, e assim por diante.

Cada arquivo é ofuscado de forma independente, e o gerador recomeça do início da sequência para cada um. Quando dois arquivos acabam no mesmo escopo, os nomes colidem. Duas declarações let vmd de nível superior caem no mesmo escopo, e o parser rejeita a segunda.

Cada arquivo ofuscado pela VM declara um nome de runtime de nível superior sem sufixo, e isso basta para colidir. renameGlobals: true piora muito a situação: toda declaração de nível superior vira um nome vm* curto, e os nomes do próprio runtime perdem o sufixo único.

Soluções

Prefira empacotar primeiro e depois ofuscar o bundle uma única vez. Se você ofuscar separadamente e os scripts compartilharem um escopo global, escolha uma das opções a seguir:

  • Ative randomIdentifiersPrefix (recomendado)

    Cada execução da ofuscação recebe um prefixo aleatório adicionado a todos os identificadores globais (na ofuscação VM, ele substitui o prefixo vm padrão). Os nomes de arquivos diferentes deixam de compartilhar um namespace, então as colisões desaparecem sem que você precise coordenar prefixos manualmente.

  • Defina um identifiersPrefix único por arquivo

    Passe manualmente um prefixo diferente ao ofuscar cada arquivo (por exemplo, identifiersPrefix: 'auth_' para um, checkout_ para outro). Funciona, mas é propenso a erros se você tiver muitos arquivos - prefira a opção aleatória acima.

    JavaScript

  • Mude identifierNamesGenerator para hexadecimal

    Nomes hexadecimais usam um espaço de chaves muito maior, então é bem menos provável que dois arquivos produzam o mesmo identificador - mas a unicidade não é garantida. Contrapartida: os identificadores são mais longos que a saída de mangled-shuffled, então o bundle fica um pouco maior.

  • Use a interface de lote com vários arquivos ou verifique o plugin do seu bundler

    O painel adiciona um prefixo distinto a cada arquivo dentro de um mesmo lote com vários arquivos (planos pagos); arquivos de lotes separados ainda podem colidir. Se você usa um plugin de bundler, verifique o comportamento dele em vez de supor que faz o mesmo. Se você chama o pacote javascript-obfuscator ou a API por conta própria, precisa ativar um prefixo.

Para verificar a correção, refaça o build, recarregue a aplicação combinada e confirme que o SyntaxError sumiu. O nome da mensagem de erro antiga não deve mais ser declarado em mais de um chunk; um prefixo muda todos os nomes gerados, então o grep acima só informa sobre aquele nome específico, não sobre os novos.

Opções relacionadas