ChatGPT解决这个技术问题 Extra ChatGPT

Angular 如何构建和运行

只是想了解 Angular 如何在幕后构建和运行?

以下是我到目前为止所理解的。想知道我是否错过了什么。

Angular 是如何构建的

在使用 TypeScript 编写 Angular 应用程序后,我们使用 Angular CLI 命令来构建应用程序。

ng build 命令将应用程序编译到输出目录中,构建工件将存储在 dist/ 目录中。

内部流程

1. Angular CLI 运行 Webpack 来构建和捆绑所有 JavaScript 和 CSS 代码。

2. Webpack 依次调用 TypeScript 加载器,该加载器获取 Angular 项目中的所有 .ts 文件,然后将它们转换为 JavaScript,即转换为浏览器可以理解的 .js 文件。

This 帖子说 Angular 有两个编译器:

查看编译器

模块编译器

关于构建的问题

调用构建过程的顺序是什么?

Angular CLI 首先调用用 TypeScript 编写的 Angular 内置编译器 =>然后调用 TypeScript Transpiler =>然后调用 Webpack 打包并存储在 dist/ 目录中。

Angular 如何运行

构建完成后,我们应用程序的所有组件、服务、模块等都被转换为 JavaScript .js 文件,用于在浏览器中运行 Angular 应用程序。

Angular Docs 中的语句

当您使用 AppComponent 类(在 main.ts 中)进行引导时,Angular 会在 index.html 中查找 ,找到它,实例化 AppComponent 的一个实例,并将其呈现在 标记中。当用户在应用程序中移动时,Angular 会创建、更新和销毁组件。

关于跑步的问题

尽管在上面的语句中使用了 main.ts 来解释引导过程,但 Angular 应用程序不是使用 JavaScript .js 文件引导或启动的吗?

上面所有的语句不都是使用 JavaScript .js 文件在运行时完成的吗?

有谁知道所有部分如何深入结合在一起?


P
Pace

(当我说 Angular 时,我的意思是 Angular 2+,如果我提到 Angular 1,我会明确地说 angular-js)。

前奏:令人困惑

Angular,可能更准确地说是 angular-cli,已经将构建过程中涉及的 Javascript 中的许多趋势工具合并在一起。它确实会导致一些混乱。

为了进一步混淆,在 angular-js 中经常使用术语 compile 来指代获取模板的伪 html 并将其转换为 DOM 元素的过程。这是编译器所做的一部分,但只是较小的部分之一。

首先,不需要使用 TypeScript、angular-cli 或 Webpack 来运行 Angular。回答你的问题。我们应该看一个简单的问题:“什么是 Angular?”

角:它有什么作用?

这部分可能会引起争议,我们将拭目以待。 Angular 提供的服务的核心是一种依赖注入机制,可以跨 Javascript、HTML 和 CSS 工作。您单独编写所有的点点滴滴,并且在每个小块中您都遵循 Angular 的规则来引用其他部分。然后,Angular 以某种方式将其编织在一起。

(稍微)更具体:

模板允许将 HTML 连接到 Javascript 组件中。这允许用户在 DOM 本身上的输入(例如单击按钮)输入到 Javascript 组件中,并且还允许 Javascript 组件中的变量控制 DOM 中的结构和值。

Javascript 类(包括 Javascript 组件)需要能够访问它们所依赖的其他 Javascript 类的实例(例如经典依赖注入)。 BookListComponent 需要 BookListService 的实例,而 BookListService 可能需要 BookListPolicy 或类似的实例。这些类中的每一个都有不同的生命周期(例如,服务通常是单例,组件通常不是单例),Angular 必须管理所有这些生命周期、组件的创建和依赖关系的连接。

CSS 规则需要以仅适用于 DOM 子集的方式加载(组件的样式对于该组件是本地的)。

需要注意的一件可能很重要的事情是,Angular 不负责 Javascript 文件如何引用其他 Javascript 文件(例如 import 关键字)。这由 Webpack 负责。

