Spec-Zone.ru › Angular 2

Развёртывание

Узнайте, как развернуть ваше приложение Angular.

Эта страница описывает инструменты и методы для развёртывания и оптимизации вашего приложения Angular.

Содержание

  • Обзор
  • Самое простое возможное развёртывание
  • Оптимизация для производства
    • Компиляция Ahead-of-Time (AOT)
    • Webpack
    • Удаление неиспользуемого кода с rollup
    • Удалённые библиотеки
    • Сначала измерьте производительность
  • Настройка Angular
    • Тег base
    • Включить режим производства
    • Ленивая загрузка
  • Настройка сервера
    • Приложения с маршрутизацией должны использовать index.html
    • CORS: запрос услуг с другого сервера

Обзор

Это руководство описывает методы подготовки и развёртывания приложения Angular на удалённом сервере. Методы переходят от простых, но не оптимальных к более оптимальным и более сложным.

  • Простой способ — скопировать среду разработки на сервер.

  • Компиляция Ahead of Time (AOT) — это первая из нескольких стратегий оптимизации. Вам также нужно прочитать подробные инструкции в кулинарной книге AOT.

  • Webpack — популярный универсальный инструмент для создания пакетов с богатым экосистемой, включая плагины для AOT. Руководство Angular по Webpack поможет вам начать работу, а на этой странице приведены дополнительные советы по оптимизации, но, вероятно, вам придётся самостоятельно узнать больше о Webpack.

  • В разделе настройки Angular обращается внимание на конкретные изменения в приложении клиента, которые могут улучшить производительность.

  • Раздел настройки сервера описывает изменения на стороне сервера, которые могут потребоваться независимо от способа развёртывания приложения.

Самое простое возможное развёртывание

Самый простой способ развернуть приложение — опубликовать его на веб-сервере непосредственно из среды разработки.

Приложение уже запущено локально. Вам нужно просто скопировать его, практически без изменений, на удалённый сервер, доступный другим пользователям.

  1. Скопируйте всё (или почти всё) из локальной папки проекта в папку на сервере.

  2. Если вы развертываете приложение в подпапке, отредактируйте версию index.html, чтобы правильно установить <base href>. Например, если URL до index.html — www.mysite.com/my/app/, установите base href в <base href="/my/app/">. В противном случае оставьте его как есть. Подробнее об этом ниже.

  3. Настройте сервер таким образом, чтобы он перенаправлял запросы на отсутствующие файлы в index.html. Подробнее об этом ниже.

  4. Включите режим производства, как описано ниже (необязательно).

Это самое простое развертывание, которое вы можете сделать.

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

Загрузка файлов пакетов npm из сети (SystemJS)

Папка node_modules пакетов npm содержит гораздо больше кода, чем необходимо для фактического запуска вашего приложения в браузере. node_modules для установки Quickstart обычно содержит более 20 500 файлов и более 180 МБ. Само приложение требует лишь незначительной части этого объёма для работы.

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

Вместо этого загружайте нужные файлы из сети.

(1) Сделайте копию index.html для развертывания и замените все node_module скрипты версиями, которые загружают из сети. Это может выглядеть так.

<!-- Polyfills -->
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>

<!-- Update these package versions as needed -->
<script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>

(2) Замените systemjs.config.js скрипт скриптом, который загружает systemjs.config.server.js.

<!-- This SystemJS configuration loads umd packages from the web -->
<script src="systemjs.config.server.js"></script>

(3) Добавьте systemjs.config.server.js (показано в примере кода ниже) в папку src/. Эта альтернативная версия настраивает SystemJS для загрузки UMD версий Angular (и других сторонних пакетов) из сети.

Измените systemjs.config.server.js по мере необходимости, чтобы оставаться в синхронизации с изменениями, которые вы вносите в systemjs.config.js.

Обратите внимание на ключ paths.

paths: {
  'npm:': 'https://unpkg.com/' // path serves as alias
},

В стандартной конфигурации SystemJS путь npm указывает на node_modules/. В этой конфигурации сервера он указывает на https://unpkg.com, сайт, на котором размещены пакеты npm, и загружает их непосредственно из сети. Существуют и другие поставщики услуг, которые делают то же самое.

Если вы не хотите или не можете загружать пакеты из открытой сети, инвентарь в systemjs.config.server.js указывает файлы и папки, которые вы скопируете в папку библиотек на сервере. Затем измените путь 'npm' в конфигурации, чтобы он указывал на эту папку.

