schmod / babel-plugin-angularjs-annotate

Add Angular 1.x dependency injection annotations to ES6 code
http://schmod.github.io/babel-plugin-angularjs-annotate
MIT License
240 stars 29 forks source link

"Cannot set property '$inject' of undefined" with explicit es6 class annotation #22

Closed Kamilius closed 7 years ago

Kamilius commented 7 years ago

Hi I'm having a module which has following look:

export default class ExampleClass {
  constructor(customService) {
    'ngInject';

    this.customService = customService;
  }
}

ErrorType.serviceName = 'ERROR_TYPE';

For some reason, in generated code, ExampleClass.$inject = ['customService']; appears before ExampleClass function definition.

FjVillar commented 7 years ago

The code seems fine for me and I can't reproduce it. Is this all your code?

Kamilius commented 7 years ago

Missing description, this code is being processed with karma-webpack, while running UnitTests.

When building it directly with Webpack, it looks 100% legit and totally works even minified. But when it is processed through karma-webpack (with exact same config passed), $inject appears before method in generated code, but not after it, which causes an error.

FjVillar commented 7 years ago

Confirmed. I have already test some classes and with karma-webpack seems to not work properly. This is such a problem for us since we can't test our code using this plugin. @schmod can you enlight us on how to get a workaround or a fix for this?

schmod commented 7 years ago

Would one of you mind pasting a copy of the code generated by karma-webpack here?

joerideg commented 7 years ago

I have the same problem, however I think it might be related to babel-istanbul-plugin:

/* my source code */
class RootCtrl {
  constructor(TopicService) {
    'ngInject';

    this.TopicService = TopicService;
  }

  $onInit() {
    this.TopicService.initialize();
    this.topic = this.TopicService.topic;
  }
}

export default RootCtrl;

/* My normal webpack output when running webpack-dev server */
class RootCtrl {
  constructor(TopicService) {
    'ngInject';

    this.TopicService = TopicService;
  }

  $onInit() {
    this.TopicService.initialize(); this.topic = this.TopicService.topic;
  }
}
RootCtrl.$inject = ['TopicService'];

/* When using babel-angularjs-annotate plugin and babel-istanbul-plugin */
RootCtrl.$inject = ['TopicService'];
class RootCtrl {
  constructor(TopicService) {
    'ngInject';

    cov_129uwns0e2.f[0]++;
    cov_129uwns0e2.s[0]++;
    this.TopicService = TopicService;
  }

  $onInit() {
    cov_129uwns0e2.f[1]++;
    cov_129uwns0e2.s[1]++;

    this.TopicService.initialize();
    cov_129uwns0e2.s[2]++;
    this.topic = this.TopicService.topic;
  }
}

/* When using only babel-angularjs-annotate plugin and no babel-istanbul-plugin */
"use strict";
class RootCtrl {
  constructor(TopicService) {
    'ngInject';

    this.TopicService = TopicService;
  }

  $onInit() {
    this.TopicService.initialize();
    this.topic = this.TopicService.topic;
  }
}

RootCtrl.$inject = ['TopicService'];

If I add the part in my babelrc file for the istanbul plugin it fails, if I remove the part the tests pass, however I obviously have no coverage :(.

{
  "plugins": ["angularjs-annotate"],
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": [
          "last 1 Chrome versions",
          "last 1 Firefox versions",
          "last 1 Safari versions",
          "last 1 Edge versions"
        ]
      }
    }]
  ],
  "env": {
    "test": {
      "plugins": [
        ["istanbul", {
          "exclude": [
            "**/*.spec.js"
          ]
        }]
      ]
    }
  }
}

My error is not like the title of the issue its Uncaught ReferenceError: RootCtrl is not defined Since RootCtrl is obviously not defined before calling RootCtrl.$inject.

I hope this sheds some light on the issue?

joerideg commented 7 years ago

Actually I just realized I could NOT run angularjs-annotate on my test code, since its not minified. I can only run angularjs-annotate during a production build therefore solving my problem. Yay for me. I will leave my comment above though in case any one else realizes this same thing.

FjVillar commented 7 years ago

@joerideg Actually, It's not reccomended to use angularjs-annotate in dev build since, at least for me, the watch feature of webpack gets really slowed down. So I only use angularjs-annotate plugin in build config too. Now I can't really help with this, my solution was to migrate Karma to Jest but, I think that if you just run your karma jasmine unit tests before minifying the code It should be fine. @Kamilius here are some non-tested workarounds or solutions for you now:

  1. Make another Karma config sibling of your build Karma config which dont use webpack preprocesor to run your tests before minification.
  2. Migrate to Jest (Its really great, less config and really such a fast test running solution)
  3. Break your brain trying to fit a solution that prevents the preprocess minification of webpack before running your tests.

This still not tests if the angularjs-annotate injects actually work. But at least you can run your test suites within your CI.

schmod commented 7 years ago

I occasionally benchmark this plugin, and in my experience, I've found that it adds a negligible amount of overhead compared to what normally gets run via the AST parser or babel-preset-env. I do not recommend going out of your way to run your dev build and/or tests with a different configuration, and would encourage you to open an issue if this plugin is significantly degrading the performance of your builds.

In particular, I encourage you to run your tests against a build that resembles your production build as closely as possible.

schmod commented 7 years ago

The fix added in v0.8.2 appears to have fixed the original problem reported by @Kamilius.

Please re-open this issue if you're still having problems!