Angular 4 教學- Webpack 預先編譯Ahead-of-Time (AOT)

文章推薦指數: 80 %
投票人數:10人

Ahead-of-Time (AOT) 預先編譯,是在程式發佈之前就透過Angular Compiler 進行編譯,所以瀏覽器下載完的 *.js 檔案,就可以直接被執行,然後渲染畫面 ... HomeCategoriesTagsArchives之前用Angular4(Angular2)開發後台系統,使用者都是在PC上面使用,網站啟動速度都很快,所以沒有使用到Ahead-of-Time(AOT)預先編譯的需求。

最近新產品上線,遇到很多Android的使用者開啟網站超級慢,舊一點的機型甚至開一分鐘才有畫面。

事後才趕緊補上AOT編譯。

本篇將介紹用Webpack預先編譯AOT編譯。

AOTvsJIT開發Angular所撰寫的TypeScript透過TypeScriptCompiler產生出來的*.js檔,是屬於Angular的SourceCode,必須經由AngularCompiler,才能在瀏覽器中執行。

而AngularCompiler可以在兩個不同的階段進行編譯:Just-in-Time(JIT)Angular預設是使用Just-in-Time(JIT)即時編譯,等瀏覽器下載完*.js檔案後,會在用戶端的瀏覽器編譯Angular的JS程式碼,接著才會渲染畫面。

優點:*.js檔案是Angular的原始碼,所以檔案較小。

缺點:在用戶端的瀏覽器編譯,所以網站啟動速度會較慢。

Ahead-of-Time(AOT)Ahead-of-Time(AOT)預先編譯,是在程式發佈之前就透過AngularCompiler進行編譯,所以瀏覽器下載完的*.js檔案,就可以直接被執行,然後渲染畫面。

優點:減少掉了在用戶端的瀏覽器編譯的時間,所以網站啟動速度會較快。

缺點:由於*.js是經過編譯後的檔案,所以檔案會較大。

範例程式碼我用之前Angular4教學-從頭開始的範例延伸。

初始結構檔案結構如下:12345678910index.html#起始頁面package.json#npm套件設定檔systemjs.config.js#systemjs設定檔tsconfig.json#TypeScript設定檔app/#Angular4的主要目錄main.ts#bootstrap的程式進入點app.module.ts#bootstrap的第一個module(e.g.AppModule)app.component.html#app.component用到的templateapp.component.ts#AppModulebootstrap的第一個component(e.g.AppComponent)node_modules/#npm套件存放位置安裝Webpack套件安裝Webpack及接下來範例打包所需的開發套件,指令如下:1npminstall--save-devwebpackangular2-template-loaderawesome-typescript-loaderraw-loaderWebpack設定新增webpack.config.js123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354varwebpack=require("webpack");module.exports={cache:true,entry:{"bundle":[__dirname+"/app/main.ts"],"bundle-vendors":["core-js","zone.js","rxjs","@angular/core","@angular/common","@angular/compiler","@angular/platform-browser","@angular/platform-browser-dynamic","@angular/http","@angular/router","@angular/forms"]},output:{path:__dirname+"/js",filename:"[name].js",sourceMapFilename:"[name].map"},resolve:{extensions:[".ts",".js",".html"]},module:{loaders:[{test:/\.ts$/,loaders:["awesome-typescript-loader","angular2-template-loader"],exclude:/(node_modules)/},{test:/\.html$/,loader:"raw-loader"}]},plugins:[newwebpack.optimize.UglifyJsPlugin(),newwebpack.optimize.CommonsChunkPlugin({name:"bundle-vendors"}),newwebpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/,__dirname+"./app")]}執行webpack打包指令如下:1webpack-p修改index.html參考*.js的位置:12345678910111213141516

MyAngular4 Loading...打開網頁用瀏覽器的開發工具,看到bundle-vendors.js及bundle.js檔案大小及載入時間:到目前為止,只是改成用Webpack打包Angular的SourceCode,所以還只是JIT編譯。

由於本篇範例實在是太簡單了,看到載入的速度很快,才400/ms左右。

安裝AOT套件AOT編譯所需的套件,除了bundle-vendors設定中的11個套件,還需要額外安裝@angular/compiler-cli及@angular/platform-server,指令如下:1npminstall--save@angular/compiler-cli@angular/platform-serverTypeScript設定編輯tsconfig.json,設定AOT編譯後的檔案輸出位置:123456789101112131415161718192021222324{"compilerOptions":{"emitDecoratorMetadata":true,"experimentalDecorators":true,"lib":["es2015","dom"],"module":"commonjs","moduleResolution":"node","noImplicitAny":true,"sourceMap":true,"suppressImplicitAnyIndexErrors":true,"target":"es5","watch":true},"exclude":["node_modules"],"files":["app/app.module.ts"],"angularCompilerOptions":{"genDir":"aot","skipMetadataEmit":true}}基本上tsconfig.json的設定跟原本差不多,新增了files及angularCompilerOptions。

files指定Module的位置,如果是LazyLoading,這邊就要加入所有LazyLoading的Module。

genDir指定AOT編譯後的檔案輸出位置。

