13 votes

L'ordre automatique des exportations dans index.ts fait planter l'application

Chaque fois que je génère quelque chose dans mon dossier partagé, le fichier index.ts est reconstruit et les exportations sont classées par ordre alphabétique. Cela semble casser les dépendances pour moi. En changeant l'ordre manuellement pour que les dépendances soient exportées avant les classes avec les dépendances, cela fonctionne à nouveau.

Si nous avons app/shared/auth.guard.ts :

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

import { AuthService, User } from './';

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private accountService: AuthService, private router: Router) { }

    canActivate(next: ActivatedRouteSnapshot): Observable<boolean> {
        let result = this.accountService.currentUser.first().map(user => user != null);

        let route: any[] = ['/login'];

        if (next.url.length) {
            route.push({ redirectUrl: next.url });
        }

        result.subscribe(isLoggedIn => {
            if (!isLoggedIn) {
                this.router.navigate(route);
            }
        });

        return result;
    }
}

et app/shared/account.service.ts :

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { User } from './';

const LOCAL_STORAGE_KEY = 'currentUser';

@Injectable()
export class AuthService {
  private currentUserSubject: BehaviorSubject<User>;

  constructor() {
    this.currentUserSubject = new BehaviorSubject<User>(this.getUserFromLocalStorage())
    this.currentUserSubject.subscribe(user => this.setUserToLocalStorage(user));
  }

  logIn(userName: string, password: string) : Observable<User> {
    this.currentUserSubject.next({
      id: userName,
      userName: userName,
      email: userName
    });

    return this.currentUser.first();
  }

  logOut() {
    this.currentUserSubject.next(null);
  }

  get currentUser(): Observable<User> {
    return this.currentUserSubject.asObservable();
  }

  private getUserFromLocalStorage(): User {
    let userString = localStorage.getItem(LOCAL_STORAGE_KEY);

    if (!userString) {
      return null;
    }

    return JSON.parse(userString);
  }

  private setUserToLocalStorage(user: User) {
    if (user) {
      localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(user));
    }
    else {
      localStorage.removeItem(LOCAL_STORAGE_KEY);
    }
  }

}

Ça ne marche pas :

export * from './auth.guard';
export * from './auth.service';

Unhandled Promise rejection: Error: Cannot resolve all parameters for 'AuthGuard'(undefined, Router). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'AuthGuard' is decorated with Injectable.

Ça marche :

export * from './auth.service';
export * from './auth.guard';

D'après ce que j'ai remarqué, cela ne s'applique pas à tous. Par exemple, mon modèle d'utilisateur peut être exporté après le service d'authentification et il fonctionne bien.

J'aimerais ne pas avoir à le modifier manuellement à chaque fois. Existe-t-il une solution de contournement ? Pourrais-je structurer les fichiers d'une manière différente ?

Dépendances de package.json :

"@angular/common": "^2.0.0-rc.2",
"@angular/compiler": "^2.0.0-rc.2",
"@angular/core": "^2.0.0-rc.2",
"@angular/forms": "^0.1.0",
"@angular/http": "^2.0.0-rc.2",
"@angular/platform-browser": "^2.0.0-rc.2",
"@angular/platform-browser-dynamic": "^2.0.0-rc.2",
"@angular/router": "^3.0.0-alpha.7",
"bootstrap": "^3.3.6",
"es6-shim": "0.35.1",
"moment": "^2.13.0",
"ng2-bootstrap": "^1.0.17",
"reflect-metadata": "0.1.3",
"rxjs": "5.0.0-beta.6",
"slideout": "^0.1.12",
"systemjs": "0.19.26",
"zone.js": "0.6.12"

DevDependencies :

"angular-cli": "1.0.0-beta.6"

32voto

Michael Points 631

C'est un problème avec la commande d'exportations en barils. Il a été signalé dans le dépôt angulaire ici : https://github.com/angular/angular/issues/9334

Il existe trois solutions de contournement :

Modifier l'ordre des exportations dans vos barils

Modifiez l'ordre pour que les dépendances des modules soient listées avant leurs dépendants.

Dans cet exemple, AuthGuard dépend de sur AuthService. AuthService est un dépendance d'AuthGuard. Par conséquent, exportez AuthService avant AuthGuard.

export * from './auth.service';
export * from './auth.guard';

N'utilisez pas du tout les barils.

Ce n'est pas recommandé car cela signifie que d'autres importations sont nécessaires.

Dans cet exemple, vous importeriez AuthService à partir de son fichier plutôt que d'un baril.

import { AuthService } from './auth.service';
import { User } from './';

Utiliser le format de module systemJS plutôt que commonJS

Modifier les options du compilateur typescript pour compiler au format SystemJS plutôt que commonJS. Pour ce faire, modifiez l'option de compilation de tsconfig.json compilerOptions.module de commonjs a system .

Notez que lorsque vous modifiez cette configuration, vous devez mettre à jour le fichier moduleId de tous vos décorateurs de composants à partir de module.id a __moduleName et le déclarer dans typings.d.ts comme suit :

declare var __moduleName: string;

Ce format de module n'est pas le format par défaut dans le Angular-CLI (outil de construction officiel créé par l'équipe Angular) et peut donc ne pas être recommandé ou pris en charge.


Remarque : je ne suis personnellement satisfait d'aucune de ces solutions de contournement.

2voto

Floydus Points 41

J'ai eu ce problème et cela a été causé par une référence circulaire. Explications : dans la 'classe de service du fournisseur', j'avais une référence à une page d'interface utilisateur dont le constructeur faisait référence à ce même service, ce qui causait la référence circulaire....

import { MyUIPage } from "../pages/example/myuipage";

Donc ce que j'ai dû faire, c'est supprimer la référence du service et construire une fonction recevant un callback. Plus besoin de référencer la page de l'interface utilisateur depuis le service et l'erreur disparaît.

public setCallBackSpy(callback)
{
   this.callBackSpy = callback;
}

Dans le constructeur de la classe app.component, celui qui fait référence au service, j'ai simplement défini le lien vers la fonction de rappel comme ci-dessous.

this.servicingClass.setCallBackSpy(this.myCallBackFunctionUsingUIPage);

J'espère que cela vous aidera, c'est ma toute première réponse :)

1voto

Kieran Ryan Points 509

Vous pouvez également obtenir cette erreur dans Angular2 live et suggère qu'angular ne veut pas instancier un service qui a déjà été instancié. Cela peut se produire si vous incluez "mal" le service, par exemple ActivatedRoute de '@angular/router' dans la propriété providers du décorateur de classe @Component, alors que vous avez déjà inclus le RouterModule dans le fichier App.module, qui enregistre de toute façon tous les fournisseurs et directives de routeur pour l'App.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X