Skip to content

Commit

Permalink
feat(router): deprecate loadChildren:string (#30073)
Browse files Browse the repository at this point in the history
The proposed ES dynamic import() is now supported by the Angular CLI and the
larger toolchain. This renders the `loadChildren: string` API largely
redundant, as import() is far more natural, is less error-prone, and is
standards compliant. This commit deprecates the `string` form of
`loadChildren` in favor of dynamic import().

DEPRECATION:

When defining lazy-loaded route, Angular previously offered two options for
configuring the module to be loaded, both via the `loadChildren` parameter
of the route. Most Angular developers are familiar withthe `string` form of
this API. For example, the following route definition configures Angular to
load a `LazyModule` NgModule from `lazy-route/lazy.module.ts`:

```
[{
  path: 'lazy',
  loadChildren: 'lazy-route/lazy.module#LazyModule',
}]
```

This "magic string" configuration was previously necessary as there was
no dynamic module loading standard on the web. This has changed with the
pending standardization of dynamic `import()` expressions, which are now
supported in the Angular CLI and in web tooling in general. `import()`
offers a more natural and robust solution to dynamic module loading. The
above example can be rewritten to use dynamic `import()`:

```
[{
  path: 'lazy',
  loadChildren: () => import('./lazy-route/lazy.module').then(mod => mod.LazyModule),
}]
```

This form of lazy loading offers significant advantages in terms of:

* type checking via TypeScript
* simplicity of generated code
* future potential to run natively in supporting browsers
  (see: [caniuse: dynamic import()](https://caniuse.com/#feat=es6-module-dynamic-import))

As a result, Angular is deprecating the `loadChildren: string` syntax in
favor of ES dynamic `import()`. An automatic migration will run during
`ng upgrade` to convert your existing Angular code to the new syntax.

PR Close #30073
  • Loading branch information
alxhub authored and AndrewKushnir committed Apr 25, 2019
1 parent abcb2cf commit c61df39
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/core/src/linker/ng_module_factory_loader.ts
Expand Up @@ -17,6 +17,8 @@ import {NgModuleFactory} from './ng_module_factory';
* Used to load ng module factories.
*
* @publicApi
* @deprecated the `string` form of `loadChildren` is deprecated, and `NgModuleFactoryLoader` is
* part of its implementation. See `LoadChildren` for more details.
*/
export abstract class NgModuleFactoryLoader {
abstract load(path: string): Promise<NgModuleFactory<any>>;
Expand Down
Expand Up @@ -24,6 +24,8 @@ declare var System: any;
* token.
*
* @publicApi
* @deprecated the `string` form of `loadChildren` is deprecated, and `SystemJsNgModuleLoaderConfig`
* is part of its implementation. See `LoadChildren` for more details.
*/
export abstract class SystemJsNgModuleLoaderConfig {
/**
Expand All @@ -47,6 +49,8 @@ const DEFAULT_CONFIG: SystemJsNgModuleLoaderConfig = {
/**
* NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory
* @publicApi
* @deprecated the `string` form of `loadChildren` is deprecated, and `SystemJsNgModuleLoader` is
* part of its implementation. See `LoadChildren` for more details.
*/
@Injectable()
export class SystemJsNgModuleLoader implements NgModuleFactoryLoader {
Expand Down
28 changes: 27 additions & 1 deletion packages/router/src/config.ts
Expand Up @@ -93,6 +93,18 @@ export type ResolveData = {
/**
*
* A function that is called to resolve a collection of lazy-loaded routes.
*
* Often this function will be implemented using an ES dynamic `import()` expression. For example:
*
* ```
* [{
* path: 'lazy',
* loadChildren: () => import('./lazy-route/lazy.module').then(mod => mod.LazyModule),
* }];
* ```
*
* This function _must_ match the form above: an arrow function of the form
* `() => import('...').then(mod => mod.MODULE)`.
*
* @see `Route#loadChildren`.
* @publicApi
Expand All @@ -105,10 +117,24 @@ export type LoadChildrenCallback = () => Type<any>| NgModuleFactory<any>| Observ
* A string of the form `path/to/file#exportName` that acts as a URL for a set of routes to load,
* or a function that returns such a set.
*
* The string form of `LoadChildren` is deprecated (see `DeprecatedLoadChildren`). The function
* form (`LoadChildrenCallback`) should be used instead.
*
* @see `Route#loadChildren`.
* @publicApi
*/
export type LoadChildren = string | LoadChildrenCallback;
export type LoadChildren = LoadChildrenCallback | DeprecatedLoadChildren;

/**
* A string of the form `path/to/file#exportName` that acts as a URL for a set of routes to load.
*
* @see `Route#loadChildren`
* @publicApi
* @deprecated the `string` form of `loadChildren` is deprecated in favor of the proposed ES dynamic
* `import()` expression, which offers a more natural and standards-based mechanism to dynamically
* load an ES module at runtime.
*/
export type DeprecatedLoadChildren = string;

/**
*
Expand Down
2 changes: 1 addition & 1 deletion packages/router/src/index.ts
Expand Up @@ -7,7 +7,7 @@
*/


export {Data, LoadChildren, LoadChildrenCallback, ResolveData, Route, Routes, RunGuardsAndResolvers, UrlMatchResult, UrlMatcher} from './config';
export {Data, DeprecatedLoadChildren, LoadChildren, LoadChildrenCallback, ResolveData, Route, Routes, RunGuardsAndResolvers, UrlMatchResult, UrlMatcher} from './config';
export {RouterLink, RouterLinkWithHref} from './directives/router_link';
export {RouterLinkActive} from './directives/router_link_active';
export {RouterOutlet} from './directives/router_outlet';
Expand Down
3 changes: 3 additions & 0 deletions tools/public_api_guard/core/core.d.ts
Expand Up @@ -586,6 +586,7 @@ export declare abstract class NgModuleFactory<T> {
abstract create(parentInjector: Injector | null): NgModuleRef<T>;
}

/** @deprecated */
export declare abstract class NgModuleFactoryLoader {
abstract load(path: string): Promise<NgModuleFactory<any>>;
}
Expand Down Expand Up @@ -1297,11 +1298,13 @@ export interface SkipSelfDecorator {

export declare type StaticProvider = ValueProvider | ExistingProvider | StaticClassProvider | ConstructorProvider | FactoryProvider | any[];

/** @deprecated */
export declare class SystemJsNgModuleLoader implements NgModuleFactoryLoader {
constructor(_compiler: Compiler, config?: SystemJsNgModuleLoaderConfig);
load(path: string): Promise<NgModuleFactory<any>>;
}

/** @deprecated */
export declare abstract class SystemJsNgModuleLoaderConfig {
factoryPathPrefix: string;
factoryPathSuffix: string;
Expand Down
5 changes: 4 additions & 1 deletion tools/public_api_guard/router/router.d.ts
Expand Up @@ -101,6 +101,9 @@ export declare class DefaultUrlSerializer implements UrlSerializer {
serialize(tree: UrlTree): string;
}

/** @deprecated */
export declare type DeprecatedLoadChildren = string;

export declare type DetachedRouteHandle = {};

export declare type Event = RouterEvent | RouteConfigLoadStart | RouteConfigLoadEnd | ChildActivationStart | ChildActivationEnd | ActivationStart | ActivationEnd | Scroll;
Expand Down Expand Up @@ -145,7 +148,7 @@ export declare class GuardsCheckStart extends RouterEvent {
toString(): string;
}

export declare type LoadChildren = string | LoadChildrenCallback;
export declare type LoadChildren = LoadChildrenCallback | DeprecatedLoadChildren;

export declare type LoadChildrenCallback = () => Type<any> | NgModuleFactory<any> | Observable<Type<any>> | Promise<NgModuleFactory<any> | Type<any> | any>;

Expand Down

0 comments on commit c61df39

Please sign in to comment.