Lỗi rút gọn Angular.module


82

Có thời gian tuyệt vời nhất để cố gắng tìm ra lý do tại sao quá trình thu nhỏ không hoạt động.

Tôi đã đưa vào qua một đối tượng mảng mà các nhà cung cấp của tôi có chức năng trước khi có nhiều đề xuất trên web và vẫn "Nhà cung cấp không xác định: aProvider <- a"

Đều đặn:

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);
    }])

Thu nhỏ:

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);
    }])

Bất kỳ đề nghị sẽ có nghĩa vụ nhiều!


1
Bạn sử dụng gì để rút gọn mã của mình? uglifyJS? Ngoài ra, hãy xem tại: github.com/btford/ngmin ;)
AndreM96

Tôi đã sử dụng ngmin, tất cả những gì nó làm là sắp xếp mã ở một định dạng khoảng trắng khác. Tôi đã thử sử dụng express-uglify làm phần mềm trung gian nhưng nó không hoạt động nên tôi đã thử theo cách thủ công bằng công cụ uglify trực tuyến. Dù bằng cách nào thì mã này cũng giống nhau.
BPWDevelopment

Ngoài ra, không có thiếu ]? (trước khi đóng cửa ))
AndreM96

Có, tôi đã quên chúng trong đoạn trích cụ thể này. Nó không thay đổi thực tế "nhà cung cấp không xác định a" vẫn xảy ra :(
BPWDevelopment

2
Được rồi, bạn đã sử dụng công cụ thu nhỏ trực tuyến nào? Này hoạt động tốt với mã của bạn: marijnhaverbeke.nl/uglifyjs
AndreM96

Câu trả lời:


139

Tôi đã gặp sự cố này trước đây với plugin Grunt.js Uglify .

Một trong những lựa chọn là mangle

uglify: {
  options: {
    mangle: false
  },

Mà tôi tin rằng chạy các hàm regex trên "giống như chuỗi" và thu nhỏ chúng.

Ví dụ:

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

Sẽ trở thành:

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

Tắt nó đi --- tính năng này không hoạt động tốt với Angular.

Biên tập:

Nói chính xác hơn như @JoshDavidMiller giải thích:

Uglify manglechỉ mangles như các biến, đó là nguyên nhân thực sự gây ra vấn đề AngularJS. Đó là, vấn đề là ở tiêm chứ không phải định nghĩa.

function MyCtrl($scope, myService)sẽ bị xáo trộn function MyCtrl(a, b), nhưng định nghĩa dịch vụ bên trong một chuỗi không bao giờ được thay đổi.

  • Chạy ng-mintrước khi chạy uglifygiải quyết vấn đề này.

3
Anh ấy đã cập nhật mã của mình. Vấn đề của anh ấy không phải là "$ locationProvider" trở thành "b" hay bất cứ thứ gì tương tự. Nó chỉ không hoạt động. Tuy nhiên, +1 cho câu trả lời này :)
AndreM96

1
Cảm ơn đã tìm kiếm khó khăn để tìm tùy chọn đó.
reen

Tôi đã gặp phải điều này chính xác khi sử dụng angle bootstrap + yeoman. Sử dụng máy phát góc yeoman, nó đã tạo ra một bản distdựng có lỗi phụ thuộc được đề cập là "Nhà cung cấp không xác định". Cài đặt đã mangle: falsegiải quyết vấn đề. (lưu ý: vấn đề chỉ là một vấn đề trong gruntxây dựng distkhông phải là nhà phát triển thân thiện appxây dựng)
craigb

6
mangle: true thực sự mangle "như dây"? Tôi khá chắc rằng nó chỉ mangles như các biến , đó là nguyên nhân thực sự gây ra vấn đề AngularJS. Đó là, vấn đề là ở tiêm chứ không phải định nghĩa. function MyCtrl($scope, myService)sẽ bị xáo trộn function MyCtrl(a, b), nhưng định nghĩa dịch vụ bên trong một chuỗi không bao giờ được thay đổi. Chạy ng-mintrước khi chạy uglifygiải quyết vấn đề này, không?
Josh David Miller

1
ng-minhiện không được dùng nữa để ủng hộng-annotate
Atav32

51

Vấn đề

Từ AngularJS: The Bad Parts :

Angular có một bộ phun phụ thuộc tích hợp sẽ truyền các đối tượng thích hợp vào hàm của bạn dựa trên tên của các tham số của nó:

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

Tại đây, tên của các tham số $scope$windowsẽ được so khớp với danh sách các tên đã biết, và các đối tượng tương ứng sẽ được khởi tạo và chuyển đến hàm. Angular lấy tên tham số bằng cách gọi toString()hàm, sau đó phân tích cú pháp định nghĩa hàm.

Tất nhiên, vấn đề với điều này là nó ngừng hoạt động ngay khi bạn rút gọn mã của mình . Vì bạn quan tâm đến trải nghiệm người dùng, bạn sẽ giảm thiểu mã của mình, do đó việc sử dụng cơ chế DI này sẽ phá vỡ ứng dụng của bạn. Trên thực tế, một phương pháp phát triển phổ biến là sử dụng mã không hợp nhất trong quá trình phát triển để dễ gỡ lỗi và sau đó rút gọn mã khi chuyển sang sản xuất hoặc dàn dựng. Trong trường hợp đó, vấn đề này sẽ không tồn tại sau cái đầu xấu xí của nó cho đến khi bạn ở thời điểm mà nó đau đớn nhất.

(...)

Vì cơ chế tiêm phụ thuộc này không thực sự hoạt động trong trường hợp chung, Angular cũng cung cấp một cơ chế hoạt động. Để chắc chắn, nó cung cấp hai. Bạn có thể chuyển dọc theo một mảng như vậy:

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

Hoặc bạn có thể đặt thuộc $injecttính trên hàm tạo của mình:

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

Giải pháp

Bạn có thể sử dụng ng-annotateđể tự động thêm các chú thích cần thiết để thu nhỏ:

ng-annotatethêm và xóa chú thích chèn phụ thuộc AngularJS. Nó không xâm nhập nên mã nguồn của bạn vẫn hoàn toàn giống nhau. Không có bình luận bị mất hoặc dòng di chuyển.

ng-annotatenhanh hơn và ổn định hơn ngmin(hiện không được dùng nữa) và nó có các plugin cho nhiều công cụ:


Bắt đầu từ AngularJS 1.3, cũng có một tham số mới ngAppđược gọi là ngStrictDi:

nếu thuộc tính này xuất hiện trên phần tử ứng dụng, bộ phun sẽ được tạo ở chế độ "nghiêm ngặt". Điều này có nghĩa là ứng dụng sẽ không gọi được các hàm không sử dụng chú thích hàm rõ ràng (và do đó không phù hợp để rút gọn), như được mô tả trong hướng dẫn Dependency Injection và thông tin gỡ lỗi hữu ích sẽ hỗ trợ tìm ra gốc rễ của những lỗi này.


1
+1 Chỉ cần chuyển sang grunt-ng-annotate đã khắc phục được sự cố này và ngmin hiện không được dùng nữa nên đó là một lý do khác để chuyển.
Pier-Luc Gendreau

đó là bản sửa lỗi tôi đã tìm kiếm nhiều ngày!
jack.the.ripper

Tôi đang đối mặt với vấn đề tương tự khi xây dựng một mã được rút gọn với Browserify, angle và gulp-minify. Tôi đã gỡ bỏ gulp minify và thay thế bằng gulp-ng-annotate, mã vẫn được minify nhưng vẫn không hoạt động.
Dimitri Kopriwa

@BigDong nếu bạn đang sử dụng Browserify, cách tốt nhất có lẽ là bật ngStrictDi(một cái gì đó giống như <div ng-app="myApp" ng-strict-di />) và sử dụng gulp-ng-annotatengay cả trong môi trường phát triển của bạn để bạn dễ dàng theo dõi các lỗi thu nhỏ này.
Paolo Moretti

@PaoloMoretti Tôi đã thử với ngStrictDi và gulp-ng-annotate, Browserify có thể đóng gói nhưng mã không được rút gọn, nó có phải là công việc ng-annotate không?
Dimitri Kopriwa

22

Tôi gặp lỗi tương tự. Tuy nhiên, đối với tôi, vấn đề là khai báo bộ điều khiển của chỉ thị. Bạn nên làm điều này thay thế.

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
Xin cảm ơn @angelokh! Tôi đã gặp chính xác vấn đề này. Tôi đã sử dụng controller: function ($scope) {}ký hiệu.
jbasko

2
Đây giống như giải pháp cho vấn đề thực tế hơn là được mangle: falseđề xuất trong các câu trả lời khác, bởi vì chúng tôi vẫn muốn có thể đặt tên.
jbasko

9

Tôi đã gặp sự cố tương tự khi sử dụng grunt, ngmin và uglify.

Tôi đã chạy quy trình theo thứ tự sau: concat, ngmin, uglify

Tôi tiếp tục nhận được lỗi $ injectionor từ angle cho đến khi tôi thêm vào mangle tùy chọn uglify: false - sau đó mọi thứ đã được khắc phục.

Tôi cũng đã cố gắng thêm các ngoại lệ cho uglify như thế này:

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

Nhưng không có kết quả...

Đây là gruntFile.js của tôi để làm rõ thêm:

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']);

}