编译器是做什么的?

既然您知道 Angular 是做什么的,我们就可以谈谈编译器的作用。我会避免过于技术性,主要是因为我无知。但是,在依赖注入系统中,您通常必须使用某种元数据来表达您的依赖关系(例如,类如何表示 I can be injectedMy lifetime is blahYou can think of me as a Component type of instance)。在 Java 中,Spring 最初是使用 XML 文件来实现的。 Java 后来采用了注解,它们已经成为表达元数据的首选方式。 C# 使用属性来表达元数据。

Javascript 没有一个很好的机制来公开这个内置的元数据。 angular-js 做了一个尝试,还不错,但是有很多规则不容易检查,有点混乱。使用 Angular 有两种支持的方式来指定元数据。您可以编写纯 Javascript 并手动指定元数据,有点类似于 angular-js,只需继续遵循规则并编写额外的样板代码。或者,您可以切换到 TypeScript,因为它恰好具有用于表达元数据的装饰器(那些 @ 符号)。

所以这里是我们最终可以使用编译器的地方。编译器的工作是获取元数据并创建作为您的应用程序的工作系统。您专注于所有部分和所有元数据,编译器构建一个大型互连应用程序。

编译器是如何做到的?

编译器有两种工作方式,运行时和提前。从这里开始,我假设您使用的是 TypeScript:

运行时:当 typescript 编译器运行时,它会获取所有装饰器信息并将其推送到附加到装饰类、方法和字段的 Javascript 代码中。在您的 index.html 中,您引用了调用 bootstrap 方法的 main.js。该方法传递给您的顶级模块。

bootstrap 方法启动运行时编译器并为其提供对该顶级模块的引用。然后运行时编译器开始爬取该模块、该模块引用的所有服务、组件等,以及所有相关元数据,并构建您的应用程序。

AOT:Angular 提供了一种在构建时完成大部分工作的机制,而不是在运行时完成所有工作。这几乎总是使用 webpack 插件来完成(这一定是最流行但最不为人知的 npm 包之一)。它在 typescript 编译运行后运行,因此它看到的输入与运行时编译器基本相同。 AOT 编译器像运行时编译器一样构建您的应用程序,然后将其保存回 Javascript。

这里的优势不仅在于您可以节省编译本身所需的 CPU 时间,而且还可以让您减小应用程序的大小。

具体答案

Angular CLI 首先调用用 Typescript => 编写的 Angular 内置编译器,然后调用 Typescript Transpiler =>,然后调用 Webpack 打包并存储在 dist/ 目录中。

不。Angular CLI 调用 Webpack(Angular CLI 的真正服务是配置 webpack。当您运行 ng build 时,它只不过是启动 Webpack 的代理)。 Webpack 首先调用 Typescript 编译器,然后调用 Angular 编译器(假设为 AOT),同时打包您的代码。

虽然在上面的声明中使用 main.ts 来解释引导过程,但 Angular 应用程序不是使用 Javascript .js 文件引导或启动的吗?

我不完全确定你在这里问什么。 main.ts 将被转换为 Javascript。该 Javascript 将包含对 bootstrap 的调用,它是 Angular 的入口点。 bootstrap 完成后,您将运行完整的 Angular 应用程序。

这篇文章说 Angular 有两个编译器: View Compiler Module Compiler

老实说,我只是在这里声称无知。我认为在我们的层面上,我们可以将其全部视为一个大型编译器。

有谁知道所有部分如何深入结合在一起?

我希望以上满足这一点。

不要@我:Angular 不仅仅是依赖注入

当然。它执行路由、视图构建、更改检测和各种其他事情。编译器确实会生成用于视图构建和更改检测的 Javascript。当我说这只是依赖注入时,我撒了谎。然而,依赖注入是核心,足以驱动其余的答案。