Практика с примером

Следующее тривиальное приложение с примером маршрутизатора демонстрирует эти изменения.

index.html
<!DOCTYPE html>
<html>
  <head>
    <!-- Doesn't load from node_modules! -->

    <!-- Set the base href -->
    <base href="/">
    <title>Simple Deployment</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- Polyfills -->
    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>

    <!-- Update these package versions as needed -->
    <script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
    <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>

    <!-- This SystemJS configuration loads umd packages from the web -->
    <script src="systemjs.config.server.js"></script>

    <script>
      System.import('main.js')
            .catch(function(err){ console.error(err); });
    </script>
  </head>

  <body>
    <my-app>loading...</my-app>
  </body>

</html>
systemjs.config.server.js
/**
 * System configuration for deployment without installing node_modules
 * Loads umd packages from the web instead
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      'npm:': 'https://unpkg.com/' // path serves as alias
    },
    // map tells the System loader where to look for things
    map: {
      app: 'app', // location of transpiled app files

      // angular minimized umd bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.min.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.min.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.min.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.min.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.min.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.min.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.min.js',
      '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.min.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.min.js',
      '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.min.js',
      '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.min.js',

      // other libraries
      'rxjs':                      'npm:rxjs@5.0.1',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      }
    }
  });
  })(this);
main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

import { enableProdMode } from '@angular/core';

// Enable production mode unless running locally
if (!/localhost/.test(document.location.host)) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule);
app/app.module.ts
import { NgModule }             from '@angular/core';
import { BrowserModule }        from '@angular/platform-browser';
import { RouterModule, Routes } from '@angular/router';

import { AppComponent }           from './app.component';
import { CrisisListComponent }    from './crisis-list.component';
import { HeroListComponent }      from './hero-list.component';

const appRoutes: Routes = [
  { path: 'crisis-center', component: CrisisListComponent },
  { path: 'heroes',        component: HeroListComponent },

  { path: '', redirectTo: '/heroes', pathMatch: 'full' }
];

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(appRoutes)
  ],
  declarations: [
    AppComponent,
    CrisisListComponent,
    HeroListComponent
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }
app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <h1>Simple Deployment</h1>
    <nav>
      <a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
      <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
    </nav>
    <router-outlet></router-outlet>
  `
})
export class AppComponent { }
app/crisis-list.component.ts
import { Component } from '@angular/core';

@Component({
  template: `
    <h2>CRISIS CENTER</h2>
    <p>Get your crisis here</p>`
})
export class CrisisListComponent { }
app/hero-list.component.ts
import { Component } from '@angular/core';

@Component({
  template: `
    <h2>HEROES</h2>
    <p>Get your heroes here</p>
  `
})
export class HeroListComponent { }

Потренируйтесь с этим примером, прежде чем применять эти методы к своему приложению.

  1. Следуйте инструкциям по установке для создания нового проекта под названием .

  2. Добавьте файлы-примеры "Простого развертывания", показанные выше.

  3. Запустите его с npm start как любой другой проект.

  4. Проверьте сетевой трафик в инструментах разработчика браузера. Обратите внимание, что все пакеты загружаются из сети. Вы можете удалить папку node_modules и приложение всё равно будет работать (хотя вы не сможете перекомпилировать или запустить lite-server до тех пор, пока вы не восстановите её).

  5. Разверните пример на сервере (без папки node_modules!).

После того, как это будет работать, попробуйте применить тот же процесс к своему приложению.

Оптимизация для производства

Хотя развертывание непосредственно из среды разработки работает, это далеко не оптимальный вариант.

Клиент делает много небольших запросов для отдельных файлов кода и шаблонов приложения, что вы быстро можете подтвердить, посмотрев вкладку «Сеть» в инструментах разработчика браузера. Загрузка каждого небольшого файла может тратить больше времени на общение с сервером, чем передача данных.

Файлы разработки заполнены комментариями и пробелами для удобства чтения и отладки. Браузер загружает целые библиотеки вместо того, чтобы загружать только те части, которые необходимо приложению. Объём кода, передаваемого с сервера на клиент («полезная нагрузка»), может быть значительно больше, чем это строго необходимо для выполнения приложения.

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

Это важно? Это зависит от бизнес- и технических факторов, которые вы должны оценить самостоятельно.

Если это важно, существуют инструменты и методы для уменьшения количества запросов и размера ответов.

  • Компиляция Ahead-of-Time (AOT): предварительная компиляция шаблонов компонентов Angular.
  • Бенделинг: объединяет модули в один файл (бандл).
  • Встраивание: вставляет html и css шаблоны в компоненты.
  • Минификация: удаляет лишние пробелы, комментарии и необязательные токены.
  • Угнетение: переписывает код, используя короткие и загадочные имена переменных и функций.
  • Удаление неиспользуемого кода: удаляет неиспользуемые модули и неиспользуемый код.
  • Удалённые библиотеки: удаление неиспользуемых библиотек и сокращение других до необходимых функций.
  • Измерение производительности: фокус на оптимизациях, которые дают измеримый эффект.

Каждый инструмент выполняет что-то своё. Они работают лучше всего в сочетании и взаимно усиливают друг друга.

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

Компиляция Ahead-of-Time (AOT)

Компилятор Angular Ahead-of-Time предварительно компилирует компоненты приложения и их шаблоны во время процесса сборки.

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

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

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

Webpack (и AOT)

Webpack 2 — ещё один отличный вариант для встраивания шаблонов и стилей, для создания бандлов, минификации и угнетения приложения. Руководство "Webpack: введение" поможет вам начать работу с Webpack и Angular.

Рассмотрите возможность настройки Webpack с официальным плагином Angular Ahead-of-Time Webpack Plugin. Этот плагин транспилирует код приложения TypeScript, объединяет лениво загружаемые NgModules отдельно и выполняет компиляцию AOT — без каких-либо изменений в исходном коде.

Удаление неиспользуемого кода с rollup

Любой код, который вы не вызываете, — это мертвый код. Вы можете существенно уменьшить общий размер приложения, удалив мертвый код из приложения и из сторонних библиотек.

Сжатие дерева — это техника удаления мертвого кода, которая удаляет целые экспорты из модулей JavaScript. Если библиотека экспортирует что-то, чего приложение не импортирует, инструмент сжатия дерева удаляет его из кодовой базы.

Сжатие дерева было популяризовано Rollup, популярным инструментом с экосистемой плагинов для объединения, минимизации и уродливания. Узнайте больше о сжатии дерева и удалении мертвого кода в этой статье от создателя Rollup, Ричарда Харриса.

Удаленные библиотеки

Не полагайтесь на автоматизацию для удаления всего мертвого кода.

Удаляйте библиотеки, которые вы не используете, особенно ненужные скрипты в index.html. Рассмотрите более компактные альтернативы используемым вами библиотекам.

Некоторые библиотеки предлагают средства для создания пользовательской, компактной версии с необходимыми функциями. Другие библиотеки позволяют импортировать функции по отдельности. RxJS — хороший пример; импортируйте операторы RxJS Observable по отдельности вместо всей библиотеки.

Измерьте производительность в первую очередь

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

Страница Chrome DevTools Network Performance — хорошее место для начала изучения измерения производительности.

Инструмент WebPageTest — ещё один хороший вариант, который также поможет проверить успешность развертывания.

Настройка Angular

Настройка Angular может повлиять на то, запустится ли приложение быстро или вообще не загрузится.

Тег base

HTML-тег <base href="..."/> указывает базовый путь для разрешения относительных URL-адресов к ресурсам, таким как изображения, скрипты и таблицы стилей. Например, при заданном <base href="/my/app/">, браузер преобразует URL, такой как some/place/foo.jpg, в запрос серверу для my/app/some/place/foo.jpg. Во время навигации маршрутизатор Angular использует базовый href в качестве базового пути к файлам компонентов, шаблонов и модулей.

См. также альтернативу APP_BASE_HREF.

В режиме разработки вы обычно запускаете сервер в папке, которая содержит index.html. Это корневая папка, и вы бы добавили <base href="/"> в начале index.html, потому что / является корнем приложения.

Но на общем или производственном сервере приложение может быть размещено в подпапке. Например, когда URL для загрузки приложения — это что-то вроде http://www.mysite.com/my/app/, подпапка — my/app/, и вы должны добавить <base href="/my/app/"> к серверной версии index.html.

Если тег base настроен неправильно, приложение не загружается, а консоль браузера отображает ошибки 404 - Not Found для отсутствующих файлов. Обратите внимание на то, где пытались найти эти файлы, и соответствующим образом скорректируйте тег base.

Включить режим производства

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

Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.

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

Чтобы включить производственный режим при удалённом запуске, добавьте следующий код в main.ts.

src/main.ts (enableProdMode)

import { enableProdMode } from '@angular/core';

// Enable production mode unless running locally
if (!/localhost/.test(document.location.host)) {
  enableProdMode();
}

Ленивая загрузка

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

Настройте маршрутизатор Angular для отложенной загрузки всех остальных модулей (и связанного кода), либо, дождавшись запуска приложения, либо лениво загружая их по требованию.

Не следует жадно импортировать что-то из лениво загружаемого модуля

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

Конфигурация объединения должна учитывать ленивую загрузку. Поскольку модули с ленивой загрузкой не импортируются в JavaScript (как только что было отмечено), сборщики по умолчанию исключают их. Сборщики не знают о конфигурации маршрутизатора и не создадут отдельные пакеты для лениво загружаемых модулей. Вам необходимо создать эти пакеты вручную.

Плагин Angular Ahead-of-Time Webpack Plugin автоматически распознаёт лениво загружаемые NgModules и создаёт для них отдельные пакеты.

Настройка сервера

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

Приложения с маршрутизацией должны использовать index.html

Приложения Angular идеально подходят для обслуживания с простым статическим HTML-сервером. Вам не нужен серверный движок для динамического составления страниц приложения, поскольку Angular выполняет эту задачу на стороне клиента.

Если приложение использует маршрутизатор Angular, необходимо настроить сервер на возвращение главной страницы приложения (index.html) при запросе файла, которого у него нет.

Приложение с маршрутизацией должно поддерживать «глубокие ссылки». Глубокая ссылка — это URL, который указывает путь к компоненту внутри приложения. Например, http://www.mysite.com/heroes/42 — это глубокая ссылка на страницу детали героя, которая отображает героя с id: 42.

Проблем нет, когда пользователь переходит по этой ссылке из работающего клиента. Маршрутизатор Angular интерпретирует URL и перенаправляет на эту страницу и героя.

Однако при клике по ссылке в электронном письме, вводе её в адресной строке браузера или просто обновлении браузера на странице детали героя — все эти действия обрабатываются самим браузером, вне работающего приложения. Браузер напрямую обращается к серверу по этому URL, минуя маршрутизатор.

Статический сервер обычно возвращает index.html при получении запроса на http://www.mysite.com/. Но он отклоняет http://www.mysite.com/heroes/42 и возвращает ошибку 404 - Not Found если не настроен на возврат index.html вместо этого.

Примеры конфигурации обратного вызова

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

Сервера разработки

  • Lite-Server: сервер разработки по умолчанию, установленный с репозиторием Quickstart, настроен на обратный вызов к index.html.

  • Webpack-Dev-Server: настройте запись historyApiFallback в опциях сервера разработки следующим образом:

historyApiFallback: {
  disableDotRule: true,
  htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
}

Сервера производства

  • Apache: добавьте правило перенаправления rewrite в файл .htaccess, как показано здесь:
RewriteEngine On  
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
  • NGinx: используйте try_files, как описано в Front Controller Pattern Web Apps, с изменениями для обслуживания index.html:
try_files $uri $uri/ /index.html;
  • IIS: добавьте правило перенаправления в web.config, аналогичное тому, которое показано здесь:
  • GitHub Pages: вы не можете непосредственно настроить сервер GitHub Pages, но вы можете добавить страницу 404. Скопируйте index.html в 404.html. Она всё ещё будет служить ответом 404, но браузер обработает эту страницу и правильно загрузит приложение. Также рекомендуется обслуживать из docs/ в ветке master и создать файл .nojekyll

  • Firebase hosting: добавьте правило перенаправления.

"rewrites": [ {
  "source": "**",
  "destination": "/index.html"
} ]

Запрос услуг с другого сервера (CORS)

Разработчики Angular могут столкнуться с ошибкой совместного использования ресурсов между разными доменными зонами при выполнении запроса к сервису (обычно запроса к сервису данных) на сервер, отличный от собственного сервера приложения. Браузеры запрещают такие запросы, если сервер явно их не разрешает.

Клиентское приложение ничего не может сделать с этими ошибками. Сервер должен быть настроен на приём запросов приложения. Узнайте, как включить CORS для определённых серверов на enable-cors.org.

Следующие шаги

Если вы хотите перейти от подхода простого копирования и развертывания, прочитайте кулинарную книгу по AOT-компилятору далее.

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://v2.angular.io/docs/ts/latest/guide/deployment.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API