返回博客首页
← 所有文章

NativeScript for Angular 12 发布

2021年6月8日 — 作者:技术指导委员会 (TSC)

我们很高兴发布 NativeScript for Angular 12,因为它充满了更新,包括彻底改进的引擎。TSC 决定从整体上着手这个新的主要版本,从底层开始考虑 Angular 框架的所有最新进展。

"@nativescript/angular": "~12.0.0"

您期望使用的 package.json 版本的完整范围如下:

"dependencies": {
  "@angular/animations": "~12.0.0",
  "@angular/common": "~12.0.0",
  "@angular/compiler": "~12.0.0",
  "@angular/core": "~12.0.0",
  "@angular/forms": "~12.0.0",
  "@angular/platform-browser": "~12.0.0",
  "@angular/platform-browser-dynamic": "~12.0.0",
  "@angular/router": "~12.0.0",
  "@nativescript/angular": "~12.0.0"
  "@nativescript/core": "~8.0.0",
  "@nativescript/theme": "~3.0.0",
  "rxjs": "^6.6.0",  // you can use rxjs 7.x.x as well
  "zone.js": "~0.11.4"
},
"devDependencies": {
  "@angular/compiler-cli": "~12.0.0",
  "@nativescript/android": "8.0.0",
  "@nativescript/ios": "8.0.0",
  "@nativescript/types": "8.0.0",
  "@nativescript/webpack": "beta",
  "@ngtools/webpack": "~12.0.0",
  "typescript": "~4.2.0"
}

注意:请参阅下面的升级部分,因为您需要考虑此处提到的 polyfills.ts 文件。

简史

有些人可能不知道 NativeScript 与 Angular 的第一次集成是在很久以前写的。对 nativescript-angular(原始集成仓库)的第一次提交是在 2015年6月11日Hristo Deshev 完成的。它在当时使用了子模块,并且针对 2.0.0-alpha.26 编写!!

没错。第一个主要 Angular 重写的 alpha 版本,2.0。NativeScript for Angular 这些年来随着每个主要版本的发布而不断发展,但主要引擎和结构始终基于现代 Angular 的早期阶段。

我们非常感谢这些早期的贡献者,因为他们为这些年来的一些精彩发展铺平了道路。

我们喜欢使用 Angular,并认为是时候从一个全新的视角出发,考虑到所有最新的 Angular 功能了。

改进的引擎

新实现的核心旨在比以往任何时候都更加赋能开发者,让他们能够做出自己的决定并根据自己的需要自定义他们的应用。我们不再将 NativeScript 隐藏在 Angular 后面,而是提供了一组辅助工具,这些工具应该能让开发者在针对 NativeScript 平台进行 Angular 开发时感到轻松。

它也为 Angular 的 CDK 在集成中开始蓬勃发展奠定了基础,围绕模态对话框处理和其他细节提供了新的基于门户的 API。更多内容将在后续文章中介绍。

多功能启动选项

NativeScript Angular 应用中使用的当前引导方法已被设计为向后兼容,因此这对现有应用来说应该可以正常工作。

platformNativeScriptDynamic().bootstrapModule(AppModule);

我们开发了一种新的引导方法,它允许进行一些令人兴奋和动态的配置。我们将在几周后的后续博客文章中详细介绍这一点。我们鼓励大家在升级到 Angular 12 时切换他们的应用以使用此方法。

import { runNativeScriptAngularApp, platformNativeScript } from '@nativescript/angular';
import { AppModule } from './app/app.module';

runNativeScriptAngularApp({
  appModuleBootstrap: () => platformNativeScript().bootstrapModule(AppModule),
});

不过,让我们花点时间稍微扩展一下……

应用程序生命周期

NativeScript 有自己的生命周期,以前隐藏在 nativeScriptPlatformDynamic 后面。每个应用都有一个启动事件和一个退出事件。您的 Angular AppModule 始终在原生 iOS 和 Android 应用启动时引导,并在应用退出时销毁。虽然您的应用在许多方面可能仍在后台运行,但不能保证您的 AppModule 在某些情况下会处于活动状态。这个新的 API 使情况更加清晰。

import {
  runNativeScriptAngularApp,
  platformNativeScript // this is the actual platform used to boot a module into a NativeScript View
} from '@nativescript/angular';
import { AppModule } from './app/app.module';
import { LoadingModule } from './app/loading.module';

// The entry point.
// This signals in your code that from now on we're running the app.
// Nothing is bootstrapped imperatively. Everything now comes from generator functions.
runNativeScriptAngularApp({
  // This is an event implementation.
  // Every time we need the main module bootstrapped, you're required to resolve a NgModuleRef via a Promise, which is what `bootstrapModule(...)` does.

  // Booting your AppModule.
  appModuleBootstrap: (reason: string) => platformNativeScript().bootstrapModule(AppModule),
  // Note: The `reason: string` argument should be either 'applaunch' or 'hotreload'.

  // 🌟 Amazing new abilities here. 
  // Bootstrapping a module that's not the AppModule!?
  // For the async APP_INITIALIZER users out there, you can now bootstrap a small (synchronous) module to show until your main AppModule is loaded.
  // This allows you to better isolate an entirely encapsulated rich launch experience (which is only experienced once in your app's lifecycle by your users)
  loadingModule: (reason: string) => platformNativeScript().bootstrapModule(LoadingModule),

  // A feature from the previous versions that makes a return here, for example:
  // launchView: () => {
  //   const grid = new GridLayout();
  //   grid.backgroundColor = 'yellow';
  //   return grid;
  // }
});

