ngUpgrade入门:从AngularJS到Angular

Angular (2+) is here, and we're all super excited about it. For some of us, though, we're still maintaining large AngularJS (1.x) codebases at work. How do we start migrating our application to the new version of Angular -- especially if we can't afford to take six months away from a feature development for a complete rewrite?

Angular(2+)在这里,我们都对此感到非常兴奋。 但是,对于我们中的某些人,我们仍然在工作中维护大型AngularJS(1.x)代码库。 我们如何开始将应用程序迁移到新版本的Angular中-尤其是如果我们不能花6个月的时间进行功能重写以进行完全重写时?

That's where the ngUpgrade library comes in. ngUpgrade is the official tool to allow you to migrate your application litle by little. It lets Angular run side-by-side along with your AngularJS code for as long as you need to slowly upgrade.

这就是ngUpgrade库的来源。ngUpgrade是允许您少量迁移应用程序文档的官方工具。 只要您需要缓慢升级,它就可以使Angular与AngularJS代码并排运行。

In this guide, you're going to learn how to install and set up ngUpgrade and Angular. Then, you'll learn the basics of rewriting components. Let's dig in!

在本指南中,您将学习如何安装和设置ngUpgrade和Angular。 然后,您将学习重写组件的基础知识。 让我们开始吧!

(P.S. If the length of this guide freaks you out, don't worry. I've built a step-by-step, super detailed video program called Upgrading AngularJS that covers all of this in detail.)

(PS:如果本指南的篇幅太吓人了,请放心。我已经构建了一个名为Upgradeing AngularJS的分步,超详细的视频程序,其中详细介绍了所有这些。)

<a href="https://www\.upgradingangularjs\.com?ref=scotch\.io"\>

</a>

<a href=" https://www\.upgradingangularjs\.com?ref=scotch\.io"\>

我们的出发点 ( Our Starting Point )

To get started with ngUpgrade, your application needs to meet a few prerequisites:

要开始使用ngUpgrade,您的应用程序需要满足一些先决条件:

  1. Code organized by feature (not by type) and every file contains only one item (like a directive or service)

    代码按功能(不是按类型)组织,并且每个文件仅包含一项(如指令或服务)
  2. TypeScript set up

    TypeScript设置
  3. Using a module bundler (most people use Webpack)

    使用模块捆绑器(大多数人使用Webpack)
  4. Using AngularJS 1.5+ with controllers replaced by components

    将AngularJS 1.5+与控制器替换为组件一起使用

