[從 0 開始的 Angular 生活]No.7 Angular 應用程式的啟動過程

前言

當我們透過 VSCode 的終端機執行 「npm start」 時,這段時間發生了什麼事情,讓我們好好地整理一下。

npm start

首先開啟一個之前就建立好的 Angular 專案範本,接著在 VSCode 的終端機執行 npm start

透過這張圖可以觀察到,當執行 npm start 時,其實是呼叫執行 Angular CLI 的命令 ng serve ,這個過程會啟動一個開發伺服器,而這個開發伺服器在啟動之前,背後透過 Webpack 將目前的 Source Code 內所有的 TypeScript 進行編譯。

編譯之後把所有的 JavaScript 檔案合併在一起,而這個過程中產生了幾支檔案:

  • es2015-polyfills.js, es2015-polyfills.js.map
  • polyfills.js, polyfills.js.map
  • runtime.js, runtime.js.map
  • styles.js, styles.js.map
  • vendor.js, vendor.js.map

那麼這些檔案會用在什麼地方呢?

index.html

在首頁打開的時候,預設會把剛才編譯產生的這些檔案給載入,我們可以透過觀察原始碼來了解。

對著 index.html 按右鍵 > 檢視網頁原始碼

首先我們看到一個

標籤,這個標籤可能比較少用,詳細的應用可以到這邊查看。

接著是標籤,這個標籤事實上就是 Angular 裡面的根元件,也可以稱它為一個 directive ,關於 directive 之後會有更詳細的說明。

然後發現 之前被插入了剛剛編譯出來的 .js 檔,而 Angular 應用程式也在載入這些 .js 檔後正式開始運行。

然而執行的過程中,也有一個啟動的流程。

啟動的流程結束後,標籤的內容就會被動態的插入一些 DOM 物件,最後顯示在畫面上。

對著 index.html 按右鍵 > 檢查

從 chrome 的開發者工具底下,可以看到標籤包含了一些從剛剛的原始碼內看不到的標籤。

因為這些內容全部都是透過 Angular 應用程式動態運算出來的結果。

實際觀察專案內的 index.html 檔案

這支檔案也就是剛才 chrome 瀏覽器開啟的檔案,而裡面確實有個標籤。

可以發現檔案內的

標籤內並沒有插入剛才那些 .js 檔,也就是說那是 Webpack 幫我們編譯後動態插入的

也就是說我們在開發 Angular 網頁時,它的 JavaScript 在開發時期是動態被注入的。

從哪支 .js 檔開始跑呢?

之前有提過, Angular 應用程式的進入點是 main.ts 檔案,而它的長相如下:

1
2
3
4
5
6
7
8
9
10
11
12
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

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

if (environment.production) {
enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));

前面 5 行主要是引用從某一些模組匯入程式運行時必要的物件進來。
而第 11 行的地方,則是透過 platformBrowserDynamic().bootstrapModule(AppModule) 去執行啟動模組這件事,接著會進入到 AppModule 裡面執行相關的程式碼,讓我們一起觀察下去吧。

小提示:在 VSCode 內可以對著 AppModule 點一下接著按 F12 會自動追蹤到該檔案喔

AppModule 內

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

這支檔案可以說是在 Angular 應用程式裡面最重要的一支程式,而程式碼結構不難看出它是一個 class 而且被 export 出來,神奇的是裡面沒有任何的程式碼。

在大部分的情況,我們寫 Angular 應用程式時確實是不需要寫程式在裡面的。

我們只需要套用一個 declarator ,而這個 declarator 要設定成 NgModule ,去宣告這個類別它是一個 Angular 的 Module ,然後我們在這個 Module 裡面又有好幾個 Property (屬性) 需要宣告:

  • declarations - 用來宣告一些跟 view 有關的元件
  • imports - 用來匯入一些跟這個模組會用到的其他模組,而模組說穿了就是多個元件封裝後的東西
    • BrowserModule 就是把 BrowserModule 內所有的元件一起匯入進來的意思
  • providers - 註冊服務的提供者
  • bootstrap - 啟動根元件 AppComponent ,也就是 Angular 最上層的元件 (預設名稱為 AppComponent)

接著我們使用剛才介紹的追蹤方式,繼續追蹤 AppComponent

AppComponent 內

1
2
3
4
5
6
7
8
9
10
import { Component } from '@angular/core';

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

AppComponent 元件的程式碼結構也一樣是個被 export 的 class ,然後這個範例程式預設有一個屬性 title

這個元件一樣有使用到 declarator ,叫做 Component ,這個 Component 在 Angular 內有特殊的涵義,這是用來宣告這個 class 代表的是一個 Component 。

而這個 Component 同樣有一些屬性如:

  • selector - 如果寫過 JQuery 肯定不會陌生,就是一個選取器,如同範例的 app-root 就是選取到 HTML 中 app-root 標籤,並且把這個標籤的內容,修改為這個元件執行的結果。
    • 同理,如果改寫成 .app-root 則是選取具有 .app-root 的 className

舉例來說可以這麼做,我們修改 AppComponent 與 index.html 如下:

1
2
3
4
5
6
7
8
9
10
import { Component } from '@angular/core';

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

1
2
3
4
<body>
<!-- <app-root class="app-root"></app-root> -->
<div class="app-root"></div>
</body>

之後回到瀏覽器觀察,發現仍然是可以運行的。

而 HTML 中不管是直接在元件寫上 className 或者是新建一個具有 app-root className 的 div 標籤都是有效果的。

在我們把 selector 修改成 .app-root 後,下方突然多出綠色的蚯蚓,這是因為我使用了 TSLint ,而 TSLint 這個套件是遵照 Angular 官方發布的 Style Guide 規範,這當中就包含了 Component 的 selector 最好都以 element 的 selector 為主。

  • templateUrl - 指這個 AppComponent 的 HTML Template 的所在之處,而這堆內容就是我們在瀏覽器上看到的 HTML 內容

所以我們的每一個 Component 都會有一個相對應的 HTML Template 做搭配,一個負責程式的邏輯、另一個負責呈現於瀏覽器。

  • styleUrls - 指 AppComponent 的 HTML Template 有用到的 CSS 樣式,需要注意的是這裡的樣式預設只針對這個 Component ,並不會與其他 Component 互相衝突,當然這個預設值也是可以調整的。

小結

以上就是 Angular 應用程式的啟動流程,透過這樣的描述能讓自己更加地了解 Angular 的運作過程。

0%