В чем разница между Angular AOT и JIT-компилятором

Я погружаюсь в угловой 4, и я пытаюсь понять сборник. Я читал, что AOT и JIT компилируют TypeScript в JavaScript, будь то на стороне сервера или на стороне клиента. Если я собираю его, когда собираю его с помощью Webpack, хрюкаю и внедряю этот минимизированный javascript, как AOT и JIT вообще попадают в картину?

3 ответа

Решение

Я читал, что AOT и JIT компилируют TypeScript в JavaScript, будь то на стороне сервера или на стороне клиента.

Нет, это не то, что делают компиляторы AOT и JIT. TypeScript транслируется в JavaScript с помощью компилятора машинописи.

Угловой компилятор

Есть два компилятора, которые выполняют тяжелую работу по компиляции и генерации кода:

Компилятор представлений компилирует шаблоны компонентов и генерирует фабрики представлений. Он анализирует выражения и элементы html внутри шаблона и проходит через многие стандартные фазы компилятора:

parse-tree (lexer) -> abstract-syntax-tree (parser) -> intermediate-code-tree -> output

Компилятор провайдера компилирует провайдеры модулей и генерирует фабрики модулей.

JIT против AOT

Эти два компилятора используются как в JIT, так и в AOT-компиляции. Компиляции JIT и AOT отличаются тем, как они получают метаданные, связанные с компонентом или модулем:

// the view compiler needs this data

@Component({
   providers: ...
   template: ...
})

// the provider compiler needs this data

@NgModule({
   providers: ...
});

JIT-компилятор использует среду выполнения для получения данных. Функции декоратора @Component а также @NgModule выполняются, и они прикрепляют метаданные к классу компонента или модуля, который впоследствии читается компиляторами Angular с использованием отражательного capabiliteis (библиотека Reflect).

Компилятор AOT использует статический анализ кода, предоставляемый компилятором машинописи, для извлечения метаданных и не полагается на оценку кода. Следовательно, он немного ограничен по сравнению с JIT-компилятором, поскольку он не может вычислять неявный код - например, он требует экспорта функции:

// this module scoped function

function declarations() {
  return [
    SomeComponent
  ]
}

// should be exported

export function declarations() {
  return [
    SomeComponent
  ];
}
@NgModule({
  declarations: declarations(),
})
export class SomeModule {}

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

Если я собираю его, когда собираю его с помощью Webpack, хрюкаю и внедряю этот минимизированный javascript, как AOT и JIT вообще попадают в картину?

Angular предоставляет плагин webpack, который выполняет перенос из машинописного текста во время сборки. Этот плагин также может AOT компилировать ваш проект, чтобы вы не включали JIT-компилятор в комплект и не выполняли компиляцию на клиенте.

Прежде всего, angular отходит от компиляции JIT. Я надеюсь, что мы увидим это в angular@5.x.x

Угловой компилятор принимает все метаданные, которые вы пишете, используя декораторы, такие как

@Component({
  selector: 'my-app',
  template: '<h1>Hello</h1>'m
  styles: [ ':host { display: block }' ]
})

constructor(
  @Host() @Optional() private parent: Parent,
  @Attribute('name') name: string) {} 

@ViewChild('ref') ref;

@ContentChildren(MyDir) children: QueryList<MyDir>;  

@HostBinding('title') title;

@HostListener('click') onClick() { ... }

// and so on

и анализирует это. Затем он берет шаблон и таблицы стилей и анализирует его. Компилятор проходит через много шагов, которые я не буду здесь описывать. Вы можете взглянуть на следующую страницу, которая описывает процесс компиляции. От Тобиаса Босха также много разговоров. Наконец, компилятор создает ngfactories для создания экземпляра нашего приложения.

Я думаю, что основные различия между AOT в JIT

  • когда и где выполняется угловая компиляция
  • как компилятор собирает метаданные
  • какой формат ngfactory этот компилятор производит

JIT-компилятор

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

Он собирает метаданные с помощью API ReflectionCapabilities из @angular/core пакет. У нас есть следующие опции для работы с метаданными в режиме JIT:

1) прямой API

например, мы можем объявить наш компонент как

export class AppComponent {
  static annotations = [
    new Component({
      selector: 'my-app',
      templateUrl: `./app.component.html`,
      styles: [ ':host { display: block }' ]
    })
  ];

  test: string;

  static propMetadata = {
      test: [new HostBinding('title')]
  };


  ngOnInit() {
    this.test = 'Some title'
  }
}

Подобный код мы можем написать в ES5. JIT-компилятор прочтет annotations а также propMetadata статические свойства Компилятор AOT не будет работать с ним.

2) Цикл API

export class AppComponent {
  static decorators = [{
      type: Component,
      args: [{
        selector: 'my-app',
        templateUrl: `./app.component.html`,
        styles: [ ':host { display: block }' ]
      },]
  }];

