Angular.moduleの縮小バグ


82

最小化が機能していない理由を理解しようと最悪の時間を過ごしています。

Web全体の多数の提案に従って、関数の前に配列オブジェクトを介してプロバイダーを挿入しましたが、それでも「不明なプロバイダー:aProvider <-a」

レギュラー:

var app = angular.module('bpwApp', ['ui.bootstrap', 'ui', 'myTabs'])
    .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
    $routeProvider.
        when('/', {templateUrl: 'partials/home.jade', controller: HomeCtrl});

    $locationProvider.html5Mode(true);
    }])

縮小:

var app = angular.module('bpwApp', ['ui.bootstrap', 'ui', 'myTabs'])
    .config(['$routeProvider', '$locationProvider', function(a, b){
    a.
        when('/', {templateUrl: 'partials/home.jade', controller: HomeCtrl});

    b.html5Mode(true);
    }])

どんな提案も大いに義務づけられるでしょう!


1
コードを縮小するために何を使用しますか?uglifyJS?また、チェックアウトしてください:github.com/btford/ngmin ;)
AndreM96 2013年

私はngminを使用しましたが、コードを別の空白形式で並べるだけでした。Express-uglifyをミドルウェアとして使用しようとしましたが、機能しなかったため、オンラインuglifierを手動で使用してみました。いずれにせよ、コードは同じ結果になりました。
BPWDevelopment 2013年

また、足りないものはありませ]んか?(閉会前)
AndreM96 2013年

