fix(core): export inject() from @angular/core (#22389)

inject() supports the ngInjectableDef-based configuration of the injector
(otherwise known as tree-shakeable services). It was missing from the
exported API of @angular/core, this PR adds it.

The test added here is correct in theory, but may pass accidentally due
to the decorator side-effect replacing the inject() call at runtime. An
upcoming compiler PR will strip reified decorators from the output
entirely.

Fixes #22388

PR Close #22389
This commit is contained in:
Alex Rickabaugh
2018-02-23 09:04:55 -08:00
committed by Alex Eagle
parent 7d65356ae3
commit f8749bfb70
8 changed files with 123 additions and 7 deletions

View File

@ -0,0 +1,41 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Injectable, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
@Injectable()
export class NormalService {
}
@Component({
selector: 'dep-app',
template: '{{found}}',
})
export class AppComponent {
found: boolean;
constructor(service: ShakeableService) { this.found = !!service.normal; }
}
@NgModule({
imports: [
BrowserModule.withServerTransition({appId: 'id-app'}),
ServerModule,
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [NormalService],
})
export class DepAppModule {
}
@Injectable({scope: DepAppModule})
export class ShakeableService {
constructor(readonly normal: NormalService) {}
}

View File

@ -6,11 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Inject, InjectionToken, NgModule, forwardRef} from '@angular/core';
import {Component, Inject, Injectable, InjectionToken, NgModule, forwardRef, inject} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
export interface IService { readonly data: string; }
export interface IService { readonly dep: {readonly data: string;}; }
@NgModule({})
export class TokenModule {
@ -18,7 +18,7 @@ export class TokenModule {
export const TOKEN = new InjectionToken('test', {
scope: TokenModule,
factory: () => new Service(),
factory: () => new Service(inject(Dep)),
});
@ -28,7 +28,7 @@ export const TOKEN = new InjectionToken('test', {
})
export class AppComponent {
data: string;
constructor(@Inject(TOKEN) service: IService) { this.data = service.data; }
constructor(@Inject(TOKEN) service: IService) { this.data = service.dep.data; }
}
@NgModule({
@ -37,10 +37,18 @@ export class AppComponent {
ServerModule,
TokenModule,
],
providers: [forwardRef(() => Dep)],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class TokenAppModule {
}
export class Service { readonly data = 'fromToken'; }
@Injectable()
export class Dep {
readonly data = 'fromToken';
}
export class Service {
constructor(readonly dep: Dep) {}
}

View File

@ -9,6 +9,7 @@
import {enableProdMode} from '@angular/core';
import {renderModuleFactory} from '@angular/platform-server';
import {BasicAppModuleNgFactory} from 'app_built/src/basic.ngfactory';
import {DepAppModuleNgFactory} from 'app_built/src/dep.ngfactory';
import {HierarchyAppModuleNgFactory} from 'app_built/src/hierarchy.ngfactory';
import {RootAppModuleNgFactory} from 'app_built/src/root.ngfactory';
import {SelfAppModuleNgFactory} from 'app_built/src/self.ngfactory';
@ -66,4 +67,14 @@ describe('ngInjectableDef Bazel Integration', () => {
done();
});
});
it('can inject dependencies', done => {
renderModuleFactory(DepAppModuleNgFactory, {
document: '<dep-app></dep-app>',
url: '/',
}).then(html => {
expect(html).toMatch(/>true<\//);
done();
});
});
});