前言
當我們透過 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 按右鍵 > 檢視網頁原始碼
首先我們看到一個
接著是
然後發現 之前被插入了剛剛編譯出來的 .js 檔,而 Angular 應用程式也在載入這些 .js 檔後正式開始運行。
然而執行的過程中,也有一個啟動的流程。
啟動的流程結束後,
對著 index.html 按右鍵 > 檢查
從 chrome 的開發者工具底下,可以看到
因為這些內容全部都是透過 Angular 應用程式動態運算出來的結果。
實際觀察專案內的 index.html 檔案
這支檔案也就是剛才 chrome 瀏覽器開啟的檔案,而裡面確實有個
可以發現檔案內的
標籤內並沒有插入剛才那些 .js 檔,也就是說那是 Webpack 幫我們編譯後動態插入的。也就是說我們在開發 Angular 網頁時,它的 JavaScript 在開發時期是動態被注入的。
從哪支 .js 檔開始跑呢?
之前有提過, Angular 應用程式的進入點是 main.ts 檔案,而它的長相如下:
1 | import { enableProdMode } from '@angular/core'; |
前面 5 行主要是引用從某一些模組匯入程式運行時必要的物件進來。
而第 11 行的地方,則是透過 platformBrowserDynamic().bootstrapModule(AppModule)
去執行啟動模組這件事,接著會進入到 AppModule
裡面執行相關的程式碼,讓我們一起觀察下去吧。
小提示:在 VSCode 內可以對著
AppModule
點一下接著按 F12 會自動追蹤到該檔案喔
AppModule 內
1 | import { BrowserModule } from '@angular/platform-browser'; |
這支檔案可以說是在 Angular 應用程式裡面最重要的一支程式,而程式碼結構不難看出它是一個
class
而且被 export 出來,神奇的是裡面沒有任何的程式碼。
在大部分的情況,我們寫 Angular 應用程式時確實是不需要寫程式在裡面的。
我們只需要套用一個 declarator
,而這個 declarator
要設定成 NgModule
,去宣告這個類別它是一個 Angular 的 Module ,然後我們在這個 Module 裡面又有好幾個 Property (屬性) 需要宣告:
- declarations - 用來宣告一些跟 view 有關的元件
- imports - 用來匯入一些跟這個模組會用到的其他模組,而模組說穿了就是多個元件封裝後的東西
- 而
BrowserModule
就是把BrowserModule
內所有的元件一起匯入進來的意思
- 而
- providers - 註冊服務的提供者
- bootstrap - 啟動根元件
AppComponent
,也就是 Angular 最上層的元件 (預設名稱為AppComponent
)
接著我們使用剛才介紹的追蹤方式,繼續追蹤 AppComponent
AppComponent 內
1 | import { Component } from '@angular/core'; |
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 | import { Component } from '@angular/core'; |
1 | <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 的運作過程。