  test: string;

  static propDecorators = {
    'test': [{ type: HostBinding, args: ['title'] }]
  };

  ngOnInit() {
    this.test = 'Some title'
  }
}

Код выше обычно генерируется некоторой библиотекой. Угловая упаковка также имеет такой же формат. Это также не будет работать с aot. Мы должны отправить metadata.json файл с нашей библиотекой для компиляции AOT.

3) получение метаданных, созданных с помощью декораторов

@Component({
  selector: 'my-app',
  templateUrl: `./app.component.html`
})
export class AppComponent {
  @HostBinding('title') test = 'Some title';
}

Компилятор Typescript преобразует предыдущий код в

 var AppComponent = (function () {
    function AppComponent() {
        this.test = 'Some title';
    }
    return AppComponent;
}());
__decorate([
    HostBinding('title')
], AppComponent.prototype, "test", void 0);
AppComponent = __decorate([
    Component({
        selector: 'my-app',
        templateUrl: "./app.component.html"
    })
], AppComponent);

этот код выполняется в режиме JIT, поэтому angular вызывает Component decorator

const TypeDecorator: TypeDecorator = <TypeDecorator>function TypeDecorator(cls: Type<any>) {
      // Use of Object.defineProperty is important since it creates non-enumerable property which
      // prevents the property is copied during subclassing.
      const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
          (cls as any)[ANNOTATIONS] :
          Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS];
      annotations.push(annotationInstance);
      return cls;
};

Сегодня он не использует Reflect API больше. Компилятор читает данные напрямую из __annotations__ имущество

if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
  return (typeOrFunc as any)[ANNOTATIONS];
}

JIT-компилятор создает javascript ngfactories

AOT-компилятор

работает на стороне сервера (nodejs) во время сборки, используя ngc,

С AOT нет этапа компиляции во время выполнения. Когда мы запускаем наше приложение в браузере, мы уже предварительно скомпилировали ngfactories, Это дает нам лучшую производительность вначале и ленивую нагрузку. Мы также не грузим @angular/compiler код в нашей рабочей комплектации больше. Но наш пакет может значительно вырасти из-за нашего ngfactories код.

Компилятор AOT использует API- интерфейс машинописи для анализа машинописного кода. Чтобы получить метаданные, компилятор проходит через API-интерфейсы StaticSymbolResolver и MetadataCollector.

Так что требуется app.component.ts файл и создает машинописную объектную модель. Так что наши AppComponent класс будет представлен как NodeObject с типом 229 (ClassDeclaration)

как мы видим, этот объект имеет decorators имущество

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

Когда встречается компилятор d.ts файл пытается получить метаданные из metadata.json:

if (DTS.test(filePath)) {
  var metadataPath = filePath.replace(DTS, '.metadata.json');
  if (this.context.fileExists(metadataPath)) {
    return this.readMetadata(metadataPath, filePath);
  }
  else {
    // If there is a .d.ts file but no metadata file we need to produce a
    // v3 metadata from the .d.ts file as v3 includes the exports we need
    // to resolve symbols.
    return [this.upgradeVersion1Metadata({ '__symbolic': 'module', 'version': 1, 'metadata': {} }, filePath)];
  }
}

И, наконец, компилятор AOT использует TypeScriptEmitter для создания надписей ngfactories (angular <4.4.0)

Смотрите также

После того как браузер загрузит ваши приложения, Angular-компилятор (упакованный в vendor.bundle.js) выполняет компиляцию шаблонов из main.bundle.js. Это называется сборкой Just-in-Time. Этот термин означает, что компиляция происходит во время поступления пакетов в браузер.

Недостатки компиляции JIT:

  1. Существует промежуток времени между загрузкой пакетов и рендерингом пользовательского интерфейса. Это время уходит на сборку JiT. В небольшом приложении это время минимально, но в более крупных приложениях JiT-компиляция может занять пару секунд, поэтому пользователю нужно подождать дольше, чтобы просто увидеть ваше приложение.

  2. Компилятор Angular должен быть включен в vendor.bundle.js, который увеличивает размер вашего приложения.

Использование JiT-компиляции в prod не рекомендуется, и мы хотим, чтобы шаблоны были предварительно скомпилированы в JavaScript перед созданием пакетов. Это то, что представляет собой компиляция Ahead-of-Time (AoT).

Преимущества компиляции AoT:

  1. Браузер может отображать пользовательский интерфейс сразу после загрузки приложения. Нет необходимости ждать компиляции кода.

  2. Компилятор ngc не включен в vendor.bundle.js, и результирующий размер вашего приложения может быть меньше.

Если вы используете Webpack, для выполнения AoT вам нужно вызвать компилятор ngc. Например:

"build:aot": "ngc -p tsconfig.json && webpack --config webpack.config.js"
Другие вопросы по тегам