我们应该称它为编译器吗?

它可能会进行大量解析和词法分析,因此肯定会生成大量代码,因此您可以将其称为编译器。

另一方面,它并没有真正将您的代码翻译成不同的表示形式。取而代之的是,它采用了一堆不同的代码并将它们编织成更大系统的可消耗部分。然后引导过程(在编译之后,如果需要)获取这些部分并将它们插入 Angular 核心。


谢谢你的详细解答。在接受您的回答之前,我对您的声明 The compiler does actually generate Javascript 用于视图构建和更改检测有疑问。这不是谎言。这就是编译器所做的不是吗?并且 Angular 进行依赖注入。
是的,对不起。我所指的谎言是“Angular 提供的服务的核心是依赖注入机制”,因为虽然 Angular 做到了,但它并不是它所做的全部,甚至编译器也不是全部。
如果 Angular 被抽象为一种具有组件、指令、服务等特性的新“语言”。它可以称为编译器。将 Angular 语言编译成原始的 js 和 html。
S
Shaiju T

让我从头开始。

在我的应用程序中,我直接从 Webpack 运行应用程序。

要构建和运行应用程序,我们使用 webpack --progresswebpack-dev-server --inline 命令,已在 package.json 中编写如下

"scripts": {
    "serve": "webpack-dev-server --inline ",
    "build": "webpack --progress"

  }

当我们运行 webpack --progress 命令时,它开始读取 webpack.config.js 文件,并在其中找到如下入口点。

module.exports = {
    devtool: 'source-map',
    entry: './src/main.ts',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.ts$/,
                loaders: ['awesome-typescript-loader', 'angular2-template-loader'],
                exclude: [/\.(spec|e2e)\.ts$/]
            },
            /* Embed files. */
            {
                test: /\.(html|css)$/,
                loader: 'raw-loader',
                exclude: /\.async\.(html|css)$/
            },
            /* Async loading. */
            {
                test: /\.async\.(html|css)$/,
                loaders: ['file?name=[name].[hash].[ext]', 'extract']
            },
        ]
    },
    resolve: {
        extensions: ['.ts', '.js']
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ]
}   

然后它读取所有 Typescript 文件并根据 tsconfig.json 文件中声明的规则进行编译,然后将其转换为相应的 .js 文件和它的映射文件。

如果它在没有任何编译错误的情况下运行,它将创建具有我们在 Webpack 输出部分中声明的名称的 bundle.js 文件。

现在让我解释一下为什么我们使用加载器。

awesome-typescript-loader, angular2-template-loader 我们使用这些加载器在 tsconfig.json 文件中声明的基础上编译 Typescript 文件,然后 angular2-template-loader 搜索 templateUrlstyleUrls 声明在 Angular 2 组件元数据中,并用相应的 require 语句替换路径。

resolve: {
        extensions: ['.ts', '.js']
    }

我们使用上述解析部分告诉 WebpackTypescript 转换为 JavaScript 文件

plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ]

Plugins 部分用于注入第三方框架或文件。在我的代码中,我使用它来注入目标文件夹的 index.html

 devtool: 'source-map',

上一行用于在浏览器中查看 Typescript 文件并对其进行调试,主要用于开发人员代码。

 loader: 'raw-loader'

上面的 raw-loader 用于加载 .html.css 文件并将它们与 Typescript 文件捆绑在一起。

最后,当我们运行 webpack-dev-server --inline 时,它将创建自己的服务器并以 web-pack.config.js 文件中提到的路径启动应用程序,其中我们提到了目标文件夹和入口点。

Angular 2 中,大多数应用程序的入口点是 main.ts,其中我们提到了初始引导模块,例如(app.module),该模块包含完整的应用程序信息,例如整个应用程序的所有指令、服务、模块、组件和路由实现.

注意:很多人怀疑为什么 index.html 只启动应用程序,即使他们没有提到任何地方。答案是当 Webpack serve 命令运行时,它会创建自己的服务,如果您没有提及任何默认页面,默认情况下它会加载 index.html