AH XIN CHÂN THÀNH CẢM ƠN! điều đó đã giúp tôi tiết kiệm rất nhiều thời gian.
mylescc

5

AndrewM96 gợi ý ng-minlà đúng.

Căn chỉnh và khoảng trắng quan trọng đối với Uglify cũng như Angular.


10
ng-min dường như chỉ xử lý các tệp góc để chúng thân thiện với uglify. Trong quá trình xây dựng của chúng tôi, chúng tôi sử dụng cả hai ( ng-mintrước đây uglify) và vẫn gặp sự cố với js chưa được xác minh.
craigb

4
Tại sao điều này được đánh dấu là câu trả lời? (Ngoài ra, AndrewM96 nên là AndreM96)
Jay

mặc dù trong tài liệu, ng-min có vẻ hứa hẹn rằng nó không giải quyết được vấn đề
special0ne 23/02

@craigb đang gặp vấn đề tương tự. Có lẽ đó là sự kết hợp của nhiều thứ. Tôi cũng sử dụng RequestJS. Về cơ bản, tôi làm tất cả những thứ mà ng-min phải làm và vẫn chạy ng-min, hơn là chạy yêu cầu xây dựng và hơn là chạy uglify với mangle true. Quá trình này dường như hoạt động hầu hết các lần.
Escapecat

