docs: add section to upgrade guide on lazy loading AngularJS (#30541)
PR Close #30541
This commit is contained in:
parent
a96976e88f
commit
c9f5f3d802
|
@ -661,6 +661,7 @@
|
|||
/packages/common/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/upgrade.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/upgrade-lazy-load-ajs/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/upgrade-module/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/upgrade-phonecat-1-typescript/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { Component, OnInit, ElementRef } from '@angular/core';
|
||||
import { LazyLoaderService } from '../lazy-loader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-angular-js',
|
||||
template: '<div ng-view></div>'
|
||||
})
|
||||
export class AngularJSComponent implements OnInit {
|
||||
constructor(private lazyLoader: LazyLoaderService, private elRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.lazyLoader.load(this.elRef.nativeElement);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import * as angular from 'angular';
|
||||
import 'angular-route';
|
||||
|
||||
const appName = 'myApp';
|
||||
|
||||
angular.module(appName, [
|
||||
'ngRoute'
|
||||
])
|
||||
.config(['$routeProvider', '$locationProvider',
|
||||
function config($routeProvider, $locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
|
||||
$routeProvider.
|
||||
when('/users', {
|
||||
template: `
|
||||
<p>
|
||||
Users Page
|
||||
</p>
|
||||
`
|
||||
}).
|
||||
otherwise({
|
||||
template: ''
|
||||
});
|
||||
}]
|
||||
);
|
||||
|
||||
export function bootstrap(el: HTMLElement) {
|
||||
return angular.bootstrap(el, [appName]);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// #docplaster
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule, UrlSegment } from '@angular/router';
|
||||
import { AngularJSComponent } from './angular-js/angular-js.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { App404Component } from './app404/app404.component';
|
||||
|
||||
// Match any URL that starts with `users`
|
||||
// #docregion matcher
|
||||
export function isAngularJSUrl(url: UrlSegment[]) {
|
||||
return url.length > 0 && url[0].path.startsWith('users') ? ({consumed: url}) : null;
|
||||
}
|
||||
// #enddocregion matcher
|
||||
|
||||
export const routes: Routes = [
|
||||
// Routes rendered by Angular
|
||||
{ path: '', component: HomeComponent },
|
||||
|
||||
// AngularJS routes
|
||||
{ matcher: isAngularJSUrl, component: AngularJSComponent },
|
||||
|
||||
// Catch-all route
|
||||
{ path: '**', component: App404Component }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
|
@ -0,0 +1,9 @@
|
|||
Lazy Loading AngularJS
|
||||
|
||||
<nav>
|
||||
<a routerLink="/">Home</a>
|
||||
<a routerLink="/users">Users</a>
|
||||
<a routerLink="/notfound">404 Page</a>
|
||||
</nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
|
@ -0,0 +1,8 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent { }
|
|
@ -0,0 +1,25 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AngularJSComponent } from './angular-js/angular-js.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { App404Component } from './app404/app404.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
AngularJSComponent,
|
||||
HomeComponent,
|
||||
App404Component
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -0,0 +1,3 @@
|
|||
<p>
|
||||
Angular 404
|
||||
</p>
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-app404',
|
||||
templateUrl: './app404.component.html',
|
||||
styleUrls: ['./app404.component.css']
|
||||
})
|
||||
export class App404Component implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<p>
|
||||
Angular Home
|
||||
</p>
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.css']
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LazyLoaderService {
|
||||
bootstrapped = false;
|
||||
|
||||
load(el: HTMLElement): void {
|
||||
if (this.bootstrapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
import('./angularjs-app').then(app => {
|
||||
try {
|
||||
app.bootstrap(el);
|
||||
this.bootstrapped = true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>AngularJS Hybrid</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": [
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1,2].*"
|
||||
]
|
||||
}
|
|
@ -838,6 +838,72 @@ After this, the service is injectable anywhere in AngularJS code:
|
|||
<code-example path="upgrade-module/src/app/a-to-ajs-providers/hero-detail.component.ts" header="hero-detail.component.ts">
|
||||
</code-example>
|
||||
|
||||
## Lazy Loading AngularJS
|
||||
|
||||
When building applications, you want to ensure that only the required resources are loaded when necessary. Whether that be loading of assets or code, making sure everything that can be deferred until needed keeps your application running efficiently. This is especially true when running different frameworks in the same application.
|
||||
|
||||
[Lazy loading](guide/glossary#lazy-loading) is a technique that defers the loading of required assets and code resources until they are actually used. This reduces startup time and increases efficiency, especially when running different frameworks in the same application.
|
||||
|
||||
When migrating large applications from AngularJS to Angular using a hybrid approach, you want to migrate some of the most commonly used features first, and only use the less commonly used features if needed. Doing so helps you ensure that the application is still providing a seamless experience for your users while you are migrating.
|
||||
|
||||
In most environments where both Angular and AngularJS are used to render the application, both frameworks are loaded in the initial bundle being sent to the client. This results in both increased bundle size and possible reduced performance.
|
||||
|
||||
Overall application performance is affected in cases where the user stays on Angular-rendered pages because the AngularJS framework and application are still loaded and running, even if they are never accessed.
|
||||
|
||||
You can take steps to mitigate both bundle size and performance issues. By isolating your AngularJS app to a separate bundle, you can take advantage of [lazy loading](guide/glossary#lazy-loading) to load, bootstrap, and render the AngularJS application only when needed. This strategy reduces your initial bundle size, defers any potential impact from loading both frameworks until absolutely necessary, and keeps your application running as efficiently as possible.
|
||||
|
||||
The steps below show you how to do the following:
|
||||
|
||||
* Setup a callback function for your AngularJS bundle.
|
||||
* Create a service that lazy loads and bootstraps your AngularJS app.
|
||||
* Create a routable component for AngularJS content
|
||||
* Create a custom `matcher` function for AngularJS-specific URLs and configure the Angular `Router` with the custom matcher for AngularJS routes.
|
||||
|
||||
### Create a service to lazy load AngularJS
|
||||
|
||||
As of Angular version 8, lazy loading code can be accomplished simply by using the dynamic import syntax `import('...')`. In your application, you create a new service that uses dynamic imports to lazy load AngularJS.
|
||||
|
||||
<code-example path="upgrade-lazy-load-ajs/src/app/lazy-loader.service.ts" header="src/app/lazy-loader.service.ts">
|
||||
</code-example>
|
||||
|
||||
The service uses the `import()` method to load your bundled AngularJS application lazily. This decreases the initial bundle size of your application as you're not loading code your user doesn't need yet. You also need to provide a way to _bootstrap_ the application manually after it has been loaded. AngularJS provides a way to manually bootstrap an application using the [angular.bootstrap()](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method with a provided HTML element. Your AngularJS app should also expose a `bootstrap` method that bootstraps the AngularJS app.
|
||||
|
||||
<code-example path="upgrade-lazy-load-ajs/src/app/angularjs-app/index.ts" header="angularjs-app">
|
||||
</code-example>
|
||||
|
||||
Your AngularJS application is configured with only the routes it needs to render content. The remaining routes in your application are handled by the Angular Router. The exposed `bootstrap` method is called in your Angular app to bootstrap the AngularJS application after the bundle is loaded.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
**Note:** After AngularJS is loaded and bootstrapped, listeners such as those wired up in your route configuration will continue to listen for route changes. To ensure listeners are shut down when AngularJS isn't being displayed, configure an `otherwise` option with the [$routeProvider](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider) that renders an empty template. This assumes all other routes will be handled by Angular.
|
||||
|
||||
</div>
|
||||
|
||||
### Create a component to render AngularJS content
|
||||
|
||||
In your Angular application, you need a component as a placeholder for your AngularJS content. This component uses the service you create to load and bootstrap your AngularJS app after the component is initialized.
|
||||
|
||||
<code-example path="upgrade-lazy-load-ajs/src/app/angular-js/angular-js.component.ts" header="src/app/angular-js/angular-js.component.ts">
|
||||
</code-example>
|
||||
|
||||
When the Angular Router matches a route that uses AngularJS, the `AngularJSComponent` is rendered, and the content is rendered within the AngularJS [`ng-view`](https://docs.angularjs.org/api/ngRoute/directive/ngView) directive.
|
||||
|
||||
### Configure a custom route matcher for AngularJS routes
|
||||
|
||||
To configure the Angular Router, you must define a route for AngularJS URLs. To match those URLs, you add a route configuration that uses the `matcher` property. The `matcher` allows you to use custom pattern matching for URL paths. The Angular Router tries to match on more specific routes such as static and variable routes first. When it doesn't find a match, it then looks at custom matchers defined in your route configuration. If the custom matchers don't match a route, it then goes to catch-all routes, such as a 404 page.
|
||||
|
||||
The following example defines a custom matcher function for AngularJS routes.
|
||||
|
||||
<code-example path="upgrade-lazy-load-ajs/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="matcher">
|
||||
</code-example>
|
||||
|
||||
The following code adds a route object to your routing configuration using the `matcher` property and custom matcher, and the `component` property with `AngularJSComponent`.
|
||||
|
||||
<code-example path="upgrade-lazy-load-ajs/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts">
|
||||
</code-example>
|
||||
|
||||
When your application matches a route that needs AngularJS, the AngularJS app is loaded and bootstrapped, the AngularJS routes match the necessary URL to render their content, and your application continues to run with both AngularJS and Angular frameworks.
|
||||
|
||||
## Using the Unified Angular Location Service
|
||||
|
||||
In AngularJS, the [$location service](https://docs.angularjs.org/api/ng/service/$location) handles all routing configuration and navigation, encoding and decoding of URLS, redirects, and interactions with browser APIs. Angular uses its own underlying `Location` service for all of these tasks.
|
||||
|
|
Loading…
Reference in New Issue