【译】Angular 5 新特性
Build Optimizer (构建优化)
从5.0.0开始,使用CLI创建的生产构建将默认应用于构建优化器。
构建优化器是我们的CLI中包含的一个工具,可以使用我们对Angular应用程序的语义理解来使您的软件包更小。
构建优化器有两个主要任务:
首先,我们可以将应用程序的部分标记为pure,这样可以改善现有工具提供的树状抖动,从而删除不需要的应用程序的其他部分。
构建优化器所做的第二件事是从应用程序的运行时代码中删除Angular装饰器。装饰器被编译器使用,在运行时不需要,并且可以被删除。这些工作都减少了JavaScript包的大小,并增加了应用程序的启动速度。
Angular Universal State Transfer API and DOM Support (Angular Universal 支持状态迁移 和 DOM)
现在,您可以更轻松地在应用程序的服务器端和客户端版本之间共享应用程序状态。
Angular Universal 是一个致力于帮助开发人员执行NG应用程序的服务器端呈现(SSR)的项目。通过在服务器上呈现您的角度应用程序,然后在生成的HTML上启动,您可以添加对不支持JavaScript的抓取器和爬虫程序的支持,并且您可以增加应用程序的性能。
在5.0.0中,团队增加了ServerTransferStateModule 模块和 相应的BrowserTransferStateModule模块。这个模块允许您使用平台服务器生成信息,然后将其传输到客户端,这样就不需要重新生成这些信息。这对于诸如当您的应用程序通过HTTP获取数据的情况非常有用。通过将状态从服务器转移,这意味着开发人员无需在应用程序向客户端发送第二个HTTP请求。在接下来的几周内,关于状态转移的文件将会发布。
另一个从Angular Universal团队的变化是将Domino添加到平台服务器。Domino意味着我们在服务器端环境中支持更多的DOM操作,提高了对第三方JS和组件库的支持,而这些库并不是服务器端感知的。
Compiler Improvements (编译优化)
我们改进了angular编译器以支持增量编译。这提供了更快的重新构建,特别是对于生产构建和使用AOT构建。我们还向我们的装饰器添加了一些特性,并通过删除空白来实现更小的bundle。
TypeScript Transforms
在底层,Angular编译器现在作为一个TypeScript变换运行,使得增量重建更快。 TypeScript Transforms是作为TypeScript 2.3的一部分引入的一个新功能,它允许我们钩入标准的TypeScript编译管道。
您可以通过在打开的AOT标志上运行 ng serve 来利用此功能。
ng serve --aot
我们建议大家试试看。 这将在CLI的将来版本中成为默认值。 有超过一千个组件的项目有一些已知的速度问题。 我们希望确保所有尺寸的项目都能体验到这些改进。
当执行(https://angular.io)的增量AOT构建时,新的编译器管道节省了95%的构建时间(从我们的开发机器上的40秒到少于2秒)。
我们的目标是使AOT编译速度足够快,以便开发人员可以使用它进行开发,从而消除开发人员在第一次尝试生产时遇到的差异。该团队已经完成了它的2秒增量的AOT重建性能目标,并且将在未来的CLI版本中默认使用AOT。
作为转换过程的一部分,我们不再需要genDir,并且outDir已经变为:现在我们总是在node_modules中为包发送生成的文件。
Preserve Whitespace (保留空格)
以前模板中的制表符、换行符和空格都是由编译器很老实地重新创建并包含在您的构建中。您现在可以选择是否保留来自组件和应用程序的空白。
您可以将其指定为每个组件装饰器的一部分,当前默认为true。
@Component({
templateUrl: 'about.component.html',
preserveWhitespaces: false
}
export class AboutComponent {}
或者您可以在tsconfig.json中将其应用范围广泛指定,当前默认值为true。
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"angularCompilerOptions": {
"preserveWhitespaces": false
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}
通常,组件级规范将覆盖应用范围的规范。在未来,团队希望默认为false,以便为开发人员默认节省空间。不要担心你的 pre 标签,这些都是智能处理的。
Read more about preserveWhitespaces on our docs site.
Improved Decorator Support(改进的装饰器支持)
我们现在支持lambdas装饰器中的表达式降低以及对象文字中的useValue,useFactory和数据的值。 这允许您使用只能在运行时在装饰器中计算降低的表达式的值。
您现在可以使用lambda而不是命名函数,这意味着您可以执行代码而不影响您的d.ts或您的公共API。
Component({
provider: [{provide: SOME_TOKEN, useFactory: () => null}]
})
export class MyClass {}
我们也将降低表达式作为useValue的一部分。
Component({
provider: [{provide: SOME_TOKEN, useValue: SomeEnum.OK}]
})
export class MyClass {}
Internationalized Number, Date, and Currency Pipes
我们已经建立了新的数字,日期和货币管道,从而提高浏览器的标准化水平,并消除了对i18n聚合物填充物的需求。
在Angular中,我们依靠浏览器使用浏览器i18n API提供数字,日期和货币格式。 这导致大多数开发人员需要一个polyfill,意味着用户在浏览器之间看到不一致的结果,我们收到了常见格式(如货币管道)与开箱人期望不符的评论。
在5.0.0中,我们更新了管道以使用我们自己的实现,依靠CLDR为您想要支持的任何区域设置提供广泛的区域设置支持和配置。 我们制作了一个比较v4和v5之间管道行为的文件。
如果您还没有准备好使用新的管道,您可以导入DeprecatedI18NPipesModule
以访问旧的行为。
Read more about the changes to our i18n pipes in the changelog
Replace the ReflectiveInjector with StaticInjector
为了清除更多的polyfill,我们已经用StaticInjector替换了ReflectiveInjector。该注射器不再需要Reflect polyfill,减少了大多数开发人员的应用程序大小。
Before
ReflectiveInjector.resolveAndCreate(providers);
After
Injector.create(providers);
Zone speed improvements
默认情况下,我们已经使区域更快,并且我们已经可以完全绕过区域来实现面向性能的应用程序。
为了绕过区域,用'noop'引导你的应用程序作为你的ngZone。
platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'}).then( ref => {} );
For a full example, take a look the example ng-component-state project.
exportAs
我们已经为您的组件/指令添加了多个名称的支持。 这对于帮助您的用户进行迁移而不会发生变化非常有用。 通过导出具有多个名称的指令,您可以在Angular microsyntax中创建新名称,而不会破坏现有代码。 这已被用作角色材料项目的前缀迁移的一部分,也可以帮助其他组件作者。
@Component({
moduleId: module.id,
selector: 'a[mat-button], a[mat-raised-button], a[mat-icon-button], a[mat-fab], a[mat-mini-fab]',
exportAs: 'matButton, matAnchor',
.
.
.
}
HttpClient
在版本4.3中,我们以@ angular / common的形式发布了HttpClient,作为一种更小,更轻松,更强大的方式,可以在Angular中进行Web请求。 新的HttpClient得到了开发人员的一致好评,因此我们现在正在为所有应用程序推荐HttpClient,并弃用了之前的@ angular / http库。
要更新到HttpClient,您需要将HttpModule 替换为 HttpClientModule 从每个模块中的@ angular / common / http,注入HttpClient服务,并删除任何映射(res => res.json())调用 不再需要。
CLI v1.5
从Angular CLI的v1.5开始,我们添加了对Angular v5.0.0的支持,默认情况下将生成v5项目。
有了这个次要版本,我们默认启用了构建优化器,因此开发人员可以从更小的捆绑中获益。
我们还在更新我们使用.tsconfig文件以更严格地遵循TypeScript标准的方式。 以前,如果我们检测到一个延迟加载的路由,并且手动指定了一个文件列表或包含在您的tsconfig.json中,我们将自动添加这些路由,但是我们现在遵循TypeScript规范,并且更长时间地执行此操作。 默认情况下,CLI配置没有文件或包含部分的TypeScript,因此大多数开发人员不会受到此影响。
Angular Forms adds updateOn Blur / Submit
你现在可以使用 ‘blur’ 或者 submit 事件验证数据或更新数据,
表单是许多应用程序中非常重要的一部分,如果您有任何类型的服务器端验证,或者您想要更少运行的验证或值更改触发的任何较重的进程,您现在可以控制验证和价值更改 在控制级别进行定时,或者为整个表单指定。
此外,您现在可以直接在options对象中指定asyncValidators,而不是将它指定为第三个参数。
Template Driven Forms
Before
<input name="firstName" ngModel>
After
<input name="firstName" ngModel [ngModelOptions]="{updateOn: 'blur'}">
Reactive Forms
Before
new FormGroup(value);
new FormControl(value, [], [myValidator])
After
new FormGroup(value, {updateOn: 'blur'}));
new FormControl(value, {updateOn: 'blur', asyncValidators: [myValidator]})
RxJS 5.5
我们已将我们对RxJS的使用更新到5.5.2或更高版本。 最近发布的RxJS完全授权开发人员使用称为“lettable运算符”的RxJS的新方法来避免先前导入机制的副作用。 这些新的运算符消除了导入运算符的以前的“补丁”方法存在的副作用和代码分割/树状抖动问题。
Instead of
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';
names = allUserData
.map(user => user.name)
.filter(name => name);
You can now
import { Observable } from 'rxjs/Observable';
import { map, filter } from 'rxjs/operators';
names = allUserData.pipe(
map(user => user.name),
filter(name => name),
);
此外,RxJS现在使用ECMAScript模块分发版本。 默认情况下,新的Angular CLI将拉入此版本,大大节省了捆绑包的大小。 但是,如果您不使用Angular CLI,您应该仍然指向新的发行版。 文档可以在lettable操作符文档的Build和Treeshaking部分找到。
New Router Lifecycle Events
我们已经向路由器添加了新的生命周期事件,允许开发人员从运行保护开始到完成激活后跟踪路由器的周期。 这些事件可以用于当孩子正在更新时或在测量卫兵和/或解析器的性能时在特定路由器插座上显示微调器。
新事件(顺序)是GuardsCheckStart
,ChildActivationStart
,ActivationStart
,GuardsCheckEnd
,ResolveStart
,ResolveEnd
,ActivationEnd
,ChildActivationEnd
。 使用这些事件启动/停止微调框的示例可能如下所示:
class MyComponent {
constructor(public router: Router, spinner: Spinner) {
router.events.subscribe(e => {
if (e instanceof ChildActivationStart) {
spinner.start(e.route);
} else if (e instanceof ChildActivationEnd) {
spinner.end(e.route);
}
});
}
}