Quando estou carregando a versão reduzida (por meio de UglifyJS) do meu aplicativo AngularJS, recebo o seguinte erro no console:
Unknown provider: aProvider <- a
Agora, percebo que isso se deve à mutilação do nome da variável. A versão não fragmentada funciona muito bem. No entanto, eu não quero fazer uso de desconfiguração do nome variável, uma vez que reduz drasticamente o tamanho do nosso arquivo de saída JS.
Por esse motivo, estamos usando o ngmin em nosso processo de construção, mas ele não parece resolver esse problema, embora tenha nos servido bem no passado.
Portanto, para depurar esse problema, habilitei os mapas de origem em nossa tarefa uglify grunt. Eles são gerados apenas multa e Chrome faz transferir os mapas do servidor. Ainda assim, continuo recebendo a mesma mensagem de erro inútil, embora tenha a impressão de que agora deveria ver o nome original do provedor.
Como faço para que o Chrome use os mapas de origem para me dizer qual provedor é o problema aqui ou, alternativamente, como posso descobrir o provedor de outra maneira?
fonte
Respostas:
Ainda adoraria saber como poderia ter encontrado o local em nosso código-fonte que causou esse problema, mas desde então consegui encontrar o problema manualmente.
Havia uma função de controlador declarada no escopo global, em vez de usar uma
.controller()
chamada no módulo de aplicativo.Então, havia algo assim:
Isso funciona bem para o AngularJS, mas para que funcione bem com mutilação, eu tive que alterá-lo para:
Depois de mais testes, eu realmente encontrei instâncias de mais controladores que também causaram problemas. Foi assim que encontrei a fonte de todos eles manualmente :
Em primeiro lugar, considero bastante importante habilitar o embelezamento da saída nas opções do uglify. Para nossa tarefa árdua, isso significava:
Em seguida, abri o site do projeto no Chrome, com as DevTools abertas. O que resulta em um erro como o seguinte sendo registrado:
O método no rastreamento de chamada em que estamos interessados é aquele que marquei com uma seta. Isso está
providerInjector
dentroinjector.js
. Você vai querer colocar um ponto de interrupção onde ele lança uma exceção:Quando você executar novamente o aplicativo, o ponto de interrupção será atingido e você poderá saltar para cima na pilha de chamadas. Haverá uma chamada de
invoke
eminjector.js
, reconhecível na string "Token de injeção incorreto":O
locals
parâmetro (mutiladod
em meu código) dá uma boa ideia sobre qual objeto em sua fonte está o problema:Uma rápida olhada
grep
em nossa fonte encontra muitas instâncias demodalInstance
, mas, a partir daí, foi fácil encontrar este ponto na fonte:Que deve ser alterado para:
Caso a variável não contenha informações úteis, você também pode pular para cima na pilha e deve acertar uma chamada para a
invoke
qual deve ter dicas adicionais:Evite que isso aconteça novamente
Agora que espero que você tenha encontrado o problema, sinto que devo mencionar a melhor forma de evitar que isso aconteça novamente no futuro.
Obviamente, você poderia apenas usar a anotação de array embutido em qualquer lugar ou (dependendo de sua preferência)
$inject
anotação de propriedade e simplesmente tentar não se esquecer disso no futuro. Se você fizer isso, certifique-se de habilitar o modo de injeção de dependência estrita para detectar erros como este antecipadamente.Ou você pode deixar o ng-annotate cuidar disso. Eu recomendo fortemente fazer isso, pois remove muito potencial de erros nesta área, como:
Manter as anotações atualizadas é simplesmente um pé no saco e você não deveria ter que fazer isso se puder ser feito automaticamente. ng-annotate faz exatamente isso.
Ele deve se integrar perfeitamente ao seu processo de construção com grunt-ng-annotate e gulp-ng-annotate .
fonte
uglify({ output : { beautify : true }})
O artigo de Oliver Salzburg foi fantástico. Votado.
Dica para quem pode ter esse erro. O meu foi simplesmente causado por esquecer de passar uma matriz para um controlador de diretiva:
RUIM
BOA
fonte
/* @ngInject */
antes da função. Parece fazer a parte complicada da injeção sem precisar digitar cada módulo incluído (estou usando Yeoman)usar ng-strict-di com ng-app
Se você estiver usando o Angular 1.3, você pode evitar muitos danos usando a diretiva ngStrictDi com ngApp:
Agora - pré-minificação - qualquer coisa que não use anotações explodirá seu console e você poderá ver o maldito nome sem procurar por rastros de pilha mutilados.
De acordo com os documentos:
Uma ressalva , ele só detecta que não são anotações, não que as anotações estão completos.
Significado:
Não vai perceber que ThingB não faz parte da anotação.
O crédito por esta dica vai para o pessoal do ng-annotate , que é recomendado em vez do agora obsoleto ngMin.
fonte
Para minimizar o angular, tudo o que você precisa fazer é alterar sua declaração para o modo "declaração de array", por exemplo:
De:
Para
Como declarar serviços de fábrica?
fonte
Eu simplesmente tive o mesmo problema e resolvi-o simplesmente substituindo ngmin (agora obsoleto) por ng-annotate para minha tarefa de compilação grunt.
Parece que yeoman angular também foi atualizado para usar ng-annotate a partir deste commit: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb
No entanto, se você estiver usando uma versão mais antiga do yeoman angular como eu, apenas substitua ng-min por ng-annotate em seu package.json:
execute
npm install
(opcionalmentenpm prune
) e siga as mudanças no commit para editarGruntfile.js
.fonte
para saber qual era o nome da variável original, você pode alterar como o uglify altera as variáveis:
e agora o erro é muito mais óbvio
EDITAR
Tão óbvio agora ...
agora cada variável é mutilada para um valor único que também contém o original ... basta abrir o javascript minificado e pesquisar por "a_orig_ $ stateProvider_91212" ou qualquer outro ... você o verá em seu contexto original ...
não poderia ser mais fácil ...
fonte
Também não se esqueça da
resolve
propriedade da rota. Ele também deve ser definido como a matriz:fonte
Com gerador-gulp-angular:
Escreva / ** @ngInject * / antes de cada controlador, serviço, diretiva.
fonte
Uma solução rápida e suja para isso se você não precisar que o Uglify mangle / encurte seus nomes de variáveis é definir mangle = false em seu Gruntfile
fonte