我希望给定的信息对某些人有所帮助。


感谢您尝试解释,如果您能以更清晰的顺序方式解释会更好。所以您不使用 Angular CLI 来构建 Angular 应用程序并直接使用 Webpack 怎么办?
S
Shaiju T

Angular 是如何构建的?

Angular CLI 调用 Webpack,当 Webpack 遇到 .ts 文件时,它会将其传递给 TypeScript 编译器,该编译器具有编译 Angular 模板的输出转换器

所以构建顺序是:

Angular CLI => Webpack => TypeScript 编译器 => TypeScript 编译器在编译时调用 Angular 编译器。

Angular 是如何运行的?

Angular 使用 Javascript 文件引导和运行。

实际上,引导过程是运行时的,并且在打开浏览器之前发生。这将我们带到下一个问题。

因此,如果引导过程发生在 Javascript 文件中,那么为什么 Angular Docs 使用 main.ts TypeScript 文件来解释引导过程?

Angular Docs 只讨论 .ts 文件,因为那是源文件。

这是简短的回答。感谢是否有人可以深入回答。

感谢 @Toxicable 在聊天中回答我的问题。


F
ForestG

这个答案可能会迟到,但最近关于这个话题的讨论非常好,它从初学者的角度开始并深入。我不会试图用我的话来总结或指出此线程中的错误信息,而是通过 Kara Erickson: How Angular works 链接视频。

她是 Angular 框架的技术负责人,并且在以下方面做了非常好的演示:

Angular 框架的主要部分是什么

编译器是如何工作的,它产生了什么

什么是“组件定义”

什么是应用程序引导程序,它是如何工作的


谢谢你的贡献:),欣赏。
它主要关注 om 运行时进程,仅简要涉及编译策略/进程。正好与 OP 的需求“相反”。
V
Vikas

因此,如果引导过程发生在 Javascript 文件中,那么为什么 Angular Docs 使用 main.ts TypeScript 文件来解释引导过程?

这是 ng build 发出的 main.ts 的转换 .js 版本的一部分,它还没有被丑化和缩小,你希望初学者如何理解这段代码?它看起来不是很复杂吗?

Object(__WEBPACK_IMPORTED_MODULE_1__angular_platform_browser_dynamic__["a" /* platformBrowserDynamic */])().bootstrapModule(__WEBPACK_IMPORTED_MODULE_2__app_app_module__["a" /* AppModule */])
    .catch(function (err) { return console.log(err); });

并且使用 ng build --prod --build-optimizer 丑化和缩小您的代码以优化它,生成的包是紧凑的并且是位不可读的格式。

webpackJsonp([1],{0:function(t,e,n){t.exports=n("cDNt")},"1j/l":function(t,e,n){"use strict";n.d(e,"a",function(){return r});var r=Array.isArray||function(t){return t&&"number"==typeof t.length}},"2kLc

而 main.ts 文件是人类可读且清晰的,这就是为什么 angular.io 使用 main.ts 来解释 Angular 应用程序的引导过程。Angular: Why TypeScript?除此之外,如果您是这样一个伟大框架的作者,您会采用什么方法为了使您的框架流行和用户友好而使用?您不会寻求清晰简洁的解释而不是复杂的解释吗?我同意 angular.io 文档缺乏深入的解释,而且它不是很好,但据我所知,他们正在努力让它变得更好。


Z
ZAFMA

Angular 9+ 使用 AOT(提前编译),这意味着它采用分散在各种文件中的所有位,即组件(.ts + .html + .css)、模块(.ts)并构建浏览器可理解的 JavaScript,在运行时下载并由浏览器执行。

在 Angular 9 之前,它是 JIT(即时编译),代码按照浏览器的要求进行编译。

有关详细信息,请参阅:Angular AOT Documentaiton