hqjs / hq

Lightning fast, zero configuration, web application development server
https://hqjs.org
MIT License
126 stars 11 forks source link

Cannot read typeAnnotation of undefined. #21

Closed Tallyb closed 4 years ago

Tallyb commented 4 years ago

Error in @hqjs/babel-plugin-add-type-metadata on this line: https://github.com/hqjs/babel-plugin-add-type-metadata/blob/master/index.js#L11 Injectors may not have typeAnnotation, so it fails

hqjs commented 4 years ago

Are you using Angular? Can you please post a snippet with injector?

Tallyb commented 4 years ago
@Injectable()
export class CoreConfig implements ICoreConfig {
  private configConstants: any = {};

  constructor(@Inject(PLATFORM_ID) private platformId, @Inject(CORECONFIG_CONSTANTS) config, protected swUpdate: SwUpdate) {
    this.configConstants = config;
  }

It is not clear from the plugin documentation if it works on constructor parameters or on the class itself.

hqjs commented 4 years ago

Fixed in @hqjs/babel-plugin-add-type-metadata@0.0.4. Just reinstall @hqjs/hq to get latest version of plugins. I will release new hq version eventually with couple of other updates.

It works on constructor parameters, check the example for details.

Tallyb commented 4 years ago

Sadly, this only supports the unknown error. The problem is deeper, since then I get the following error

compiler.map:2387 Uncaught Error: Can't resolve all parameters for CoreConfig: (?, ?, [object Object]). at syntaxError (compiler.map:2387)

This is resulting from https://github.com/angular/angular/blob/d1ea1f4c7f3358b730b0d94e65b00bc28cae279c/packages/compiler/src/metadata_resolver.ts#L985

Trying to further think about the issue, doesn't Angular need to be compiled (not bundled, but compiled) in order to run in the browser. Especially with Angular 9/10 and Ivy? While searching on it, I have noticed this project in the Angular cli team: https://github.com/angular/angular-cli/tree/master/packages/ngtools/webpack. I wonder if that can be useful.

hqjs commented 4 years ago

It means it expects some type metadata for injection. Angular does not need to be compiled on the server, it can be interpreted on the client. I have working examples for Angular (tour of heroes work without any issues).

Do you have any open minimal project so I can debug it and fix? Will check latest angular with ToH (last tested it with version 8)

hqjs commented 4 years ago

Just tried it with https://github.com/ganatan/angular-example-starter and it works like a charm. I need an example to break it and find the solution.

Tallyb commented 4 years ago

In fact, the code above is using standard angular injectors and a custom one. This can probably be added to the repro of the TOH:

import { isPlatformServer } from '@angular/common';
import { Inject, Injectable, InjectionToken, PLATFORM_ID } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';

const CORECONFIG_CONSTANTS = new InjectionToken<any>('CoreConfigConstants');

@Injectable()
export class CoreConfig implements ICoreConfig {
  private configConstants: any = {};

  constructor(@Inject(PLATFORM_ID) private platformId, @Inject(CORECONFIG_CONSTANTS) config, protected swUpdate: SwUpdate) {
    this.configConstants = config;
  }
hqjs commented 4 years ago

How can we derive a type for platformId and config in this case? What your IDE says?

hqjs commented 4 years ago

I found this example on official documentation

constructor(@Inject(APP_CONFIG) config: AppConfig) {
  this.title = config.title;
}

But as you can see they still provide some typings.

Can you please assist with that issue. I'm not really sure what too look for. My guess is we should specify types for platformId and config or derive them somehow. I'm not an Angular developer, but would be happy to hack into it again, just need decent example and some guidance/documentation of how it supposed to work.

Tallyb commented 4 years ago

But the question is - should you assume that type information is always provided? Can this be bypassed when no type info is provided?

hqjs commented 4 years ago

Well, as you can see from the error Angular requires some type metadata to be passed. It is either derived from the code or some kind of any is used instead. If I have a working example - I would run it with hq, backtrack to the place where this information is passed (I know that there would be null for the missed types, but it would help to recognize the place) and then rerun it with angular compiler to see what is the difference (it is a bit tricky as angular compiler removes and transforms part of the code, but dependency injection part should remain).

hqjs commented 4 years ago

@Tallyb can you please help with the example?

Tallyb commented 4 years ago

Hi, You can see the error in this repo: https://github.com/Tallyb/hq-angular

Tallyb commented 4 years ago

@hqjs
hi, got a chance to look at it?

hqjs commented 4 years ago

Hey! Not yet. Have very busy time at work, sorry. Will try to check during the week.

hqjs commented 4 years ago

Ok. Since my vacation was ruined I finally found some time to debug an issue. @Tallyb thanks again for posting an example. After some investigation I found that providers metadata should consist of an object with provide property equal to a class, not a class itself. by changing it in debugging console I was able to run your example. Let me dive deeper to see how to turn meta into this object, seems like it should not be hard.

hqjs commented 4 years ago

I'm preparing a fix for @hqjs/babel-plugin-add-decorators-metadata.

hqjs commented 4 years ago

Before I push anything @Tallyb are you sure it is correct syntax for providers after Angular version 6? Shouldn't it be turned into

providers: [{
    provide: CoreConfig
}]
hqjs commented 4 years ago

Fixed in the plugin https://github.com/hqjs/babel-plugin-add-decorators-metadata. Just reinstall hq to get updated plugin version.