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:
Para ver quantos chunks declaram o nome do erro, conte os arquivos que contêm uma declaração dele:
-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
vmpadrã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 arquivoPasse 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.Mude
identifierNamesGeneratorparahexadecimalNomes 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-obfuscatorou 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
randomIdentifiersPrefix- prefixo aleatório por build (recomendado)identifiersPrefix- string de prefixo explícitaidentifierNamesGenerator- formato dos nomes (mangled,hexadecimal, …)
