Компиляция Ahead-of-Time
Узнайте, как использовать компиляцию ahead-of-time.
Этот кулинарный справочник описывает, как радикально улучшить производительность, выполнив компиляцию ahead-of-time (AOT) во время процесса сборки.
Содержание
- Обзор
- Ahead-of-time (AOT) против just-in-time (JIT)
- Зачем использовать AOT компиляцию?
- Компиляция с AOT
- Инициализация
- Устранение лишнего кода
- Загрузка бандла
- Запуск приложения
- Исходный код AOT QuickStart
- Рабочий процесс и удобный скрипт
- Тур по героям
Обзор
Приложения Angular в основном состоят из компонентов и их HTML-шаблонов. Прежде чем браузер сможет отобразить приложение, компоненты и шаблоны должны быть преобразованы в исполняемый JavaScript с помощью компилятора Angular.
Посмотрите, как автор компилятора Tobias Bosch объясняет компилятор Angular на AngularConnect 2016.
Вы можете скомпилировать приложение в браузере, во время выполнения, по мере загрузки приложения, используя just-in-time (JIT) компилятор. Это стандартный подход к разработке, показанный на протяжении всей документации. Это отлично, но у него есть недостатки.
JIT компиляция влечет за собой штраф за производительность во время выполнения. Виды отображаются дольше из-за шага компиляции в браузере. Приложение больше, потому что оно включает компилятор Angular и много кода библиотек, который приложению на самом деле не нужен. Более крупные приложения загружаются дольше и медленнее.
Компиляция может выявить множество ошибок привязки компонентов и шаблонов. JIT компиляция обнаруживает их во время выполнения, что происходит поздно в процессе.
Ahead-of-time (AOT) компилятор может обнаруживать ошибки шаблонов на ранней стадии и улучшать производительность, компилируя на этапе сборки.
Ahead-of-time (AOT) против just-in-time (JIT)
На самом деле существует только один компилятор Angular. Разница между AOT и JIT заключается в планировании и инструментах. При AOT компилятор выполняется один раз на этапе сборки, используя один набор библиотек; при JIT он выполняется каждый раз для каждого пользователя во время выполнения, используя другой набор библиотек.
Зачем использовать AOT компиляцию?
Более быстрое отображение
При AOT браузер загружает предварительно скомпилированную версию приложения. Браузер загружает исполняемый код, чтобы сразу отобразить приложение, не дожидаясь компиляции приложения.
Меньше асинхронных запросов
Компилятор встраивает внешние HTML-шаблоны и CSS-стили в JavaScript приложения, исключая отдельные запросы ajax для этих файлов.
Меньший размер загрузки фреймворка Angular
Нет необходимости загружать компилятор Angular, если приложение уже скомпилировано. Компилятор занимает примерно половину от самого Angular, поэтому его исключение значительно уменьшает нагрузку на приложение.
Ранее обнаружение ошибок шаблонов
AOT компилятор обнаруживает и сообщает об ошибках привязки шаблонов на этапе сборки, прежде чем пользователи смогут их увидеть.
Лучшая безопасность
AOT компилирует HTML-шаблоны и компоненты в файлы JavaScript задолго до того, как они будут переданы клиенту. Без шаблонов для чтения и без рискованной оценки клиентского HTML или JavaScript, существует меньше возможностей для атак с внедрением.
Компиляция с AOT
Подготовка к оффлайн-компиляции требует нескольких простых шагов. Возьмите Настройку в качестве отправной точки. Несколько незначительных изменений в единственном app.component приводят к этим двум файлам класса и HTML:
<button (click)="toggleHeading()">Toggle Heading</button>
<h1 *ngIf="showHeading">Hello Angular</h1>
<h3>List of Heroes</h3>
<div *ngFor="let hero of heroes">{{hero}}</div>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html'
})
export class AppComponent {
showHeading = true;
heroes = ['Magneta', 'Bombasto', 'Magma', 'Tornado'];
toggleHeading() {
this.showHeading = !this.showHeading;
}
}
Установите несколько новых зависимостей npm с помощью следующей команды:
npm install @angular/compiler-cli @angular/platform-server --save
Вы будете запускать ngc компилятор, предоставленный в @angular/compiler-cli npm-пакете, вместо компилятора TypeScript (tsc).
ngc является прямым заменителем tsc и настраивается аналогичным образом.
ngc требует собственного tsconfig.json с настройками, ориентированными на AOT. Скопируйте исходный src/tsconfig.json в файл tsconfig-aot.json в корне проекта, затем измените его следующим образом.
tsconfig-aot.json
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"src/app/app.module.ts",
"src/main.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}
Раздел compilerOptions не изменен, за исключением одной свойства. Установите module в es2015. Это важно, как объясняется позже в разделе Устранение лишнего кода.
Что действительно нового, так это раздел ngc внизу под названием angularCompilerOptions. Его свойство genDir указывает компилятору сохранять скомпилированные выходные файлы в новую папку aot.
Свойство "skipMetadataEmit" : true предотвращает генерацию компилятором файлов метаданных с скомпилированным приложением. Файлы метаданных не нужны при работе с файлами TypeScript, поэтому нет необходимости включать их.
Компонентно-относительные URL-адреса шаблонов
AOT компилятор требует, чтобы @Component URL-адреса для внешних шаблонов и CSS-файлов были компонентно-относительными. Это означает, что значение @Component.templateUrl является значением URL-адреса относительно файла класса компонента. Например, 'app.component.html' URL-адрес означает, что файл шаблона является братом своего файла-компаньона app.component.ts.
Хотя URL-адреса JIT-приложений более гибкие, придерживайтесь компонентно-относительных URL-адресов для совместимости с AOT-компиляцией.
Компиляция приложения
Запустите AOT компиляцию из командной строки, используя установленный ранее ngc компилятор, выполнив:
node_modules/.bin/ngc -p tsconfig-aot.json
Пользователи Windows должны заключить команду
ngcв двойные кавычки:"node_modules/.bin/ngc" -p tsconfig-aot.json
ngc ожидает, что переключатель -p укажет на файл tsconfig.json или папку, содержащую файл tsconfig.json.
После завершения ngc, найдите коллекцию файлов NgFactory в папке aot. Папка aot — это каталог, указанный как genDir в tsconfig-aot.json.
Эти файлы-фабрики необходимы для скомпилированного приложения. Каждая фабрика компонента создает экземпляр компонента во время выполнения, комбинируя исходный файл класса и JavaScript-представление шаблона компонента. Обратите внимание, что исходный класс компонента по-прежнему ссылается внутри сгенерированной фабрики.
Любопытные могут открыть
aot/app.component.ngfactory.tsдля просмотра исходного синтаксиса шаблонов Angular, скомпилированного в TypeScript, его промежуточной форме.JIT компиляция генерирует те же NgFactories в памяти, где они в значительной степени незаметны. AOT компиляция показывает их как отдельные физические файлы.
Не редактируйте NgFactories! Перекомпиляция заменяет эти файлы, и все правки будут потеряны.
Инициализация
Подход AOT изменяет инициализацию приложения.
Вместо инициализации AppModule, вы инициализируете приложение с помощью сгенерированной фабрики модуля, AppModuleNgFactory.
Сделайте копию main.ts и назовите её main-jit.ts. Это версия JIT; оставьте её на случай, если вам понадобится она позже.
Откройте main.ts и преобразуйте его для компиляции AOT. Переключитесь с platformBrowserDynamic.bootstrap (используемый в JIT компиляции) на platformBrowser().bootstrapModuleFactory и передайте сгенерированный AOT AppModuleNgFactory.
Вот инициализация AOT в main.ts рядом с оригинальной версией JIT:
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory';
console.log('Running AOT compiled');
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
console.log('Running JIT compiled');
platformBrowserDynamic().bootstrapModule(AppModule);
Не забудьте перекомпилировать с ngc!
Устранение лишнего кода
AOT компиляция подготавливает почву для дальнейшей оптимизации с помощью процесса, называемого устранением лишнего кода. Утилита устранения лишнего кода проходит по графу зависимостей сверху вниз и удаляет неиспользуемый код, как сухие листья в дереве.
Устранение лишнего кода может значительно уменьшить размер загружаемого приложения, удаляя неиспользуемые части как исходного, так и библиотечного кода. В действительности, большая часть сокращения в небольших приложениях происходит от удаления неиспользуемых функций Angular.
Например, это демонстрационное приложение не использует ничего из библиотеки @angular/forms. Нет причин загружать связанный с формами код Angular, и устранение лишнего кода гарантирует, что вы этого не сделаете.
Устранение лишнего кода и AOT компиляция — это отдельные шаги. Устранение лишнего кода может применяться только к JavaScript коду. AOT компиляция преобразует больше части приложения в JavaScript, что, в свою очередь, делает больше частей приложения «устранимыми».
Rollup
Этот кулинарный справочник демонстрирует утилиту устранения лишнего кода под названием Rollup.
Rollup статически анализирует приложение, следуя следам import и export инструкций. Он генерирует конечный бандл кода, исключая код, который экспортируется, но никогда не импортируется.
Rollup может устранять лишний код только в ES2015 модулях, которые имеют import и export инструкции.
Вспомните, что
tsconfig-aot.jsonнастроен на созданиеES2015модулей. Неважно, написан ли сам код сES2015синтаксисом, таким какclassиconst. Важно, чтобы код использовал ESimportиexportинструкции вместоrequireинструкций.
В окне терминала установите зависимости Rollup с помощью этой команды:
npm install rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-uglify --save-dev
Далее, создайте файл конфигурации (rollup-config.js) в корневом каталоге проекта, чтобы указать Rollup, как обработать приложение. Файл конфигурации кулинарного справочника выглядит следующим образом.
rollup-config.js
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
export default {
entry: 'src/main.js',
dest: 'src/build.js', // output a single application bundle
sourceMap: false,
format: 'iife',
onwarn: function(warning) {
// Skip certain warnings
// should intercept ... but doesn't in some rollup versions
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
// intercepts in some rollup versions
if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; }
// console.warn everything else
console.warn( warning.message );
},
plugins: [
nodeResolve({jsnext: true, module: true}),
commonjs({
include: 'node_modules/rxjs/**',
}),
uglify()
]
}
Этот файл конфигурации сообщает Rollup, что точка входа приложения — src/app/main.js. Атрибут dest сообщает Rollup, что необходимо создать пакет под названием build.js в папке dist. Он переопределяет метод по умолчанию onwarn для пропуска раздражающих сообщений о том, что компилятор AOT использует ключевое слово this.
Следующий раздел более подробно описывает плагины.
Плагины Rollup
Необязательные плагины фильтруют и преобразуют входные и выходные данные Rollup.
RxJS
Rollup ожидает, что исходный код приложения будет использовать ES2015 модули. Не все внешние зависимости публикуются как ES2015 модули. На самом деле, большинство из них нет. Многие из них публикуются как модули CommonJS.
Библиотека наблюдаемых RxJs — это важная зависимость Angular, опубликованная как модуль ES5 JavaScript CommonJS.
К счастью, существует плагин Rollup, который изменяет RxJs, чтобы использовать операторы ES import и export , необходимые Rollup. Затем Rollup сохраняет части RxJS , на которые ссылается приложение, в итоговом пакете. Его использование простое. Добавьте следующее в массив plugins в rollup-config.js:
rollup-config.js (Плагин CommonJs в ES2015)
commonjs({
include: 'node_modules/rxjs/**',
}),
Минимизация
Сжатие дерева кода Rollup значительно уменьшает его размер. Минимизация уменьшает его еще больше. В этом руководстве используется плагин Rollup uglify для минимизации и искажения кода. Добавьте следующее в массив plugins:
rollup-config.js (Плагин CommonJs в ES2015)
uglify()
В производственной среде также необходимо включить gzip на веб-сервере, чтобы сжать код в еще меньший пакет при передаче по сети.
Запуск Rollup
Выполните процесс Rollup с этой командой:
node_modules/.bin/rollup -c rollup-config.js
Пользователи Windows должны заключить команду
rollupв двойные кавычки:"node_modules/.bin/rollup" -c rollup-config.js
Загрузка пакета
Загрузка сгенерированного пакета приложения не требует загрузчика модулей, такого как SystemJS. Удалите скрипты, связанные с SystemJS. Вместо этого загрузите файл пакета с помощью одного тега <script> после тега </body>:
index.html (загрузка пакета)
<script src="build.js"></script>
Оказание приложения
Для размещения приложения потребуется веб-сервер. Используйте тот же сервер lite-server , что и в других разделах документации:
npm run lite
Сервер запускается, запускается браузер, и приложение должно появиться.
Исходный код быстрого старта AOT
Вот соответствующий исходный код:
<button (click)="toggleHeading()">Toggle Heading</button>
<h1 *ngIf="showHeading">Hello Angular</h1>
<h3>List of Heroes</h3>
<div *ngFor="let hero of heroes">{{hero}}</div>
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html'
})
export class AppComponent {
showHeading = true;
heroes = ['Magneta', 'Bombasto', 'Magma', 'Tornado'];
toggleHeading() {
this.showHeading = !this.showHeading;
}
}
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory';
console.log('Running AOT compiled');
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
<!DOCTYPE html>
<html>
<head>
<title>Ahead of time compilation</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
<script src="build.js"></script>
</html>
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"src/app/app.module.ts",
"src/main.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
export default {
entry: 'src/main.js',
dest: 'src/build.js', // output a single application bundle
sourceMap: false,
format: 'iife',
onwarn: function(warning) {
// Skip certain warnings
// should intercept ... but doesn't in some rollup versions
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
// intercepts in some rollup versions
if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; }
// console.warn everything else
console.warn( warning.message );
},
plugins: [
nodeResolve({jsnext: true, module: true}),
commonjs({
include: 'node_modules/rxjs/**',
}),
uglify()
]
}
Поток работы и удобный скрипт
Каждый раз, когда вы вносите изменения, вам потребуется перестроить AOT-версию приложения. Эти команды npm длинные и сложные для запоминания.
Добавьте в package.json следующий удобный скрипт npm для компиляции и сборки в одной команде.
package.json (скрипт build:aot)
{
"scripts": {
"build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js"
}
}
Откройте окно терминала и попробуйте.
npm run build:aot
Разработка JIT вместе с AOT
Компиляция AOT и сборка вместе занимают несколько секунд. Возможно, вы сможете немного быстрее итеративно разрабатывать с помощью SystemJS и JIT. Один и тот же исходный код может быть собран двумя способами. Вот один из них.
- Сделайте копию
index.htmlи назовите ееindex-jit.html. - Удалите скрипт в нижней части
index-jit.html, который загружаетbundle.js - Восстановите скрипты SystemJS следующим образом:
src/index-jit.html (скрипты SystemJS)
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main-jit.js').catch(function(err){ console.error(err); });
</script>
Обратите внимание на небольшое изменение в system.import, которое теперь указывает на src/app/main-jit. Это JIT-версия файла загрузки, которую мы сохранили выше.
Откройте другое окно терминала и введите npm start.
npm start
Это компилирует приложение с JIT и запускает сервер. Сервер загружает index.html, что по-прежнему является AOT-версией, что можно подтвердить в консоли браузера. Измените адресную строку на index-jit.html , и она загрузит JIT-версию. Это также видно в консоли браузера.
Разрабатывайте как обычно. Сервер и компилятор TypeScript находятся в режиме «наблюдения», поэтому ваши изменения отражаются сразу в браузере.
Чтобы увидеть эти изменения в AOT, переключитесь на исходный терминал и снова запустите npm run build:aot. После завершения вернитесь в браузер и используйте кнопку «Назад», чтобы вернуться к AOT-версии в стандартном index.html.
Теперь вы можете разрабатывать JIT и AOT одновременно.
Тур по героям
Приведенный выше пример — это тривиальная вариация приложения QuickStart. В этом разделе вы применяете то, что узнали о компиляции AOT и сжатии дерева, к приложению с большей информативностью, приложению «Тур по героям».
JIT в разработке, AOT в производстве
Сегодня компиляция AOT и сжатие дерева занимают больше времени, чем это практично для разработки. Скоро это изменится. Пока лучше компилировать JIT в процессе разработки и переключаться на компиляцию AOT перед развертыванием в производство.
К счастью, исходный код может быть скомпилирован любым способом без изменений, если вы учтете несколько ключевых различий.
index.html
Приложения JIT и AOT требуют своих собственных файлов index.html , поскольку они настраиваются и запускаются совершенно по-разному.
Вот они для сравнения:
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Angular Tour of Heroes</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<script src="shim.min.js"></script>
<script src="zone.min.js"></script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
<script src="dist/build.js"></script>
</html>
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Angular Tour of Heroes</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- Polyfills -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
JIT-версия полагается на SystemJS для загрузки отдельных модулей. Ее скрипты отображаются в ее index.html.
AOT-версия загружает все приложение в одном скрипте aot/dist/build.js . Она не нуждается в SystemJS , поэтому этот скрипт отсутствует в ее index.html
main.ts
JIT и AOT-приложения загружаются примерно одинаково, но для этого требуются разные библиотеки Angular. Ключевые различия, рассмотренные в разделе «Загрузка» выше, очевидны в этих файлах main , которые могут и должны находиться в одной папке:
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
Конфигурация TypeScript
Приложения, скомпилированные JIT, транслируются в commonjs модули. Приложения, скомпилированные AOT, транслируются в модули ES2015/ES6 для облегчения сжатия дерева. AOT требует своих собственных параметров конфигурации TypeScript.
Вам понадобятся отдельные файлы конфигурации TypeScript, такие как эти:
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"../../node_modules/@types/"
]
},
"files": [
"src/app/app.module.ts",
"src/main-aot.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}
}
В структуре файлов этого конкретного образца проекта папка node_modules находится на два уровня выше корня проекта. Поэтому "typeRoots" должно быть установлено в "../../node_modules/@types/".
В более типичном проекте node_modules будет находиться рядом с tsconfig-aot.json , и "typeRoots" должно быть установлено в "node_modules/@types/". Измените свой tsconfig-aot.json в соответствии со структурой файлов вашего проекта.
Сжатие дерева
Rollup выполняет сжатие дерева как и раньше.
rollup-config.js
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
//paths are relative to the execution path
export default {
entry: 'src/main-aot.js',
dest: 'aot/dist/build.js', // output a single application bundle
sourceMap: true,
sourceMapFile: 'aot/dist/build.js.map',
format: 'iife',
onwarn: function(warning) {
// Skip certain warnings
// should intercept ... but doesn't in some rollup versions
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
// intercepts in some rollup versions
if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; }
// console.warn everything else
console.warn( warning.message );
},
plugins: [
nodeResolve({jsnext: true, module: true}),
commonjs({
include: ['node_modules/rxjs/**']
}),
uglify()
]
}
Запуск приложения
Инструкции для общей аудитории по запуску AOT-сборки приложения «Тур по героям» еще не готовы.
Следующие инструкции предполагают, что вы клонировали репозиторий github angular.io и подготовили его к разработке, как описано в файле README.md репозитория.
Исходный код «Тура по героям» находится в папке
public/docs/_examples/toh-6/ts.
Запустите JIT-скомпилированное приложение с помощью npm start , как и для всех других JIT-примеров.
Компиляция с AOT предполагает определенные поддерживающие файлы, большинство из которых обсуждались выше.
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Angular Tour of Heroes</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- Polyfills -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
var fs = require('fs');
var resources = [
'node_modules/core-js/client/shim.min.js',
'node_modules/zone.js/dist/zone.min.js',
'src/styles.css'
];
resources.map(function(f) {
var path = f.split('/');
var t = 'aot/' + path[path.length-1];
fs.createReadStream(f).pipe(fs.createWriteStream(t));
});
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
//paths are relative to the execution path
export default {
entry: 'src/main-aot.js',
dest: 'aot/dist/build.js', // output a single application bundle
sourceMap: true,
sourceMapFile: 'aot/dist/build.js.map',
format: 'iife',
onwarn: function(warning) {
// Skip certain warnings
// should intercept ... but doesn't in some rollup versions
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
// intercepts in some rollup versions
if ( warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; }
// console.warn everything else
console.warn( warning.message );
},
plugins: [
nodeResolve({jsnext: true, module: true}),
commonjs({
include: ['node_modules/rxjs/**']
}),
uglify()
]
}
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"../../node_modules/@types/"
]
},
"files": [
"src/app/app.module.ts",
"src/main-aot.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}
Расширьте раздел scripts в package.json следующими скриптами npm:
package.json (удобные скрипты)
{
"scripts": {
"build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
"serve:aot": "lite-server -c bs-config.aot.json"
}
}
Скопируйте файлы AOT-распределения в папку /aot с помощью скрипта node:
node copy-dist-files
Вы не будете делать этого снова, пока не появятся обновления
zone.jsилиcore-jsплагина для старых браузеров.
Теперь скомпилируйте приложение AOT и запустите его с помощью lite-server:
npm run build:aot && npm run serve:aot
Просмотр пакета
Интересно посмотреть, как выглядит сгенерированный пакет JavaScript после Rollup. Код сжат, поэтому при прямом просмотре пакета вы не многое узнаете. Но инструмент source-map-explorer может быть довольно информативным.
Установите его:
npm install source-map-explorer --save-dev
Запустите следующую команду для создания карты:
node_modules/.bin/source-map-explorer aot/dist/build.js
source-map-explorer анализирует сгенерированную карту исходного кода с пакетом и строит карту всех зависимостей, показывая, какие модули и классы приложения и Angular включены в пакет.
Вот карта для «Тура по героям».
© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://v2.angular.io/docs/ts/latest/cookbook/aot-compiler.html