Cuando estoy cargando la versión minificada (a través de UglifyJS) de mi aplicación AngularJS, aparece el siguiente error en la consola:
Unknown provider: aProvider <- a
Ahora, me doy cuenta de que esto se debe a la alteración del nombre de las variables. La versión sin destrozar funciona bien. Sin embargo, yo no quiero hacer uso de renombrado de nombres variables, ya que reduce drásticamente el tamaño de nuestro archivo de salida JS.
Por esa razón, estamos usando ngmin en nuestro proceso de compilación, pero no parece resolver este problema, aunque nos sirvió bien en el pasado.
Entonces, para depurar este problema, habilité los mapas de origen en nuestra tarea uglify grunt. Se generan muy bien y Chrome hace cargar los mapas desde el servidor. Sin embargo, sigo recibiendo el mismo mensaje de error inútil, aunque tenía la impresión de que ahora debería ver el nombre original del proveedor.
¿Cómo consigo que Chrome use los mapas de origen para decirme qué proveedor es el problema aquí o, alternativamente, cómo puedo encontrar el proveedor de otra manera?
fuente
Respuestas:
Todavía me encantaría saber cómo pude haber encontrado el lugar en nuestro código fuente que causó este problema, pero desde entonces he podido encontrar el problema manualmente.
Había una función de controlador declarada en el ámbito global, en lugar de usar una
.controller()
llamada en el módulo de la aplicación.Entonces había algo como esto:
Esto funciona bien para AngularJS, pero para que funcione correctamente con la manipulación, tuve que cambiarlo a:
Después de más pruebas, encontré casos de más controladores que también causaron problemas. Así es como encontré la fuente de todos ellos manualmente :
En primer lugar, considero bastante importante habilitar el embellecimiento de salida en las opciones de uglify. Para nuestra dura tarea eso significaba:
Luego abrí el sitio web del proyecto en Chrome, con DevTools abierto. Lo que da como resultado que se registre un error como el siguiente:
El método en el seguimiento de llamadas que nos interesa es el que marqué con una flecha. Esto está
providerInjector
eninjector.js
. Querrá colocar un punto de interrupción donde arroje una excepción:Cuando vuelva a ejecutar la aplicación, se alcanzará el punto de interrupción y podrá saltar la pila de llamadas. Habrá una llamada desde
invoke
adentroinjector.js
, reconocible desde la cadena "Token de inyección incorrecto":El
locals
parámetro (alteradod
en mi código) da una idea bastante buena sobre qué objeto en su fuente es el problema:Un rápido
grep
vistazo a nuestra fuente encuentra muchas instancias demodalInstance
, pero a partir de ahí, fue fácil encontrar este lugar en la fuente:Que debe cambiarse a:
En caso de que la variable no contenga información útil, también puede saltar más en la pila y debe hacer una llamada a la
invoke
que debe tener sugerencias adicionales:Evita que esto vuelva a suceder
Ahora que, con suerte, ha encontrado el problema, creo que debería mencionar la mejor forma de evitar que esto vuelva a suceder en el futuro.
Obviamente, puede usar la anotación de matriz en línea en todas partes, o la
$inject
anotación de propiedad (según su preferencia) y simplemente tratar de no olvidarse de ella en el futuro. Si lo hace, asegúrese de habilitar el modo de inyección de dependencia estricta para detectar errores como este antes de tiempo.O puede dejar que ng-annotate se encargue de ello. Recomiendo encarecidamente hacerlo, ya que elimina una gran cantidad de posibles errores en esta área, como:
Mantener las anotaciones actualizadas es simplemente un dolor de cabeza y no debería tener que hacerlo si se puede hacer automáticamente. ng-annotate hace exactamente eso.
Debería integrarse muy bien en su proceso de compilación con grunt-ng-annotate y gulp-ng-annotate .
fuente
uglify({ output : { beautify : true }})
El artículo de Oliver Salzburg fue fantástico. Voto a favor.
Sugerencia para cualquiera que pueda tener este error. El mío simplemente fue causado por olvidar pasar una matriz para un controlador de directiva:
MALO
BUENO
fuente
/* @ngInject */
antes de la función. Parece hacer la parte de inyección complicada sin necesidad de escribir cada módulo incluido (estoy usando Yeoman)use ng-strict-di con ng-app
Si está utilizando angular 1.3 usted puede ahorrarse un mundo de dolor mediante el uso de ngStrictDi Directiva con ngApp:
Ahora, pre-minificación, cualquier cosa que no use anotaciones hará explotar tu consola y podrás ver el maldito nombre sin buscar entre los rastros de pila destrozados.
Según los documentos:
Una advertencia , sólo se detecta que no son anotaciones, no es que las anotaciones se han completado.
Sentido:
No captaré que ThingB no es parte de la anotación.
El crédito por este consejo es para la gente de ng-annotate , que se recomienda sobre el ahora obsoleto ngMin.
fuente
Para minimizar el angular, todo lo que necesita es cambiar su declaración al modo de declaración de "matriz", por ejemplo:
De:
A
¿Cómo declarar los servicios de fábrica?
fuente
Acabo de tener el mismo problema y lo resolví simplemente reemplazando ngmin (ahora en desuso) con ng-annotate para mi tarea de compilación grunt.
Parece que yeoman angular también se ha actualizado para usar ng-annotate a partir de este compromiso: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb
Sin embargo, si está utilizando una versión anterior de yeoman angular como yo, simplemente reemplace ng-min con ng-annotate en su package.json:
ejecutar
npm install
(luego opcionalmentenpm prune
) y seguir los cambios en la confirmación para editarGruntfile.js
.fuente
para saber cuál era el nombre de la variable original, puede cambiar cómo uglify manipula las variables:
y ahora el error es mucho más obvio
EDITAR
Tan obvio ahora ...
ahora cada variable está alterada a un valor único que también contiene el original ... simplemente abra el javascript minificado y busque "a_orig_ $ stateProvider_91212" o lo que sea ... lo verá en su contexto original ...
no podría ser más fácil ...
fuente
Además no olvide la
resolve
propiedad de la ruta. También debe definirse como la matriz:fuente
Con generador-gulp-angular:
Escriba / ** @ngInject * / antes de cada controlador, servicio, directiva.
fuente
Una solución rápida y sucia para esto si no necesita que Uglify mangle / acorte los nombres de sus variables es establecer mangle = false en su Gruntfile
fuente