На этапе разработки мы будем использовать systemjs для асинхронной загрузки наших ресурсов. Следующий пример представляет собой модификацию файла system.config.js официального руководства по Angular 2.
(function(global) { // map tells the System loader where to look for things var map = { 'app': 'app', // 'dist', 'rxjs': 'node_modules/rxjs', 'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', '@angular': 'node_modules/@angular', 'modules': 'node_modules/', 'ng2-translate': 'node_modules/ng2-translate' }; // packages tells the System loader how to load when no filename and/or no extension var packages = { 'app': { main: 'main.js', defaultExtension: 'js' }, 'rxjs': { defaultExtension: 'js' }, 'angular2-in-memory-web-api': { defaultExtension: 'js' }, 'modules': { defaultExtension: 'js' }, 'ng2-translate': { main: 'ng2-translate.js' }, }; var packageNames = [ '@angular/common', '@angular/compiler', '@angular/core', '@angular/http', '@angular/platform-browser', '@angular/platform-browser-dynamic', '@angular/router-deprecated', '@angular/testing', '@angular/upgrade', ]; // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' } packageNames.forEach(function(pkgName) { packages[pkgName] = { main: 'index.js', defaultExtension: 'js' }; }); var config = { format: 'register', map: map, packages: packages, defaultExtension: 'js', baseURL: 'app-ng2/' }; System.config(config); })(this);
Интересным моментом здесь является поддержка модуля ng2-translate, который является преемником поставщика перевода angular-translate. Автор angular-translate теперь работает с командой Google Angular, чтобы интегрировать тему перевода непосредственно в официальный стек angular.
Теперь мы подготовили все наши конфигурационные файлы и можем приступить к реальной работе.
Интеграция с угловым 2
Во-первых, мы изменим index.html с нашими зависимостями, а также вставим наш файл javascript начальной загрузки Angular 2.
... <!-- build:js vendors2.min.js --> <script src="app-ng2/node_modules/es6-shim/es6-shim.min.js"></script> <script src="app-ng2/node_modules/zone.js/dist/zone.js"></script> <script src="app-ng2/node_modules/reflect-metadata/Reflect.js"></script> <script src="app-ng2/node_modules/systemjs/dist/system.src.js"></script> <script src="app-ng2/systemjs.config.js"></script> <!-- endbuild --> <!-- build:js app2.min.js --> <script src="app-ng2/bootapp.js"></script> <!-- endbuild --> ...
ES6-shim и reflect-metadata — это мерцания для совместимости ES6 со старыми браузерами. Оба модуля необходимы для ssystemjs.
Zone.js реализует зоны. Зона — это контекст выполнения, который сохраняется для асинхронных задач.
systemjs.config.js — это конфигурация SystemJS, которую мы создали ранее.
bootapp.js содержит загрузочный модуль приложения systemjs.
(function() { 'use strict'; angular.element(window).ready(function() { System.import('app').then(null, console.error.bind(console)); }); })();
Когда мы вставляем загрузчик systemjs в отдельный файл, мы можем просто заменить этот файл файлом пакета в процессе сборки релиза.
В файле systemjs.config.js у нас есть псевдоним app, связанный с файлом main.js.
... var packages = { 'app': { main: 'main.js', defaultExtension: 'js' },...
Поэтому, когда браузер открывает index.html, systemjs автоматически загружает файл main.js.
import { upgrade } from './upgrade_adapter'; import { HTTP_PROVIDERS, Http } from '@angular/http'; import { provide } from '@angular/core'; import { LocationStrategy, HashLocationStrategy } from '@angular/common'; import 'rxjs/add/operator/map'; import { TranslateService, TranslateStaticLoader, TranslateLoader } from 'ng2-translate'; import { SettingsAbout } from './settings/about/settings.about.component'; upgrade.addProvider(HTTP_PROVIDERS); upgrade.addProvider(TranslateService); upgrade.addProvider(provide(LocationStrategy, {useClass: HashLocationStrategy})); upgrade.addProvider(provide(TranslateLoader, { useFactory: (http: Http) => new TranslateStaticLoader(http, '/cheetah/api/list/bmcockpits/translate?locale=', ''), deps: [Http] })); upgrade.upgradeNg1Provider('AuthService'); /// <reference path="../typings/angular/angular.d.ts" /> angular.module('app.hmc.settings').directive('settingsAbout', <angular.IDirectiveFactory>upgrade.downgradeNg2Component(SettingsAbout)); upgrade.bootstrap(document.body, ['app']);
Как обычно в начале файла ts идут импорты. Здесь интересен импорт модуля обновления. Содержание модуля upgrade_adapter.ts следующее:
import { UpgradeAdapter } from '@angular/upgrade'; export const upgrade = new UpgradeAdapter();
Здесь мы создаем адаптер постоянного обновления. Это означает, что адаптер является синглтоном.
UpgradeAdapter — это модуль из angular 2, который используется для непрерывного обновления мира angular 1 до angular 2 и взаимодействия между ними. С помощью адаптера обновления мы можем не только обновить директивы, провайдеры и т. д. angular 1, но и понизить версию компонентов и сервисов angular 2 для использования в angular 1.
main.js содержит в импорте помимо общих требований ng2 также наш первый компонент ng2 SettingsAbout. После этого регистрируем провайдеров. Поскольку нам нужна наша служба аутентификации ng2 для аутентификации и авторизации, мы обновили службу AuthService ng1, просто позвонив
upgrade.upgradeNg1Provider('AuthService');
и наш компонент SettingsAbout ng2 мы также очень просто понизили.
angular.module('app.hmc.settings').directive('settingsAbout', <angular.IDirectiveFactory>upgrade.downgradeNg2Component(SettingsAbout));
Конец файла загружает нашу интегрированную систему ng1-ng2.
upgrade.bootstrap(document.body, ['app']);
SettingsAbout является обычным компонентом ng2 и использует ng1 AuthService, обновленный до ng2; никакой магии.
import {Component, Inject} from '@angular/core'; import {Http, Response} from '@angular/http'; import {Observable} from 'rxjs/Observable'; import {TranslateService, TranslatePipe} from 'ng2-translate'; @Component({ selector: 'settings-about', templateUrl: 'app-ng2/app/settings/about/about.html', pipes: [TranslatePipe] }) export class SettingsAbout { constructor(private http: Http, @Inject('AuthService') private authService: any, private translateService: TranslateService) { translateService.setDefaultLang('en'); translateService.use(language); this.getAboutInfo(); ... }; private getAboutInfo() { ... }; ... }
Когда у нас будет готовый компонент ng2 SettingsAbout, мы можем использовать его в качестве директивы для элемента ng1. В приведенном ниже примере мы используем подход взаимодействия компонентов ng1.5 с ui-router. Но вместо компонента ng1.5 мы используем компонент ng2 пониженной версии.
$stateProvider .state('app.settings.about', { url: '/About', data: { authorizedRoles: ... }, views: { '[email protected]': { template: '<settings-about />' } } });
Итак, теперь у нас есть первый компонент ng2, используемый внутри проекта ng1, и вы можете по тому же шаблону расширить это взаимодействие.
Пожалуйста, продолжайте с Преобразование Angular 2, система построения.