Автоматическое упорядочение экспорта в index.ts приводит к сбою приложения

Каждый раз, когда я генерирую что-то в своей общей папке, файл index.ts перестраивается и экспорт помещается в алфавитном порядке. Кажется, это нарушает для меня зависимости. Изменение порядка вручную, чтобы зависимости экспортировались до того, как классы с зависимостями заставляют его работать снова.

Если 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;
    }
}

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

}

Это не работает:

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.

Это работает:

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

Из того, что я заметил, это не относится ко всем. Например, моя модель пользователя может быть экспортирована после службы auth, и она отлично работает.

Мне жаль, что мне не пришлось менять это вручную каждый раз. Доступно ли обходное решение? Могу ли я структурировать файлы по-другому?

Зависимости от 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"

Ответ 1

Это проблема с заказом экспорта в баррелях. Об этом сообщается в репозитории angular здесь: https://github.com/angular/angular/issues/9334

Существует три способа обхода:

Измените порядок экспорта в баррелях

Измените порядок, так что зависимости модулей указаны перед их иждивенцами.

В этом примере AuthGuard зависит от AuthService. AuthService - это зависимость AuthGuard. Поэтому экспортируйте AuthService перед AuthGuard.

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

Не используйте бочки вообще.

Это не рекомендуется, так как это означает, что требуется больше импорта.

В этом примере вы должны импортировать AuthService из своего файла, а не в бочку.

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

Используйте формат systemJS, а не commonJS

Измените параметры компилятора typescript для компиляции в формате SystemJS, а не в commonJS. Это делается путем изменения tsconfig.json compilerOptions.module от commonjs до system.

Обратите внимание, что при изменении этой конфигурации вам необходимо обновить свойства moduleId всех ваших декораторов компонентов от module.id до __moduleName и объявить их в typings.d.ts следующим образом:

declare var __moduleName: string;

Этот формат модуля не является значением по умолчанию в инструменте Angular -CLI (официальный инструмент построения, созданный командой angular) и поэтому не рекомендуется или поддерживается.


Примечание. Я лично не удовлетворен никакими обходными решениями.

Ответ 2

У меня была эта проблема, и это было вызвано циркулярной ссылкой. Объяснения: в "классе обслуживания поставщика" у меня была ссылка на страницу пользовательского интерфейса, на которой конструктор ссылался на эту же службу, вызывающую круговую ссылку...

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

Итак, что мне нужно было сделать, это удалить ссылку из службы и построить функцию, получающую обратный вызов. Не нужно ссылаться на страницу пользовательского интерфейса из службы, и ошибка исчезает.

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

В конструкторе класса app.component, который ссылается на службу, я просто устанавливаю ссылку на функцию обратного вызова, как показано ниже.

this.servicingClass.setCallBackSpy(this.myCallBackFunctionUsingUIPage);

Надеюсь, что поможет мой первый ответ:)

Ответ 3

Вы также можете получить эту ошибку в Angular2 вживую и предположить, что angular не хочет создавать экземпляр службы, которая уже была создана. Это может произойти, если вы "неверно" включите службу, например. ActivatedRoute из '@angular/router' в свойстве поставщиков декоратора класса @Component, несмотря на то, что он уже включил RouterModule в файл App.module, который так или иначе регистрирует всех поставщиков маршрутизаторов и директивы для приложения.