(If you're lost on any of that, we cover it all in parts 1 and 2 of the course.)

(如果您因任何一个而迷失了方向,我们将在本课程 1部分和第2部分中介绍所有内容。)

For now, though, take a minute to clone or fork the course sample project on GitHub (don’t forget to run npm install). Checkout this commit to see our starting point:

不过,现在就花点时间在GitHub上克隆或创建该课程示例项目 (不要忘记运行npm install )。 查看此提交以查看我们的起点:

git checkout fdfcf0bc3b812fa01063fbe98e18f3c2f4bcc5b4

git checkout fdfcf0bc3b812fa01063fbe98e18f3c2f4bcc5b4

We've got a simple Order System project that we can use to work through ngUpgrade. Starting at this commit, our application meets all of the above criteria. We're using component architecture, TypeScript, and Webpack (we've even got builds for both development and production).

我们有一个简单的Order System项目,可用于完成ngUpgrade。 从此提交开始,我们的应用程序满足所有以上条件。 我们正在使用组件体系结构,TypeScript和Webpack(我们甚至拥有用于开发和生产的构建)。

等一下,为什么我们不使用CLI? (Wait, why aren't we using the CLI?)

I love the Angular CLI as much as the next developer, but in many large AngularJS apps, you just can't move everything into a brand new Git repository and wipe out years of history. You also might be using a different app structure than the CLI. If you can use the CLI for your upgrade, fantastic! But for the rest of you, I'll teach you the manual setup here so that you can have complete control over your upgrade.

我和下一个开发人员一样喜欢Angular CLI,但是在许多大型AngularJS应用程序中,您无法将所有内容移至全新的Git存储库中并抹去多年的历史。 您可能还使用了与CLI不同的应用程序结构。 如果您可以使用CLI进行升级,那就太好了! 但是,对于其余的人,我将在这里教您手动设置,以便您可以完全控制升级。

Let's get started.

让我们开始吧。

安装Angular和ngUpgrade ( Installing Angular & ngUpgrade )

安装依赖项 (Installing Dependencies)

We're ready to install Angular, ngUpgrade, and all of the peer dependencies. In the sample project, go ahead and update your package.json dependencies array so it looks like this:

我们准备安装Angular,ngUpgrade和所有对等依赖项。 在示例项目中,继续并更新package.json依赖项数组,如下所示:

"dependencies": {
    "@angular/common": "^5.2.5",
    "@angular/compiler": "^5.2.5",
    "@angular/core": "^5.2.5",
    "@angular/forms": "^5.2.5",
    "@angular/platform-browser": "^5.2.5",
    "@angular/platform-browser-dynamic": "^5.2.5",
    "@angular/router": "^5.2.5",
    "@angular/upgrade": "^5.2.5",
    "angular": "1.6.6",
    "angular-route": "1.6.6",
    "bootstrap": "3.3.7",
    "core-js": "^2.5.3",
    "jquery": "^2.2.4",
    "lodash": "4.17.4",
    "moment": "~2.17.1",
    "reflect-metadata": "^0.1.12",
    "rxjs": "^5.5.6",
    "zone.js": "^0.8.20"
}

(We're going to use Angular 5 in this series, even though the sample project uses version 4. Don't sweat it - the steps are identical.)

(即使示例项目使用版本4,我们仍将在本系列中使用Angular5。不要费力-步骤相同。)

We could put all of these packages in one long command in the terminal with the save flag, but I want to take the time to explain to you what each of these packages are.

我们可以使用save标志在终端中将所有这些软件包放入一个长命令中,但是我想花时间向您解释这些软件包中的每一个。

First are our libraries under the @angular namespace:

首先是我们在@angular命名空间下的库:

  • @angular/common: These are the commonly needed services, pipes, and directives for Angular. This package also contains the new HttpClient as of version 4.3, so we no longer need @angular/http.

    @angular/common :这些是Angular常用的服务,管道和指令。 此软件包还包含4.3版以后的新HttpClient ,因此我们不再需要@angular/http
  • @angular/compiler: This is Angular's template compiler. It takes the templates and converts them into the code that makes your application run and render. You almost never need to actually interact with it.

    @angular/compiler :这是Angular的模板编译器。 它采用模板并将其转换为使您的应用程序运行和呈现的代码。 您几乎不需要真正与之互动。
  • @angular/core: These are the critical runtime parts of Angular needed by every application. This has things like the metadata decorators (e.g. Component, Injectable), all the dependency injection stuff, and the component life-cycle hooks like OnInit.

    @angular/core :这些是每个应用程序所需的Angular关键运行时部分。 它具有诸如元数据装饰器(例如ComponentInjectable ),所有依赖项注入之类的东西,以及诸如OnInit类的组件生命周期挂钩。
  • @angular/forms: This is just everything we need with forms, whether template or reactive.

    @angular/forms :这就是表单所需的一切,无论是模板还是React式。
  • @angular/platform-browser: This is everything dom and browser related, especially pieces that help render the dom. This is the package that includes bootstrapStatic, which is the method that we use for bootstrapping our applications for production builds.

    @angular/platform-browser :这是dom和浏览器相关的所有内容,尤其是有助于渲染dom的片段。 这是一个包含bootstrapStatic的软件包,这是我们用于引导应用程序进行生产构建的方法。
  • @angular/platform-browser-dynamic: This package includes providers and another bootstrap method for applications that compile templates on the client. This is the package that we use for bootstrapping during development and we'll cover switching between the two in another video.

    @angular/platform-browser-dynamic :此软件包包括提供程序和用于在客户端上编译模板的应用程序的另一种引导方法。 这是在开发过程中用于引导的软件包,我们将在另一个视频中介绍两者之间的切换。
  • @angular/router: As you might guess, this is just the router for Angular.

    @angular/router :您可能会猜到,这只是Angular的路由器。
  • @angular/upgrade: This is the ngUpgrade library, which allows us to migrate our AngularJS application to Angular.

    @angular/upgrade :这是ngUpgrade库,它使我们可以将AngularJS应用程序迁移到Angular。

After all of our Angular packages come our polyfill packages that are dependencies of Angular:

在我们所有的Angular软件包出现之后,我们的polyfill软件包即为Angular的依赖项:

  • core-js patches the global context or the window with certain features of ES6 or ES2015.

    core-js使用ES6或ES2015的某些功能修补全局上下文或窗口。
  • reflect-metadata is a polyfill library for the annotations that Angular uses in its classes.

    reflect-metadata是Angular在其类中使用的注释的polyfill库。
  • rxjs: This is the library that includes all of the observables that we'll use for handling our data.

    rxjs :这是一个库,其中包含我们将用于处理数据的所有可观察对象。
  • zone.js is a polyfill for the Zone specification, which is part of how Angular manages change detection.

    zone.js是用于Zone规范的zone.js ,这是Angular管理变更检测的一部分。

One thing to watch out for: Sometimes, there are conflicts involving the version of TypeScript you're using. This can be due to RxJS, the Angular compiler, or Webpack. If you start getting weird compilation errors, do some research to find out of any of those need a specific version range of TypeScript for the version you're using.

需要注意的一件事:有时,您所使用的TypeScript版本存在冲突。 这可能是由于RxJS,Angular编译器或Webpack引起的。 如果开始出现奇怪的编译错误,请进行一些研究以找出那些需要使用特定TypeType的特定版本范围的TypeScript。

好吧,让我们这样做。 (Okay, let's do this.)

Without further ado, open your terminal, cd into the public folder of the project, and run npm install (you're welcome to install and use Yarn if you'd prefer!). You should see that all of your packages were installed.

事不宜迟,打开你的终端, cdpublic项目的文件夹,然后运行npm install (欢迎您安装和使用的纱线如果你愿意!)。 您应该看到所有软件包都已安装。

We're now ready to make our application a hybrid application by dual-booting both AngularJS and Angular.

现在,我们准备通过双重引导AngularJS和Angular使我们的应用程序成为混合应用程序。

设置ngUpgrade ( Setting up ngUpgrade )

To set up ngUpgrade, we need to do a series of steps to allow AngularJS and Angular to run alongside of each other.

要设置ngUpgrade,我们需要执行一系列步骤,以允许AngularJS和Angular相互运行。

步骤1:从index.html移除Bootstrap (Step 1: Remove Bootstrap from index.html)

The first thing we need to do is remove our bootstrap directive from index.html. This is how AngularJS normally gets started up at page load, but we're going to bootstrap it through Angular using ngUpgrade. So, just open index.html and remove that data-ng-app tag. (if you're using strict DI in your own app, you'll remove ng-strict-di as well in this step.) Your index.html file should look like this now:

我们需要做的第一件事是从index.html删除我们的bootstrap指令。 这就是AngularJS通常在页面加载时启动的方式,但是我们将使用ngUpgrade在Angular中引导它。 因此,只需打开index.html并删除该data-ng-app标签。 (如果您在自己的应用中使用严格的DI,则在此步骤中也将删除ng-strict-di 。)您的index.html文件现在应如下所示:

<html>
  <head>
    <title>Amazing, Inc. Order System</title>
  </head>
  <body>
      <navigation></navigation>
      <div class="container" ng-view></div>
  </body>
</html>

步骤2:更改AngularJS模块 (Step 2: Change the AngularJS Module)

Now we need to make some changes in AngularJS module. Open up app.ts. The first thing we need to do is rename app.ts to app.module.ajs.ts to reflect that it's the module for AngularJS. It's kind of a lengthy name, but in Angular we want to have our type in our file name. Here we're using app.module and then we're adding that ajs to specify that it's for AngularJS instead of our root app.module for Angular (which we'll make in a second).

现在我们需要在AngularJS模块中进行一些更改。 打开app.ts。 我们需要做的第一件事是将app.ts重命名为app.module.ajs.ts以反映它是AngularJS的模块。 这是一个冗长的名称,但是在Angular中,我们希望在文件名中输入类型。 在这里,我们使用app.module ,然后添加该ajs以指定它用于AngularJS,而不是我们的根app.module用于Angular(我们将在稍后进行介绍)。

As the app is now, we're just using AngularJS, so we have all of our import statements here and we're registering everything on our Angular module. However, now what we're going to do is export this module and import it into our new Angular module to get it up and running. So, on line 28 let's create a string constant of our app name:

就像现在的应用程序一样,我们只是使用AngularJS,因此我们在这里拥有所有导入语句,并且正在Angular模块上注册所有内容。 但是,现在我们要做的是导出此模块,并将其导入到新的Angular模块中以使其启动并运行。 因此,在第28行,我们为我们的应用程序名称创建一个字符串常量:

const MODULE_NAME = 'app';

const MODULE_NAME = 'app';

Then we'll replace our app string with module name in our Angular.module declaration:

然后,在Angular.module声明中将应用程序字符串替换为模块名称:

angular.module(MODULE_NAME, ['ngRoute'])
// component and service registrations continue here

And finally, we need to export our constant:

最后,我们需要导出常量:

export default MODULE_NAME;

export default MODULE_NAME;

You can check out the finished AngularJS module at this stage here.

您可以在此阶段检查出来的成品AngularJS模块这里

步骤3:建立Angular应用程式模组 (Step 3: Create the Angular App Module)

Our AngularJS module is ready to go, so we're now ready to make our Angular module. We'll then import our AngularJS module so we can manually bootstrap it here. That's what let's the two frameworks run together, and enables ngUpgrade to bridge the gap between them.

我们的AngularJS模块已准备就绪,因此现在可以开始制作Angular模块了。 然后,我们将导入AngularJS模块,以便在此处手动进行引导。 这就是我们将两个框架一起运行的过程,并使ngUpgrade能够弥合它们之间的差距。

The first thing we need to do is create a new file at the same level as our AngularJS module called app.module.ts. Now for the first time, you're about to see a pattern that's going to become very familiar to you throughout your upgrade: making and exporting a class, decorating it with an annotation, and importing all of the dependencies.

我们需要做的第一件事是在与名为app.module.ts的AngularJS模块相同的级别上创建一个新文件。 现在,第一次,您将看到一个在整个升级过程中将变得非常熟悉的模式:制作和导出一个类,用注释装饰它,以及导入所有依赖项。

In our new app module, let's create a class named AppModule:

在我们的新应用程序模块中,让我们创建一个名为AppModule的类:

export class AppModule { 
}

Now let's add our first annotation (also called a decorator). An annotation is just a bit of metadata that Angular uses when building our application. Above our new class, we'll use the NgModule annotation and pass in an options object:

现在,让我们添加第一个注释 (也称为decorator )。 注释只是Angular在构建应用程序时使用的一些元数据。 在新类之上,我们将使用NgModule批注并传递一个options对象:

@NgModule({})
export class AppModule { 
}

If you're following along in an editor like Visual Studio Code, you'll see that TypeScript is mad at us because it doesn't know what NgModule is. This is because we need to import it from the Angular core library. Above our decorator, we can fix this with:

如果您在使用类似Visual Studio Code的编辑器,那么您会发现TypeScript很生气,因为它不知道NgModule是什么。 这是因为我们需要从Angular核心库中导入它。 在装饰器上方,我们可以使用以下方法解决此问题:

import { NgModule } from '@angular/core';

import { NgModule } from '@angular/core';

Now, in our options object for ngModule, we need to pass an array of imports. The imports array specifies other NgModules that this NgModule will depend on. (These imports are different than the TypeScript imports at the top of our file.) Right now, we need the BrowserModule and the UpgradeModule:

现在,在ngModule的options对象中,我们需要传递一个导入数组。 imports数组指定此NgModule依赖的其他NgModule。 (这些导入与文件顶部的TypeScript导入不同。)现在,我们需要BrowserModule和UpgradeModule:

import { NgModule } from '@angular/core';

@NgModule({
    imports: [
        BrowserModule,
        UpgradeModule
    ]
})
export class AppModule { }

Of course, we don't have those imported either at the top of our file, so we need to do that too. After our first import, we can add:

当然,文件的顶部也没有导入这些文件,因此我们也需要这样做。 首次导入后,我们可以添加:

import { BrowserModule } from '@angular/platform-browser'; import { UpgradeModule } from '@angular/upgrade/static';

import { BrowserModule } from '@angular/platform-browser'; import { UpgradeModule } from '@angular/upgrade/static';

There's actually an UpgradeModule in both upgrade and upgrade/static. We want to use the static one because it provides better error reporting and works with AOT (ahead-of-time) compiling.

实际上,在upgradeupgrade/static中都存在一个UpgradeModule。 我们要使用静态代码,因为它可以提供更好的错误报告,并且可以与AOT(提前)编译一起使用。

We've got the basic scaffolding of our root module for Angular set up and we're ready to do the bootstrapping itself.

我们已经有了用于Angular的根模块的基本支架,并且已经准备好进行引导。

步骤4:在Angular模块中引导 (Step 4: Bootstrap in the Angular Module)

To bootstrap our application, the first thing we need to do is inject UpgradeModule using a constructor function:

要引导我们的应用程序,我们需要做的第一件事是使用构造函数注入UpgradeModule:

constructor(private upgrade: UpgradeModule){
}

We don't need to do anything in our constructor function. The next thing we'll do is override the doBootstrap function. After the constructor, type:

我们不需要在构造函数中做任何事情。 我们要做的下一件事是覆盖doBootstrap函数。 在构造函数之后,键入:

ngDoBootstrap(){
}

Next, we'll use the UpgradeModule's bootstrap function. It actually has the same signature as the Angular bootstrap function, but it does a couple extra things for us. First, it makes sure that Angular and AngularJS run in the correct zones, and then it sets up an extra module that allows AngularJS to be visible in Angular and Angular to be visible in AngularJS. Lastly, it adapts the testability APIs, so that Protractor will work with hybrid apps, which is super important.

接下来,我们将使用UpgradeModule的引导功能。 它实际上具有与Angular bootstrap函数相同的签名,但是它为我们做了一些额外的事情。 首先,确保Angular和AngularJS在正确的区域中运行,然后设置一个额外的模块,该模块允许AngularJS在Angular中可见,而Angular在AngularJS中可见。 最后,它适应了可测试性API,因此Protractor可以与混合应用程序一起使用,这非常重要。

Let's add it:

让我们添加它:

ngDoBootstrap(){
        this.upgrade.bootstrap(document.documentElement, [moduleName], {strictDi: true});
}

We're first passing in our document element and then our AngularJS module inside an array. Lastly, just so you can see an example of this, we're adding a config object so we can switch on strict dependency injection.

我们首先要传递document元素,然后是数组中的AngularJS模块。 最后,正好您可以看到一个示例,我们添加了一个config对象,以便可以启用严格的依赖注入。

Are you thinking, "Wait, where did that moduleName come from?" Great instinct! We need to import it up with our other import statements:

您是否在想:“等等,那个moduleName是从哪里来的?” 大本能! 我们需要将其与其他导入语句一起导入:

import moduleName from './app.module.ajs';

import moduleName from './app.module.ajs';

Here's what our completed app.module.ts file looks like now:

这是我们现在完成的app.module.ts文件的外观:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static';
import moduleName from './app.module.ajs';

@NgModule({
    imports: [
        BrowserModule,
        UpgradeModule
    ]
})
export class AppModule {
    constructor(private upgrade: UpgradeModule) { }

    ngDoBootstrap(){
        this.upgrade.bootstrap(document.documentElement, [moduleName], {strictDi: true});
    }
}

This is going to be a pattern that's going to become very familiar to you over time, so if you're a little confused right now, just hang in there and keep on going. You're doing great!

随着时间的流逝,这种模式将变得非常熟悉,因此,如果您现在有点困惑,请继续坚持下去。 你做得很好!

步骤5:创建main.ts (Step 5: Create main.ts)

Now that we've got our AngularJS module and our Angular module set up, we need an entry point that's going to bring these two together and get our application running. Let's create a new file under our src folder called main.ts.

现在我们已经设置了AngularJS模块和Angular模块,我们需要一个入口点来将这两者结合在一起并使我们的应用程序运行。 让我们在src文件夹下创建一个名为main.ts的新文件。

In main.ts, we need to import a few things, tell Angular which version of AngularJS to load, and then tell it to bootstrap our Angular module. First, we need to import two polyfill libraries and Angular's platformBrowserDynamic function:

main.ts ,我们需要导入一些东西,告诉Angular加载哪个版本的AngularJS,然后告诉它引导我们的Angular模块。 首先,我们需要导入两个polyfill库和Angular的platformBrowserDynamic函数:

import 'zone.js';
import 'reflect-metadata';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

Why platformBrowserDynamic instead of just platformBrowser? Angular has two ways to compile: a dynamic option and a static option. In the dynamic option (known as just-in-time, or JIT), the Angular compiler actually compiles the application in the browser and then launches the app. The static option (known as ahead-of-time, or AOT) produces a much smaller application that launches faster. This is because the Angular compiler runs ahead of time as part of the build process. We're just going to be using the JIT method here along with the Webpack dev server.

为什么选择platformBrowserDynamic而不是platformBrowser ? Angular有两种编译方式:动态选项和静态选项。 在动态选项(称为即时或JIT)中,Angular编译器实际上是在浏览器中编译应用程序,然后启动该应用程序。 静态选项(称为“提前”或“ AOT”)生成的应用程序小得多,启动速度更快。 这是因为Angular编译器会在构建过程中提前运行。 我们将在这里与Webpack开发服务器一起使用JIT方法。

(In the course we spend an entire module setting up AOT compiling for production.)

(在此过程中,我们花费了整个模块来设置用于生产的AOT编译。)

Now we need to import both our Angular and AngularJS modules, as well as a method that tells Angular which version of AngularJS to use:

现在,我们需要导入Angular和AngularJS模块,以及一种告诉Angular使用哪个版本的AngularJS的方法:

import { setAngularLib } from '@angular/upgrade/static';
import * as angular from 'angular';

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

Now to finish this off, we just need to call setAngularLib and pass in our version of AngularJS, and we need to call platformBrowserDynamic and tell it to bootstrap our app module. The finished file looks like this:

现在完成此操作,我们只需要调用setAngularLib并传入我们的AngularJS版本,就需要调用platformBrowserDynamic并告诉它引导我们的应用程序模块。 完成的文件如下所示:

import 'zone.js';
import 'reflect-metadata';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { setAngularLib } from '@angular/upgrade/static';
import * as angular from 'angular';
import { AppModule } from './app.module';

setAngularLib(angular);
platformBrowserDynamic().bootstrapModule(AppModule);

Now that we've got that set up, we just need to change our Webpack entry point in our config.

现在我们已经完成了设置,我们只需要在配置中更改Webpack入口点即可。

步骤6:更新Webpack (Step 6: Update Webpack)

Hopefully, this process of bootstrapping a hybrid application is starting to make sense to you. We have a main.ts file that's our entry point, which sets up our AngularJS library and bootstraps our Angular module. Then, our Angular module bootstraps our AngularJS module. That's what let's both frameworks run alongside each other.

希望,这种引导混合应用程序的过程对您来说已经很有意义。 我们有一个main.ts文件作为入口点,该文件设置了我们的AngularJS库并引导了我们的Angular模块。 然后,我们的Angular模块引导我们的AngularJS模块。 这就是我们两个框架相互并行运行的原因。

We're now ready to change our Webpack config so that it's starting with our main.ts file and not one of our app module files. Open up webpack.common.js (it's under the webpack-configs folder). Under module.exports for entry, we'll change our app root to main.ts:

现在,我们准备更改Webpack的配置,使其从main.ts文件而不是我们的应用模块文件之一开始。 打开webpack.common.js (位于webpack-configs文件夹下)。 在module.exports entry ,我们将应用程序根目录更改为main.ts

entry: {
        app: './src/main.ts',
}

让我们来看看 (Let's See It in Action)

Now, we're ready to actually see our hybrid application in action. You can run the dev server by opening a terminal and running these commands:

现在,我们准备好实际查看混合应用程序了。 您可以通过打开终端并运行以下命令来运行开发服务器:

cd server
npm start
cd ../public
npm run dev

You should see that Webpack is loading and that our TypeScript is compiled successfully.

您应该看到Webpack正在加载,并且我们的TypeScript已成功编译。

Let's go check out the browser at localhost:9000. You can see that our application still runs on our dev server!

让我们在localhost:9000处签出浏览器。 您可以看到我们的应用程序仍在我们的开发服务器上运行!

Success!

You might see a couple of warnings in the console about core-js depending on your version, but don't worry about them, they won't affect us. You can also open the network tab and see the vendor bundle and app bundle:

您可能会在控制台中看到一些关于core-js的警告,具体取决于您的版本,但请不要担心,它们不会影响我们。 您还可以打开网络标签,查看供应商捆绑包和应用捆绑包:

Massive vendor file

The vendor bundle is absolutely huge, and that's because 1) we're running Webpack dev server, which means it's not minifying anything, 2) we're running Angular in dynamic compiling, so it's shipping the compiler code to the browser as well. We'll fix this downstream when we talk about AOT compiling, but we can actually navigate around here and see that all of our data is still loading. Awesome.

供应商捆绑包绝对是巨大的,这是因为1)我们正在运行Webpack开发服务器,这意味着它没有缩小任何东西,2)我们在动态编译中运行Angular,因此也将编译器代码也运送到了浏览器。 在谈论AOT编译时,我们将在下游修复此问题,但实际上我们可以在此处浏览并看到所有数据仍在加载中。 太棒了

So, we actually now have Angular and AngularJS running alongside of each other, which means we've successfully set up our hybrid application. That means we're ready to actually start upgrading our application piece by piece. Congratulations!

因此,实际上我们现在使Angular和AngularJS彼此并存运行,这意味着我们已经成功设置了混合应用程序。 这意味着我们已经准备好开始逐步升级应用程序。 恭喜你!

重写和降级您的第一个组件 ( Rewrite & Downgrade Your First Component )

步骤1:重写组件 (Step 1: Rewrite the Component)

We've got our application bootstrapped and running in hybrid mode, so we're ready to get started with migrating each piece of our application. The approach I typically take is to pick a route and then start from the bottom up to rewrite each piece, starting with whatever has the least dependencies. This allows us to iteratively upgrade our application so that every point along the way, we have something that's deployable to production.

我们已经引导了应用程序并在混合模式下运行,因此我们准备开始迁移应用程序的每一部分。 我通常采用的方法是选择一条路线,然后从下至上重新编写每个部分,从具有最小依赖性的内容开始。 这使我们可以迭代地升级应用程序,以便在开发过程中的每一个环节中,我们都可以部署一些产品。

Let's start with the home route because that's an easy one with just the home component. We'll first rename our home component to home.component.ts.

让我们从本地路由开始,因为这只是一个简单的本地组件。 我们将首先将home组件重命名为home.component.ts

Now we need to rewrite our home component as an Angular class. Rewriting an AngularJS component to an Angular component is not that bad, especially since this one is pretty simple. The first thing we need to do is import component from the Angular core library at the top of our file:

现在,我们需要将home组件重写为Angular类。 将AngularJS组件重写为Angular组件还不错,尤其是因为这非常简单。 我们需要做的第一件事是从文件顶部的Angular核心库中导入组件:

import { Component } from '@angular/core'

import { Component } from '@angular/core'

The next thing we'll do is convert our function homeComponentController to a class. We can also capitalize it and remove the controller at the end of the name, so that it's just called HomeComponent. Lastly, let's get rid of the parenthesis. It looks like this now:

我们要做的下一步是将函数homeComponentController转换为一个类。 我们还可以将其大写并删除名称末尾的controller ,以便将其称为HomeComponent 。 最后,让我们摆脱括号。 现在看起来像这样:

class HomeComponent {
    var vm = this;
    vm.title = 'Awesome, Inc. Internal Ordering System';
}

Now let's clean up what's inside the class. We no longer need the declaration of vm since we're using a class. We can also add a property of title as a string, and move setting the title to a constructor function. Our class looks like this now:

现在,让我们清理一下类中的内容。 由于我们使用的是类,因此不再需要vm的声明。 我们还可以将title属性添加为字符串,并将标题设置为构造函数。 我们的班级现在看起来像这样:

class HomeComponent {
    title: string;
    constructor(){
        title = 'Awesome, Inc. Internal Ordering System';
    }
}

We also need to export this class and then delete that export default line.

我们还需要export此类,然后删除该export default行。

Now we need to apply the Component metadata decorator that we imported to tell Angular that this is a component. We can replace the home component object with the component decorator and an options object:

现在,我们需要应用导入的Component元数据装饰器,以告诉Angular这是一个组件。 我们可以用组件装饰器和选项对象替换home组件对象:

@Component({
}

The first option of our component decorator is the selector. This is just the HTML tag that we'll use to reference this component, which will just be 'home'. Note that in Angular, the selector is actually a string literal. This is different than in AngularJS, where we would name the component in camel case, and then it would translate to an HTML tag with hyphens. Here, we're going to put exactly the tag that we want to use. In this case, we're just keeping it to 'home', so it doesn't matter too much. After that, we'll specify our template, just like we did with AngularJS, so I'll just say template: template. And believe it or not, that's all there is to it. Our finished component looks like this:

我们的组件装饰器的第一个选择是selector 。 这只是我们将用来引用此组件HTML标记,它将只是“ home”。 请注意,在Angular中,选择器实际上是字符串文字。 这与AngularJS不同,在AngularJS中,我们以驼峰式命名该组件,然后将其转换为带有连字符HTML标记。 在这里,我们将准确放置我们要使用的标签。 在这种情况下,我们只是将其保留在“家”中,所以没有太大关系。 之后,我们将指定template ,就像我们对AngularJS所做的那样,所以我只说template: template 。 信不信由你,这就是全部。 我们完成的组件如下所示:

import { Component } from '@angular/core';

const template = require('./home.html');

@Component({
    selector: 'home',
    template: template
})
export class HomeComponent {
    title: string;
    constructor(){
        this.title = 'Awesome, Inc. Internal Ordering System';
    }
}

Note: If you're working on an application that will use the AOT compiler, you'll want to use templateUrl instead what we're doing here and make some changes to Webpack. This is totally fine for JIT and the development server, though.

注意:如果您正在使用AOT编译器的应用程序上工作,则将要使用templateUrl代替我们在此处所做的事情,并对Webpack进行一些更改。 不过,对于JIT和开发服务器来说,这完全没问题。

步骤2:降级AngularJS组件 (Step 2: Downgrade the Component for AngularJS)

We now need to use the ngUpgrade library to "downgrade" this component. "Downgrading" means to make an Angular component or service available to AngularJS. "Upgrading," on the other hand, means to make an AngularJS component or service availble to Angular. We'll cover that in another article. Luckily, downgrading is super easy.

现在,我们需要使用ngUpgrade库来“降级”该组件。 “降级”是指使AngularJS可以使用Angular组件或服务。 另一方面,“升级”意味着使Angular可以使用AngularJS组件或服务。 我们将在另一篇文章中介绍。 幸运的是,降级非常容易。

注册并降级组件 (Register and Downgrade the Component)

First, we need to do two things at the top of our file along with our imports. We need to import the downgradeComponent function from the Angular upgrade library declare a variable called angular so we can register this component on our AngularJS module. This looks like this:

首先,我们需要在文件顶部和导入文件之间做两件事。 我们需要从Angular升级库中导入downgradeComponent函数,声明一个名为angular的变量,以便可以在AngularJS模块上注册该组件。 看起来像这样:

import { downgradeComponent } from '@angular/upgrade/static'; declare var angular: angular.IAngularStatic;

import { downgradeComponent } from '@angular/upgrade/static'; declare var angular: angular.IAngularStatic;

Downgrading the component is actually very simple. Down at the bottom of our component, we'll register this component as a directive. We'll pass in our directive name, which is just home, the same as our selector in this case. Then after that, we'll pass in the downgradeComponent function from ngUpgrade. This function converts our Angular component into an AngularJS directive. Finally, we'll cast this object as angular.IDirectiveFactory. The finished registration looks like this:

降级组件实际上非常简单。 在组件的底部,我们将把该组件注册为指令。 在这种情况下,我们将传入指令名称,即home ,与选择器相同。 然后,我们将从ngUpgrade传入downgradeComponent函数。 此函数将我们的Angular组件转换为AngularJS指令。 最后,我们将此对象转换为angular.IDirectiveFactory 。 完成的注册如下所示:

app.module('app')
  .directive('home', downgradeComponent({component: HomeComponent} as angular.IDirectiveFactory);
从AngularJS模块中删除 (Remove from AngularJS Module)

Now we have a downgraded Angular component that's available to our AngularJS application. You might be wondering why I registered that directive here at the bottom of this file instead of importing and registering it in our AngularJS module TypeScript file. The end goal is to actually get rid of that file altogether once all of our application is converted, so I want to gradually remove things from that file and then eventually delete it altogether when we uninstall AngularJS. This works great for sample applications or rapid migrations (more on that in a second).

现在我们有一个降级的Angular组件,可用于我们的AngularJS应用程序。 您可能想知道为什么我在此文件的底部此处注册了该指令,而不是将其导入并注册到我们的AngularJS模块TypeScript文件中。 最终目标是在转换完所有应用程序后实际上完全删除该文件,因此我想逐步从该文件中删除内容,然后最终在卸载AngularJS时将其完全删除。 这对于示例应用程序或快速迁移非常有用(稍后会详细介绍)。

Go ahead and open up app.module.ajs.ts and remove the import of homeComponent on line 12 and the component registration on line 37.

继续前进,打开app.module.ajs.ts并取出的进口homeComponent上线12和上线37的组件注册。

AOT编译快速说明 (A Quick Note on AOT Compiling)

This method of downgrading -- registering the downgraded component in the component file and removing it from the AngularJS module file -- works perfectly well for development or if you plan on quickly rewriting your application before you deploy. However, the Angular AOT compiler for production won't work with this method. Instead, it wants all of our downgraded registrations in the AngularJS module. Here in this sample project, we don't need to worry about that, but I'd be remiss if I didn't mention it for use in the real world.

这种降级方法-在组件文件中注册已降级的组件,然后将其从AngularJS模块文件中删除-对于开发或计划在部署之前快速重写应用程序的情况,该方法非常适用。 但是,用于生产的Angular AOT编译器不适用于此方法。 相反,它希望在AngularJS模块中所有降级的注册。 在此示例项目中,我们不必担心这一点,但是如果我不提及它在现实世界中的使用,那我将被忽略。

The downgrade is identical, but instead you'd:

降级是相同的,但是您可以:

  1. Import downgradeComponent in app.module.ajs.ts (you've already got angular in there so you don't need to declare it).

    app.module.ajs.ts导入downgradeComponent (您已经在其中有了angular ,因此不需要声明它)。
  2. Change the import of homeComponent to import { HomeComponent } from './home/home.component'; since we switched to a named export.

    将homeComponent的导入更改为import { HomeComponent } from './home/home.component'; 因为我们切换到命名出口。
  3. Change the component registration to the exact same directive registration shown above.

    将组件注册更改为与上面显示的完全相同的指令注册。

You can read more about setting up ngUpgrade for AOT in this article I wrote, as well as in Course 3 of Upgrading AngularJS (there's a whole module that lays it out step-by-step).

您可以在我写的这篇文章以及《 升级AngularJS的课程3》(有一个完整的模块,逐步介绍)中阅读有关为AOT设置ngUpgrade的更多信息。

步骤3:更新范本 (Step 3: Update the Template)

After a component is updated, we need to be sure to update its template so it complies with the new Angular syntax. In this case, the template for homeComponent is obviously stuper simple. We just need to remove $ctrl on line two. The template looks like this now:

组件更新后,我们需要确保更新其模板,使其符合新的Angular语法。 在这种情况下, homeComponent的模板显然很简单。 我们只需要删除第二行的$ctrl 。 现在,模板如下所示:

<div class="row">
    <h1>{{title}}</h1>
</div>

Now we have a fully functional downgraded home component in our hybrid application!

现在,我们的混合应用程序中具有功能齐全的降级家庭组件!

步骤4:添加到Angular应用模块 (Step 4: Add to the Angular App Module)

Let's add our shiny new Angular component to our Angular module. Open up app.module.ts. First, we need to just import our home component after all of our other imports:

让我们将闪亮的新Angular组件添加到Angular模块中。 打开app.module.ts 。 首先,我们需要在所有其他导入之后仅导入home组件:

import { HomeComponent } from './home/home.component';

import { HomeComponent } from './home/home.component';

I like to keep these imports separate from the imports up at the top.

我喜欢将这些进口商品与进口商品分开放在顶部。

Now, we need to add HomeComponent to our Angular application. All Angular components must be added to a declarations array of our NgModule. So, after line 12 in our options object, we'll add a new array called declarations and add our component:

现在,我们需要将HomeComponent添加到Angular应用程序中。 必须将所有Angular组件添加到我们的NgModule的declarations数组中。 因此,在options对象的第12行之后,我们将添加一个称为声明的新数组并添加我们的组件:

declarations: [
        HomeComponent
]

We also need to create an entryComponents array and add our HomeComponent to that. All downgraded components must be added to this entryComponents array. We'll add it after our declarations:

我们还需要创建一个entryComponents数组并将其entryComponents添加到该数组中。 必须将所有降级的组件添加到此entryComponents数组。 我们将在declarations后添加它:

entryComponents: [
        HomeComponent
]

And we're done!

我们完成了!

让我们检查一下它是否有效。 ( Let's check that it works. )

You did it! Let's run those same commands as before and make sure our application is still working. Here are those commands again:

你做到了! 让我们运行与以前相同的命令,并确保我们的应用程序仍在运行。 这又是这些命令:

cd server
npm start
cd ../public
npm run dev

Head back over to localhost:9000. Lo and behold, you can see that our home component is actually loading in the browser as a rewritten Angular component! You can even go look at the Sources tab of Chrome devtools just to be positive. Open up webpack://, scroll down to ./src/home/home.component.ts, and sure enough, there it is!

回到localhost:9000 。 瞧,您可以看到我们的home组件实际上是作为重写的Angular组件加载到浏览器中的! 您甚至可以直接看一下Chrome devtools的“来源”标签。 打开webpack:// ,向下滚动到./src/home/home.component.ts ,可以肯定的是!

Shiny new home component!

Way to go!

要走的路!

下一步去哪里 ( Where to Go Next )

Here's what you've accomplished in this guide:

这是本指南中您完成的工作:

  1. Installed Angular and ngUpgrade

    已安装Angular和ngUpgrade
  2. Set up an Angular module

    设置一个Angular模块
  3. Bootstrapped Angular and AngularJS

    自举Angular和AngularJS
  4. Updated Webpack

    更新了Webpack
  5. Rewritten and downgraded your first component

    重写并降级您的第一个组件

You should feel super proud!

您应该感到超级自豪!

Where should you go next? Take a crack at a more complicated route. I suggest the customers route in this application. In our next guide, we'll talk about the basics of rewriting and downgraded services. Stay tuned!

你下一步应该去哪里? 尝试更复杂的方法。 我建议customers在此应用程序中进行路由。 在下一个指南中,我们将讨论重写和降级的服务的基础知识。 敬请关注!

<a href="https://www\.upgradingangularjs\.com?ref=scotch\.io"\>

</a>

<a href=" https://www\.upgradingangularjs\.com?ref=scotch\.io"\>

If you love this guide, I’ve got 200+ detailed videos, quiz questions, and more for you in my comprehensive course Upgrading AngularJS. I created it for everyday, normal developers and it’s the best ngUpgrade resource on the planet. Head on over and sign up for our email list to get yourself a free Upgrade Roadmap Checklist so you don’t lose track of your upgrade prep. And, while you’re there, check out our full demo.

如果您喜欢本指南,则在我的综合课程《 升级AngularJS》中 ,有200多个详细的视频,测验问题以及更多内容供您选择。 我为日常的普通开发人员创建了它,它是地球上最好的ngUpgrade资源。 前往并注册我们的电子邮件列表,以获取免费的升级路线图清单,以免您忘记升级准备。 而且,当您在那里时,请查看我们的完整演示。

See you next time, Scotchers!

下次见,苏格兰人!

翻译自: https://scotch.io/tutorials/get-started-with-ngupgrade-going-from-angularjs-to-angular

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值