Angular CLI如何将Angular框架加载到应用程序中?

6
我正在将现有的AngularJS应用程序转换为混合应用程序,以逐步升级为Angular 4。我想了解在现有的AngularJS中如何引用Angular 4。在现有的AngularJS应用程序中,很清楚如何加载AngularJS框架 - 它只是一个包含的脚本文件:
<script src="/angular/angular.js"></script>

为了熟悉最新的Angular版本,我使用Angular快速入门指南https://angular.io/guide/quickstart创建了一个单独的“快速入门”Angular 5应用程序,并且可以通过以下方式运行它:
ng serve --open

当我查看项目文件时,我并没有看到 Angular 框架实际被加载的地方。在 src/index.html 文件中,并没有包含任何脚本来加载该应用程序的框架,它只是声明了一个指令用于组件 (app.component.ts),其代码如下:
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Test Angular 5 app';
}

“import”实际上是从哪里导入的呢?Angular文档中关于index.html文件的描述是:
“当有人访问你的网站时,这是提供服务的主要HTML页面。大多数情况下,你永远不需要编辑它。当构建你的应用程序时,CLI会自动添加所有js和css文件,因此你永远不需要手动添加任何

1
你尝试过ng build然后查看构建(dist)文件夹中的index.html吗? - Chau Tran
@Christian Santos的回答表明OP甚至没有看过已经构建好的index.html文件。 - Yasser Hussain
我的意图是解释导致创建 index.html 文件的过程。 - Christian Santos
那你应该问那个问题。看一下 ng-build https://github.com/angular/angular-cli/wiki/build - Yasser Hussain
谢谢,Chau。我不知道ng-build,一直在使用ng serve来运行我创建的“独立”Angular 5应用程序。当我尝试从我的源文件夹内运行ng build时,我收到错误信息“您似乎没有依赖于"@angular/core",尽管我在我的package.json中将@ angular / core:“^5.0.0”作为依赖项。通过运行ng serve还没有创建“dist”文件夹,因此目前还没有查看已构建的HTML文件的方法 - 而ng serve似乎可以在不需要静态编译的HTML文件的情况下工作? - Chris Halcrow
请确保在根目录下运行 ng build,而不是 src 目录。关于生成文件的位置,请参见我下面更新的答案。 - Christian Santos
2个回答

4
使用Angular CLI时,我们有很多组件需要协同工作。为了真正理解发生了什么,我们应该回顾一些与输出文件和模块解析相关的核心技术,包括:
- TypeScript -- 会将您的TypeScript代码转换为ES5或ES6(通常是ES5)。如果目标是ES5,则转译后的代码将默认使用CommonJS模块。如果目标是ES6,则使用ES6模块。 - Webpack -- 将获取您的转译后的TypeScript代码,并基于webpack.config.js中定义的入口点,构建一个基于导入/导出的依赖图。此依赖图将包括所有模块,并将这些模块打包成1个或多个捆绑包,具体取决于配置。在这一步骤中,Webpack会处理@angular/core依赖项(位于node_modules/@angular/core中),并将其添加到可以在运行时访问的捆绑包中。
你可以通过在HTML中包含生成的文件来加载生成的包。对于JS文件,您可以像使用AngularJS一样使用 script 标记来加载它们。
因为我们正在使用Angular CLI,所以有很多Webpack配置默认设置,因此我们将有多个生成的包。
我刚创建了一个空的Angular CLI项目并检查了HTML,看到了5个生成的包:

enter image description here

比较 Angular 项目文件和 AngularJS 文件的复杂之处在于,Angular 代码经过多个构建步骤转换,而 AngularJS 代码通常直接使用 ES5。如果将 Webpack 和 TypeScript 添加到 AngularJS 构建中,则会看到与 Angular 输出非常相似的结果。

Angular CLI 中 Webpack 的配置在哪里?

在底层,Angular CLI 使用 Webpack 构建您的项目并捆绑文件。

Angular 团队选择不公开可配置的 Webpack 配置文件供 Angular CLI 使用,但他们添加了 ng eject,该命令会生成一个与项目 Webpack 构建相匹配的 webpack.config.js 文件。强制执行此命令的缺点是您将不再使用 ng serve 来服务您的项目。而是使用 npm run build && npm run start(您会在强制执行后看到这些脚本添加到您的 package.json),它将基于生成的 webpack.config.js 文件构建和服务您的项目。

如果您需要对默认的 Webpack 构建进行自定义修改,则此功能非常重要。

了解更多有关 ng eject 此处 的信息。

生成的捆绑包在哪里?

如果您使用的是ng serve,则不会看到任何生成的文件,因为这些文件是从内存而不是磁盘中提供的(当文件不断变化时,加快开发速度),因此您的生成的文件不位于任何文件夹中。
如果您想查看生成的文件,可以运行ng build,它将创建一个带有index.html和相关资产/捆绑包的dist文件夹。
请注意,默认情况下,构建或服务项目的所有命令都会删除您的dist文件夹,除非在构建/服务时传递--no-delete-output-path参数。

谢谢Christian,这就是我想要的详细信息!但是我对Webpack的作用感到困惑。在我的项目中,我看不到任何使用Webpack的参考,并且在使用angular cli创建项目并运行ng serve后,我也看不到任何“编译”后的HTML文件。 - Chris Halcrow
嗨,克里斯——看看我的更新答案,涵盖了你的问题。如果有不清楚的地方,请告诉我。 - Christian Santos
还有一件事我不太清楚 - 我猜 TypeScript 本身可以进行模块捆绑,但是 Angular CLI 使用 WebPack 进行更全面的捆绑,包括 html、图像和其他资产捆绑,使捆绑更加全面?或者说 WebPack 必须用于模块捆绑,这是有原因的吗? - Chris Halcrow
1
你说得对 - 我们可以使用TypeScript并使用AMD或SystemJS来处理模块(大多数浏览器版本不支持原生模块,因此我们必须在浏览器中使用模块加载器)。但是添加Webpack非常有意义,因为它使我们能够执行诸如代码拆分、树摇、CSS模块、延迟模块加载等操作。简而言之,它是最全面的打包工具。 - Christian Santos

2
你需要了解在 TypeScript 中 导入导出 的工作原理。

来源:TypeScript 文档

导出声明

通过添加 export 关键字,可以导出任何声明(例如变量、函数、类、类型别名或接口)。

Validation.ts

export interface StringValidator {
    isAcceptable(s: string): boolean;
}

ZipCodeValidator.ts

export const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
导出语句

当需要为消费者重新命名出口时,导出语句非常方便,因此上述示例可以编写为:

ZipCodeValidator.ts

class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };
导入

从模块中导入内容与导出内容类似。可以通过以下任意一种导入形式来导入已导出的声明:

从模块中导入单个导出内容

import { ZipCodeValidator } from "./ZipCodeValidator";

let myValidator = new ZipCodeValidator();

进口的内容也可以被重新命名。
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();

将整个模块导入到一个变量中,并使用该变量访问模块的导出内容。
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();

由于您遵循了 Angular 快速入门指南,因此您一定使用了 npm 来安装模块和依赖项。
如果您阅读 angular.io/npm,则会看到以下内容:

@angular/core:每个应用程序都需要的框架关键运行时部分。包括所有元数据装饰器、组件、指令、依赖注入和组件生命周期钩子。

默认情况下,npm 将所有依赖项存储在 node_modules 目录中。
因此,您正在从 @angular/core 中导入 Component,它位于 node_modules 目录中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接