3

Tôi đã có một vấn đề tương tự. Và giải quyết nó theo cách sau. Chúng ta cần chạy một mô-đun Gulp có tên là gulp-ng-annotate trước khi chạy uglify. Vì vậy, chúng tôi cài đặt mô-đun đó

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

Sau đó, thực hiện yêu cầu trong Gulpfile.js

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

Và trong nhiệm vụ usemin của bạn, hãy làm điều gì đó như thế này

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

Điều đó đã giải quyết nó cho tôi.

[EDIT: Đã sửa lỗi chính tả]


gulp-MG-annotate phải là gulp-NG-annotate?
hally9k

Vâng, xin lỗi vì sai lầm. Nơi mg-annotateluôn luôn đọcng-annotate
Paulo Borralho Martins


2

Điều này rất khó gỡ lỗi vì rất nhiều dịch vụ được đặt tên giống nhau (chủ yếu là e hoặc a). Điều này sẽ không giải quyết được lỗi, nhưng sẽ cung cấp cho bạn tên của dịch vụ chưa được giải quyết cho phép bạn theo dõi, trong đầu ra chưa được xác minh, vị trí trong mã và cuối cùng cho phép bạn giải quyết vấn đề:

Đi vào lib/scope.jsUglify2 ( node_modules/grunt-contrib-uglify/node_modules/uglify-js/lib/scope.js) và thay thế dòng

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

với

this.mangled_name = this.name + "__debugging_" + counter++
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.