这个新函数将处理启动和退出事件,并在需要时要求您引导主应用。它会在应用退出时销毁模块,就像它一直做的那样,但现在您可以连接自己的逻辑,因为您是传递 NgModuleRef 的人。由于我们还公开了整个平台,因此您可以引导的模块数量没有限制。

模块将始终将其自身引导到一个“虚拟”NativeScript 视图中,@nativescript/angular 将其作为应用程序的根视图。通过使用标记 APP_ROOT_VIEW,还可以让模块在任何视图中引导,这与 Web Components 的工作方式非常相似!我们将在以后的博客文章中讨论如何提供您自己的根视图处理逻辑。

新 API 最令人兴奋的一点是,您不再局限于仅引导基于 UI 的模块(例如,您应用的整个 UI 的主要 AppModule)。没有什么可以阻止您引导自己的 BackgroundModule,它不引导任何组件,但允许您在后台服务中使用其注入器来获取诸如 HttpClient 之类的好处!为了在不同的模块之间进行协调,我们建议使用 Angular 自身的 providedIn: 'platform',这将允许在整个平台(及其模块)中共享单例服务!但请注意,此平台仅在 HMR 期间销毁,您不能在其中使用依赖于模块提供程序的服务(因此没有 HttpClient!)。您可以在 Angular 文档 中找到更多信息。

Zone.js

Zone.js 也进行了重大改进。我们不再提供自定义的 Zone.js 实现。我们之前依赖于插件开发者和 @nativescript/core 提供包装在 ZoneCallback 中的回调,以避免出现视图在事件后不会更新的烦人问题,因此许多开发者不得不将这些回调包装到 ngZone.run 中。

我们现在按原样使用 zone.js 包,并为 NativeScript API 提供我们自己的补丁。这意味着大多数以前需要 ngZone.run 的插件现在可能都可以安全地使用了。如果您是插件开发者,并且没有使用 Observable(或者如果您覆盖了 ObservableaddEventListener)来处理事件和回调,我们还为您提供了一个 API 来修补 Angular 集成中的自定义事件回调。更多内容也将发布在后续文章中。

Angular 团队在其 路线图 中添加了他们正在研究使 Zone.js 可选退出的内容,我们也已经在努力确保您可以在时机成熟时无 Zone 使用 NativeScript!

改进的 HMR

我们重新审视了 HMR 集成,并找到了一些改进它的方法,您应该会在整体上体验到更好的 HMR。

关于 iOS,需要注意几件事。Android 在这方面没有问题。

  • iOS

    • 如果您使用 Ctrl+C 停止命令行(使用 ns runns debug 等),并且应用仍然在模拟器或设备上运行(经常发生) - 您很可能需要在模拟器或设备上强制退出应用,然后才能再次运行 HMR,以便可能再次启动,所以请记住这一点。

控制您自己的 polyfills

每个 NativeScript Angular 12 应用现在都像 Angular Web 应用一样控制您自己的 polyfills。

使用 ns create myapp --ng 创建新项目时,您会找到一个 ./src/polyfills.ts 文件。这些 polyfills 也可以添加到您正在更新的任何现有项目中;有关升级的更多信息请参见下文。

内容至少必须包含以下内容:

/**
 * NativeScript Polyfills
 */

// Install @nativescript/core polyfills (XHR, setTimeout, requestAnimationFrame)
import '@nativescript/core/globals';
// Install @nativescript/angular specific polyfills
import '@nativescript/angular/polyfills';

/**
 * Zone.js and patches
 */
// Add pre-zone.js patches needed for the NativeScript platform
import '@nativescript/zone-js/dist/pre-zone-polyfills';

// Zone JS is required by default for Angular itself
import 'zone.js';

// Add NativeScript specific Zone JS patches
import '@nativescript/zone-js';

这为您提供了与 Angular Web 应用相同的强大功能,可以控制在应用中填充的内容。对于大多数用户来说,您不必考虑此文件,但如果您需要,现在就可以掌握这种能力了。

升级

  1. 如果您要升级应用,可以将 package.json 版本更新到以下版本:
"dependencies": {
  "@angular/animations": "~12.0.0",
  "@angular/common": "~12.0.0",
  "@angular/compiler": "~12.0.0",
  "@angular/core": "~12.0.0",
  "@angular/forms": "~12.0.0",
  "@angular/platform-browser": "~12.0.0",
  "@angular/platform-browser-dynamic": "~12.0.0",
  "@angular/router": "~12.0.0",
  "@nativescript/angular": "~12.0.0"
  "@nativescript/core": "~8.0.0",
  "@nativescript/theme": "~3.0.0",
  "rxjs": "^6.6.0",  // you can use rxjs 7.x.x as well
  "zone.js": "~0.11.4"
},
"devDependencies": {
  "@angular/compiler-cli": "~12.0.0",
  "@nativescript/android": "8.0.0",
  "@nativescript/ios": "8.0.0",
  "@nativescript/types": "8.0.0",
  "@nativescript/webpack": "beta",
  "@ngtools/webpack": "~12.0.0",
  "typescript": "~4.2.0"
}
  1. 如上所述,您还需要创建一个包含以下内容的 ./src/polyfills.ts 文件:
/**
 * NativeScript Polyfills
 */

// Install @nativescript/core polyfills (XHR, setTimeout, requestAnimationFrame)
import '@nativescript/core/globals';
// Install @nativescript/angular specific polyfills
import '@nativescript/angular/polyfills';

/**
 * Zone.js and patches
 */
// Add pre-zone.js patches needed for the NativeScript platform
import '@nativescript/zone-js/dist/pre-zone-polyfills';

// Zone JS is required by default for Angular itself
import 'zone.js';

// Add NativeScript specific Zone JS patches
import '@nativescript/zone-js';
  1. 现在修改您的 tsconfig.json 以包含以下修改(注意 polyfills 的提及):
"files": ["./src/main.ts", "./references.d.ts", "./src/polyfills.ts"],
  1. 最后,您可以更新您的 ./src/main.ts 以使用新的多功能引导 API:
import { platformNativeScript, runNativeScriptAngularApp } from '@nativescript/angular';

import { AppModule } from './app/app.module';

runNativeScriptAngularApp({
	appModuleBootstrap: () => platformNativeScript().bootstrapModule(AppModule)
});

现在 ns clean 并运行它。

Angular 12 测试

我们已弃用所有以前的 nsTestBed 辅助工具!它们现在不再需要了,因为我们实现了 whenRenderingDone,并且现在使用 Angular 自身的夹具处理。它们仍然有效,但在使用它们时可能会收到一些警告消息。以下是您的测试现在应该如何编写:

  • tests-main.ts(您的第一个测试入口点)
import '@nativescript/core/globals';
import '@nativescript/angular/polyfills';
import '@nativescript/zone-js/dist/pre-zone-polyfills';
import 'zone.js';
import '@nativescript/zone-js';
import 'zone.js/testing';
import { TestBed } from '@angular/core/testing';
import { NativeScriptTestingModule } from '@nativescript/angular/testing';
import { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

TestBed.initTestEnvironment(NativeScriptTestingModule, platformBrowserDynamicTesting());
  • your.spec.ts
describe('your spec', () => {
  beforeEach(() => TestBed.configureTestingModule({
      declarations: [YourComponent],
      imports: [],
      providers: [],
    }).compileComponents());
  it('creates', () => {
    const fixture = TestBed.createComponent(YourComponent);
    fixture.detectChanges();
    expect(fixture).toBeDefined();
    expect(fixture.componentRef.instance).toBeDefined();
  });
  it('renders', waitForAsync(async () => {
    const fixture = TestBed.createComponent(YourComponent);
    fixture.detectChanges();
    await fixture.whenRenderingDone();
    // do other tests with native views
  }));
});

Angular Router & 导航说明

我们提供与您的应用今天使用的 API 相同的 API,用于 Angular Router 集成,例如 page-router-outletRouterExtensions 等。

我们预计您的应用过去可能遇到的一些特定路由问题不会通过此更新得到解决,但是我们希望为您提供今天更新到 Angular 12 的能力,并且应该像您习惯的那样工作。

除了此版本之外,我们还在开发一个新的导航 API,并将其与改进的集成结合使用。今年夏天,我们将引入一种方法,让您的应用使用新的 API 来改进路由。

即将推出

NativeScript 8 和 Webpack 5 带来了许多令人兴奋的新功能,使这一切成为可能,但我们还没有完成。作为对未来的预先了解,我们已经设法使 NativeScript 中的 NGRX 与标准 Redux Devtools 良好地协同工作,并且我们期待完成细节,以便我们可以使使用完整的 NGRX 状态管理功能开发 Angular 应用变得更加容易!开发者体验与用户体验一样重要,因此我们希望继续改进您使用 NativeScript for Angular 的方式。

新的易于维护的源代码仓库

如果您好奇地想要了解改进的集成并为更新应用时可能发现的任何内容做出贡献,我们绝对欢迎贡献者。

https://github.com/NativeScript/angular

它现在像许多 NativeScript 仓库一样组织,使用 Nrwl 的 Nx

为 Angular 干杯!

感谢 Angular 团队提供了一个能够进行大量令人着迷的跨平台工作的通用框架。