Documentação
/

Solução de problemas

/

Evitando colisões de identificadores

Evitando colisões de identificadores

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:

Text

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

Text

-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 (o identifiersPrefix padrão). 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 const vmd = … de nível superior caem no mesmo escopo, e o parser rejeita a segunda.

Opções que introduzem mais identificadores de nível superior aumentam a chance de dois arquivos chegarem ao mesmo nome gerado. vmWrapTopLevelInitializers é uma delas, e todas as predefinições VM já a ativam; opções como vmDynamicOpcodes ou vmBytecodeEncoding adicionam mais.

Soluções

Prefira fazer o bundle 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 por arquivo quando você usa a ofuscação em lote de vários arquivos, que está disponível nos planos pagos. Se você usa um plugin de bundler, verifique o comportamento dele em vez de supor que faz o mesmo. Se você está montando a ofuscação manualmente com a API do npm, precisa ativar um prefixo por conta própria.

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