我的範例程式中,為了保留AOT及JIT的差異,所以另外新增了一個tsconfig-aot.json的檔案,並保留原本的tsconfig.json。

AOT編譯套件安裝完也設定完成後,就可以用ngc指令進行AOT編譯:1node_modules/.bin/ngc-ptsconfig-aot.json編譯成功後,檔案結構如下:1234567891011121314151617index.html#起始頁面package.json#npm套件設定檔systemjs.config.js#systemjs設定檔tsconfig.json#TypeScript設定檔app/#Angular4的主要目錄main.ts#bootstrap的程式進入點app.module.ts#bootstrap的第一個module(e.g.AppModule)app.component.html#app.component用到的templateapp.component.ts#AppModulebootstrap的第一個component(e.g.AppComponent)node_modules/#npm套件存放位置aot/app/app.module.ngfactory.ts#跟app.module.ts對應的ngfactory檔案app.module.ngsummary.json#跟app.module.ts對應的ngsummary檔案app.component.ngfactory.ts#跟app.component.ts對應的ngfactory檔案app.component.ngsummary.json#跟app.component.ts對應的ngsummary檔案node_modules/#aot檔案用到的npm套件更新程式進入點編輯main.ts123456789//JIT啟動AppModule用法//import{platformBrowserDynamic}from"@angular/platform-browser-dynamic";//import{AppModule}from"./app.module";//platformBrowserDynamic().bootstrapModule(AppModule);//AOT啟動AppModule用法import{platformBrowser}from"@angular/platform-browser";import{AppModuleNgFactory}from"../aot/app/app.module.ngfactory";platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);由於AppModule已經透過AOT編譯成AppModuleNgFactory,所以載入Module不再使用platformBrowserDynamic動態載入,改為用platformBrowser載入AppModuleNgFactory。

再次執行Webpack打包後,打開網頁用瀏覽器的開發工具,看到bundle-vendors.js及bundle.js檔案大小及載入時間:可以看到bundle.js的檔案大小差異非常的大,從原本的1.8KB變成4.6KB。

頁面載入速度稍微快了一點,從原本的400/ms變為250/ms左右,因為範例太簡單,所以速度差的沒有很多。

但隨著系統規模越做越大及程式複雜度提升,速度就會有非常明顯的差異。

bundle-vendors.js變小是因為我把@angular/*移除了。

補充換成用Webpack打包後,npm套件systemjs就用不到了,可以從package.json中移除,或用指令移除:1npmuninstallsystemjs--savesystem.config.js也可以隨之移除。

改成用AOT編譯後,前端不再需要動態編譯,所以在bundle-vendors中可以把@angular/*移除:1234567891011121314151617181920varwebpack=require("webpack");module.exports={entry:{"bundle-vendors":["core-js","zone.js","rxjs",//"@angular/core",//"@angular/common",//"@angular/compiler",//"@angular/platform-browser",//"@angular/platform-browser-dynamic",//"@angular/http",//"@angular/router",//"@angular/forms"]},//...}建議根據我的經驗以及網路上的資訊,PC及iPhone在執行AngularJIT編譯時,速度都還算蠻快的,而且差異不太大。

而Android不論是新舊機型或任何瀏覽器,執行AngularJIT編譯的速度都明顯比PC及iPhone慢,舊一點的機型甚至開一分鐘才有畫面。

類似的問題:angular2loadingslowonandroid(haduselazyloading)所以,如果產品需要支援手機或嵌入式裝置等,建議一開始就使用AOT。

如果只需要支援PC版,用JIT會較省下載速度及流量,可以比較不用擔心啟動效率問題。

程式碼下載my-angular-aot參考Ahead-of-TimeCompilationAngular2AOTwithWebpackandLazyLoadingangular2loadingslowonandroid(haduselazyloading)AngularTypeScriptWebpackAOTnext:IIS-HTTP405錯誤prev:C#-constvsstaticreadonly正在培養寫技術部落格的Web工程師,擅長ASP.NETMVC/WebAPI2、.NETCore、Angular網站開發,也略懂ELKstack及Jenkins應用。

目前正在學習敏捷軟體開發及Scrum。

AOTvsJITJust-in-Time(JIT)Ahead-of-Time(AOT)範例程式碼安裝Webpack套件Webpack設定執行webpack安裝AOT套件TypeScript設定AOT編譯更新程式進入點補充建議程式碼下載參考MicrosoftMVP2018-2020VisualStudioandDevelopmentTechnologies大內攻城-SoftwareEngineeringin.NET2020-12-25數學練習小程式2020-01-16.NETCore-在Mac開發階段發生ObjectDisposedException2019-10-29ASP.NETCore3系列-注入多個相同的介面(Interface)2019-10-29ASP.NETCore3系列-自行建置ServiceProvider2019-10-28ASP.NETCore3系列-程式進入點Main方法取得DI註冊的Services大內攻城粉絲團吳吉米-YouTube技術頻道Blackie-FailedNotesLarry-LevelupYowko-Yowko'sNotesJames-詹爸的隨手筆記Bruno-饅頭小舖MaxW.-RetrySamXiao-資料探索世界


請為這篇文章評分?