ありました、私はこの特定のスニペットでそれらを忘れました。「不明なプロバイダーa」がまだ発生しているという事実は変わりません:(
BPWDevelopment 2013年

2
さて、あなたはどのオンラインミニファイアを使用しましたか?これはあなたのコードでうまく機能します:marijnhaverbeke.nl/uglifyjs
AndreM96

回答:


139

以前、Grunt.jsUglifyプラグインでこの問題に遭遇しました

オプションの1つはマングルです

uglify: {
  options: {
    mangle: false
  },

これは、「文字列のように」正規表現関数を実行し、それらを最小化すると私は信じています。

例えば:

angular.module("imgur", ["imgur.global","imgur.album"]);

になります:

angular.module("a", ["a.global","a.album"]);

無効にする---この機能はAngularではうまく機能しません。

編集:

@JoshDavidMillerが説明するように、より正確に言うと:

Uglify mangle変数のようなのみをUglifyします。これが、実際にAngularJSの問題を引き起こします。つまり、問題は注入にあり、定義にはありません。

function MyCtrl($scope, myService)にマングルされfunction MyCtrl(a, b)ますが、文字列内のサービス定義が変更されることはありません。

  • 実行するng-min前に実行uglifyすると、この問題が解決します。

3
彼は自分のコードを更新しました。彼の問題は、「$ locationProvider」が「b」などになることではありませんでした。それはうまくいきませんでした。ただし、この回答の+1 :)
AndreM96 2013年

1
おかげでそのオプションを見つけるのは大変でした。
reen 2013年

Angular Bootstrap + yeomanを使用しているときに、これとまったく同じことが発生しました。ヨーマン角度ジェネレーターを使用しdistて、前述の依存関係エラー「不明なプロバイダー」を持つビルドを生成しました。設定でmangle: false問題は解決しました。(注:この問題は、唯一の問題だったgrunt建てdist開発者フレンドリーではないappビルド)
craigb

6
mangle: true 本当に「文字列のように」マングル?AngularJSの問題を実際に引き起こしているのは、変数のようにマングルしているだけだと確信しています。つまり、問題は注入にあり、定義にはありません。function MyCtrl($scope, myService)にマングルされfunction MyCtrl(a, b)ますが、文字列内のサービス定義が変更されることはありません。実行するng-min前に実行uglifyすると、この問題は解決しますね。
Josh David Miller

1
ng-min現在、非推奨になっていますng-annotate
Atav32 2014年

51

問題

AngularJSから:悪い部分

Angularには、パラメーターの名前に基づいて適切なオブジェクトを関数に渡す依存性注入が組み込まれています。

function MyController($scope, $window) {
    // ...
}

ここでは、パラメータの名前$scopeとは$window知られている名前のリストと照合され、対応するオブジェクトをインスタンス化し、関数に渡されます。Angularはを呼び出すことでパラメータ名を取得しますtoString()関数をてから関数定義を解析で。

もちろん、これに伴う問題は、コードを縮小した瞬間に機能しなくなることです。。ユーザーエクスペリエンスを重視するため、コードを縮小することになります。したがって、このDIメカニズムを使用すると、アプリが破損します。実際、一般的な開発方法論は、デバッグを容易にするために開発で縮小されていないコードを使用し、本番環境またはステージングにプッシュするときにコードを縮小することです。その場合、この問題は、最も痛いところに到達するまで、醜い頭を抱えることはありません。

(...)

この依存性注入メカニズムは一般的なケースでは実際には機能しないため、Angularは機能するメカニズムも提供します。確かに、それは2つを提供します。次のように配列を渡すことができます。

module.controller('MyController', ['$scope', '$window', MyController]);

または$inject、コンストラクターでプロパティを設定できます。

MyController.$inject = ['$scope', '$window'];

解決

ng-annotate縮小に必要な注釈の自動追加に使用できます。

ng-annotateAngularJSの依存性注入アノテーションを追加および削除します。邪魔にならないので、ソースコードはそれ以外はまったく同じです。コメントの紛失や行の移動はありません。

ng-annotatengmin(現在は非推奨)よりも高速で安定しており、多くのツール用のプラグインがあります。


AngularJS 1.3から開始すると、新しいparamがでもありますngApp呼ばれますngStrictDi

この属性がapp要素に存在する場合、インジェクターは「strict-di」モードで作成されます。これは、依存性注入ガイドで説明されているように、アプリケーションが明示的な関数アノテーションを使用しない(したがって縮小に適さない)関数の呼び出しに失敗することを意味し、有用なデバッグ情報はこれらのバグの根本を追跡するのに役立ちます。


1
+1 grunt-ng-annotateに切り替えるだけでこの問題が修正され、ngminは非推奨になりました。これが、切り替えるもう1つの理由です。
Pier-Luc Gendreau 2014

それは私が何日も探していた修正でした!
jack.the.ripper 2014

私は、browserify、angular、gulp-minifyを使用して縮小化されたコードを構築するのと同じ問題に直面しています。gulp minifyを削除し、gulp-ng-annotateに置き換えました。コードはまだ縮小されていますが、機能しません。
Dimitri Kopriwa 2015年

@BigDongを使用している場合、browserifyを使用するのが最善の方法は、おそらくngStrictDi(のような<div ng-app="myApp" ng-strict-di />)を有効にgulp-ng-annotateして、開発環境でも使用することです。これにより、これらの縮小バグを簡単に追跡できます。
パオロモレッティ2015年

@PaoloMoretti ngStrictDiとgulp-ng-annotateを試してみましたが、browserifyはバンドルできますが、コードは縮小されていません。ng-annotateジョブであるはずではありませんか?
Dimitri Kopriwa 2015年

22

同じエラーが発生しました。しかし、私にとっては、問題はディレクティブのコントローラー宣言です。代わりにこれを行う必要があります。

myModule.directive('directiveName', function factory(injectables) {
    var directiveDefinitionObject = {
      templateUrl: 'directive.html',
      replace: false,
      restrict: 'A',
      controller: ["$scope", "$element", "$attrs", "$transclude", "otherInjectables",
        function($scope, $element, $attrs, $transclude, otherInjectables) { ... }]
    };
    return directiveDefinitionObject;
  });

https://github.com/angular/angular.js/pull/3125


1
ありがとう@angelokh!私はまさにこの問題を抱えていました。私はcontroller: function ($scope) {}表記法を使用していました。
jbasko 2014

2
これはmangle: false、他の応答で提案されているよりも実際の問題の解決策に似ています。これは、名前をマングルできるようにしたいためです。
jbasko 2014

9

grunt、ngmin、uglifyを使用して同様の問題が発生しました。

プロセスを次の順序で実行しました:concat、ngmin、uglify

uglifyオプションのマングルを追加するまで、角度から$ injectorエラーを取得し続けていました:false-その後、すべてが修正されました。

私はまた、次のように醜くするために例外を追加しようとしました:

 options: {
  mangle: {
     except: ['jQuery', 'angular']
  }
}

しかし、役に立たない...

さらに明確にするために、これが私のgruntFile.jsです。

module.exports = function(grunt) {
'use strict';
// Configuration goes here
grunt.initConfig({
    pkg: require('./package.json'),

    watch: {
        files: ['scripts/**/*.js', 'test/**/*spec.js', 'GruntFile.js'],
        tasks: ['test', 'ngmin']
    },

    jasmine : {
        // Your project's source files
        src : ['bower_components/angular/angular.js', 'bower_components/angular-mocks/angular-mocks.js', 'scripts/app.js', 'scripts/**/*.js' ],
        // Your Jasmine spec files

        options : {
            specs : 'test/**/*spec.js',
            helpers: 'test/lib/*.js'
        }
    },

    concat: {
      dist : {
          src: ['scripts/app.js', 'scripts/**/*.js'],
          dest: 'production/js/concat.js'
      }
    },

    ngmin: {
        angular: {
            src : ['production/js/concat.js'],
            dest : 'production/js/ngmin.js'
        }

    },

    uglify : {
        options: {
            report: 'min',
            mangle: false
        },
        my_target : {
            files : {
                'production/app/app.min.js' : ['production/js/ngmin.js']
            }
        }
    },

  docular : {
      groups: [],
      showDocularDocs: false,
      showAngularDocs: false
  }

});

// Load plugins here
grunt.loadNpmTasks('grunt-ngmin');
grunt.loadNpmTasks('grunt-docular');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-connect');

// Define your tasks here
grunt.registerTask('test', ['jasmine']);
grunt.registerTask('build', ['concat', 'ngmin', 'uglify']);
grunt.registerTask('default', ['test', 'build', 'watch']);

};


ああ、ありがとう!それは私に多くの時間を節約しました。
mylescc 2014年

5

AndrewM96の提案ng-minは正しいです。

配置と空白は、AngularだけでなくUglifyにとっても重要です。


10
ng-minは、Angularファイルを処理するだけのように見えるので、それらはに使いやすいuglifyです。ビルドプロセスでは、両方を使用しますが(ng-min以前uglify)、まだ醜いjsに問題がありました。
craigb 2013年

4
なぜこれが答えとしてマークされているのですか?(また、AndrewM96はAndreM96である必要があります)
Jay

ドキュメントで問題を解決しないことを約束した音分のngのけれども
special0ne

@craigbも同じ問題を抱えています。多分それは物事の組み合わせです。私もRequireJSを使用しています。私は基本的に、ng-minが自分で実行する必要のあるすべての機能変更を実行し、それでもng-minを実行します。実行するには、buildが必要であり、uglifyをmangletrueで実行します。このプロセスはほとんどの場合うまくいくようです。
エスケープキャット2014

3

私も同様の問題を抱えていました。そしてそれを次のように解決しました。uglifyを実行する前に、gulp-ng-annotateというGulpモジュールを実行する必要があります。そのモジュールをインストールします

npm install gulp-ng-annotate --save-dev

次に、Gulpfile.jsでrequireを実行します

ngannotate = require(‘gulp-ng-annotate’)

そしてあなたのuseminタスクでこのようなことをしてください

js: [ngannotate(), uglify(),rev()] 

それは私にとってそれを解決しました。

[編集:タイプミスを修正]


gulp-MG-annotateはgulp-NG-annotateである必要がありますか?
hally9k 2016

はい、間違いでごめんなさい。読み取りmg-annotateが常に行われる場所ng-annotate
Paulo Borralho Martins 2016


2

多くのサービスに同じ名前が付けられているため(ほとんどの場合eまたはa)、これをデバッグするのは非常に困難です。これはエラーを解決しませんが、未解決のサービスの名前を提供しますこれにより、醜い出力でコード内の場所を追跡し、最終的に問題を解決できます。

lib/scope.jsUglify2(node_modules/grunt-contrib-uglify/node_modules/uglify-js/lib/scope.js)に移動し、行を置き換えます

this.mangled_name = this.scope.next_mangled(options);

this.mangled_name = this.name + "__debugging_" + counter++
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.