AOT Не удается разрешить все параметры для []

Прежде всего, я должен сказать, что мое приложение отлично работает при «использовании» JIT. Я даже могу объединить в prod (без AOT, просто JIT), и он отлично работает.

Но когда я пытаюсь скомпилировать его (AOT) с помощью ngc, я получаю сообщение об ошибке:

Can't resolve all parameters for MyComponentView in /path/my-component/my-component.view.ts:
([object Object], [object Object], [object Object], [object Object], ?)

Это конструктор MyComponent:

constructor( headerService:HeaderService, sidebarService:SidebarService, @Inject( AuthService.Token ) authService:AuthService.Class, router:Router, carbon:Carbon ) {
    …
    this.carbon = carbon;
    …
}

Последняя зависимость (Carbon) предоставляется в AppModule следующим образом:

@NgModule( {
    imports: [
        …
    ],
    declarations: [
        …
    ],
    providers: [
        …
        CARBON_PROVIDERS,   //<---- HERE IS BEING PROVIDED
        CARBON_SERVICES_PROVIDERS,
        …
    ],
    bootstrap: [ AppComponent ],
} )
export class AppModule { }

CARBON_PROVIDERS импортируются с помощью проекта angular2-carbonldp, который экспортирует их следующим образом:

export const CARBON_PROVIDERS:any[] = [
{
        provide: Carbon,
        useFactory(): Context {
            return carbon;
        },
    },
    {
        provide: ContextToken,
        useFactory(): Context {
            return activeContextFn();
        },
    },
    {
        provide: App.Context,
        useFactory(): App.Context {
            if( ! activeContextFn.isAppContext() ) throw new Errors.IllegalStateError( "The activeContext is not an App Context" );
            return <any>activeContextFn();
        },
    },
];

Но у меня такая же ошибка, и я не понимаю, ПОЧЕМУ! Ребята, вы случайно не знаете, почему это так работает?


person Alvaro Contreras    schedule 07.03.2017    source источник
comment
почему в `useFactory()` есть круглые скобки?   -  person pixelbits    schedule 07.03.2017
comment
Это просто использование краткой нотации литерального метода объекта, которая действительна, хотя я бы сказал, что здесь ее не следует отдавать предпочтение. Но это не причина ошибки.   -  person Aluan Haddad    schedule 07.03.2017
comment
@pixelbits Да, из-за этого. [Проверьте это][github.com/angular/angular/issues/13614] так что вы можете видеть, как это можно использовать. Но что касается отсутствующего провайдера... есть идеи, почему это работает JIT, но не AOT?   -  person Alvaro Contreras    schedule 07.03.2017


Ответы (2)


Потому что компилятор AOT поддерживает только небольшое подмножество JavaScript. Этот факт плохо задокументирован, если вообще задокументирован, и не получил широкой огласки.

Он не может анализировать многие выражения JavaScript внутри декораторов фреймворка Angular 2. Сюда входят вызовы функций, они неправомерны.

Следующий код вызывает сбой

useFactory(): Context {
  return activeContextFn();
}

Причина этого в том, что декораторы angular2 в AOT вообще не являются декораторами.

Компилятор Angular 2 AOT поддерживает список известных декораторов, которые он не сохраняет во время выполнения, вместо этого рассматривая их как не более чем аннотации*. Это означает, что они могут содержать только константные выражения, ссылки на экспортированные имена, несколько форм синтаксиса литерала массива и синтаксиса литерала объекта, состоящего из константных выражений, и немного больше.

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

Это другой язык с другой семантикой, а не просто подмножество, потому что выполняемое им преобразование декоратора нарушает спецификацию этой функции в ECMAScript. Typescript не добавляет и не изменяет какое-либо поведение ECMAScript во время выполнения.

*Для справки, термин аннотация используется здесь, поскольку он относится к ныне мертвому языку @Script. Это язык, который команда Angular изобрела для написания своего фреймворка и начала интенсивно использовать через специальный транспилятор, прежде чем они перешли на TypeScript.

В этом конкретном случае я думаю, вам нужно переписать фабрику следующим образом:

useFactory: contextFactory

....

export function contextFactory() {
    return activeContextFn();
}

Это может быть не все, что вам нужно сделать, и язык, несомненно, со временем изменится. Планируется поддержка IDE.

Вот довольно полезная «песочница» https://github.com/rangle/angular-2-aot-sandbox

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

person Aluan Haddad    schedule 07.03.2017
comment
Мне ОЧЕНЬ понравилось ваше объяснение того, почему аннотации бесполезны с кодом внутри них. Это помогло мне понять необходимость экспортировать функции и использовать их вне аннотации при компиляции AOT. Имея это в виду, я начал экспортировать функции следующим образом: ` export function aotCarbonFactory():Context { return carbon; } export const CARBON_PROVIDERS:any[] = [{provide: Carbon, useFactory: aotCarbonFactory, } ]` Но результат все тот же. Вы знаете, почему? - person Alvaro Contreras; 07.03.2017
comment
Я считаю, что carbon нужно экспортировать, но я не уверен. - person Aluan Haddad; 07.03.2017
comment
Я добавил ссылку на неофициальную песочницу AOT в ответ. Вы можете найти это полезным, но прочитайте предостережения. - person Aluan Haddad; 07.03.2017
comment
Спасибо за проект песочницы, посмотрю на это! У меня есть последний вопрос... Считаете ли вы, что библиотека Carbon также должна быть совместима с AOT? Я имею в виду, должна ли библиотека также предоставлять файлы metdata.json? (Реализовать АОТ) - person Alvaro Contreras; 07.03.2017
comment
Если он использует Angular 2, то да, требование AOT на 100% транзитивно. - person Aluan Haddad; 07.03.2017
comment
Проект Carbon [github.com/CarbonLDP/carbonldp-js-sdk] не вообще не использовать Angular. Это просто библиотека, не имеющая ничего общего с Angular. Из-за этого ему не нужно экспортировать/предоставлять файлы .metadata.json, верно? Я имею в виду, его можно использовать как есть, верно? - person Alvaro Contreras; 07.03.2017
comment
Ссылка 404. Как вы ее импортируете? - person Aluan Haddad; 07.03.2017
comment
Вот ссылка: github.com/CarbonLDP/carbonldp-js-sdk Я тоже импортирую вот так: import Carbon from "carbonldp/Carbon"; - person Alvaro Contreras; 07.03.2017
comment
Да, зависимости, отличные от Angular2, не могут и не предоставляют метаданные AOT. Ваш импорт правильный (кстати, приятно видеть пакет с фактическим экспортом по умолчанию). Я не уверен, почему это не работает, но попробуйте заменить его на return null и посмотрите, сработает ли это. - person Aluan Haddad; 08.03.2017

Для всех, кто ищет этот конкретный текст ошибки:

Я столкнулся с этой ошибкой при создании родительского проекта angular с включенным AOT, в котором был проект дочерней библиотеки angular, который я упаковал с помощью ng-packagr, в котором использовались бочки внутри. Мне удалось решить проблему, изменив все ссылки на бочки в проекте библиотеки на явные ссылки.

До

import { MyService } from './featureFolder';

После

import { MyService } from './featureFolder/my.service';

Ссылка на проблему. Команда разработчиков утверждает, что это было исправлено, но похоже, что в той или иной форме она вернулась в Angular 8. https://github.com/angular/angular/issues/23713

person DJKeeg    schedule 14.11.2019