https://cloud.tencent.com/developer/article/1015527?
https://cloud.tencent.com/developer/article/1114057
?2.webpack,里面的webpack.config.js怎么配置
?10. 是否寫過Loader和Plugin?描述一下編寫loader或plugin的思路
?15. 什么是bundle,什么是chunk,什么是module
1. 對webpack的了解
本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler),將項目當作一個整體,通過一個給定的的主文件,webpack將從這個文件開始找到你的項目的所有依賴文件,使用loaders處理它們,最后打包成一個或多個瀏覽器可識別的js文件
核心概念:
- 入口(entry)
入口起點(entry point)
指示 webpack
應該使用哪個模塊,來作為構建其內部依賴圖的開始
可以通過在 webpack
配置中配置 entry
屬性,來指定一個入口起點(或多個入口起點)
module.exports = {
entry: './path/to/my/entry/file.js'
};
- 輸出(output)
output
屬性告訴 webpack
在哪里輸出它所創建的 bundles
,以及如何命名這些文件,默認值為 ./dist
- loader
loader
讓 webpack
能夠去處理那些非 JavaScript
文件(webpack
自身只理解 JavaScript
)
- 插件(plugins)
loader
被用于轉換某些類型的模塊,而插件則可以用于執行范圍更廣的任務。插件的范圍包括,從打包優化和壓縮,一直到重新定義環境中的變量
- 模式
通過選擇 development
或 production
之中的一個,來設置 mode
參數,你可以啟用相應模式下的 webpack
內置的優化
module.exports = {
mode: 'production'
};
WebPack和Grunt和Gulp對比
Webpack可以看做是模塊打包器,把你的代碼轉換成合適的格式供瀏覽器使用;
常用webpack構建本地服務器,可以讓瀏覽器監聽你代碼的修改,自動刷新現實后的結果;
Gulp/Grunt是一種能夠優化前端開發的流程工具,而WebPack是一種模塊化的解決方案;
WebPack有4個配置選項,打包速度越快,負面作用就越大,會不利于調試,文件的執行效率也有一定的影響;開發階段使用:eval-source-map:使用eval打包源文件模塊,在同一個文件中生成干凈的完整的source map。這個選項可以在不影響構建速度的前提下生成完整的sourcemap,但是對打包后輸出的JS文件的執行具有性能和安全的隱患。在開發階段這是一個非常好的選項,在生產階段則一定不要啟用這個選項;
2. webpack,里面的webpack.config.js怎么配置
let webpack = require('webpack');
module.exports = {
entry:'./entry.js', //入口文件
output:{
//node.js中__dirname變量獲取當前模塊文件所在目錄的完整絕對路徑
path:__dirname, //輸出位置
filename:'build.js' //輸入文件
},
module:{
// 關于模塊的加載相關,我們就定義在module.loaders中
// 這里通過正則表達式去匹配不同后綴的文件名,然后給它們定義不同的加載器。
// 比如說給less文件定義串聯的三個加載器(!用來定義級聯關系):
rules:[
{
test:/\.css$/, //支持正則
loader:'style-loader!css-loader'
}
]
},
//配置服務
devServer:{
hot:true, //啟用熱模塊替換
inline:true
//此模式支持熱模塊替換:熱模塊替換的好處是只替換更新的部分,而不是頁面重載.
},
//其他解決方案配置
resolve:{
extensions:['','.js','.json','.css','.scss']
},
//插件
plugins:[
new webpack.BannerPlugin('This file is create by baibai')
]
}
3. webpack本地開發怎么解決跨域的
- 下載 webpack-dev-server 插件
- 配置 webpack.config.js 文件
// webpack.config.js
var WebpackDevServer = require("webpack-dev-server");
module.exports = {
...
devServer: {
...
port: '8088', //設置端口號
// 代理設置
proxy: {
'/api': {
target: 'http://localhost:80/index.php', // 目標代理
pathRewrite: {'^/api' : ''}, // 重寫路徑
secure: false, // 是否接受運行在 HTTPS 上
}
}
}
}
4. 如何配置多入口文件
配置多個入口文件
entry: {
home: resolve(__dirname, "src/home/index.js"),
about: resolve(__dirname, "src/about/index.js")
}
5. webpack與grunt、gulp的不同
三者都是前端構建工具
grunt
和gulp
是基于任務和流的。找到一個(或一類)文件,對其做一系列鏈式操作,更新流上的數據, 整條鏈式操作構成了一個任務,多個任務就構成了整個web的構建流程
webpack
是基于入口的。webpack
會自動地遞歸解析入口所需要加載的所有資源文件,然后用不同的Loader
來處理不同的文件,用Plugin
來擴展webpack
功能
webpack
與前者最大的不同就是支持代碼分割,模塊化(AMD,CommonJ,ES2015),全局分析
6. 有哪些常見的Loader?他們是解決什么問題的
css-loader
:加載CSS
,支持模塊化、壓縮、文件導入等特性style-loader
:把CSS
代碼注入到JavaScript 中
,通過DOM
操作去加載CSS
slint-loader
:通過SLint
檢查JavaScript
代碼babel-loader
:把ES6
轉換成ES5
file-loader
:把文件輸出到一個文件夾中,在代碼中通過相對URL
去引用輸出的文件url-loader
:和file-loader
類似,但是能在文件很小的情況下以base64
的方式把文件內容注入到代碼中去
7. 有哪些常見的Plugin?他們是解決什么問題的
define-plugin
:定義環境變量commons-chunk-plugin
:提取公共代碼
8. Loader和Plugin的不同
- loader 加載器
Webpack
將一切文件視為模塊,但是webpack
原生是只能解析js
文件.Loader
的作用是讓webpack
擁有了加載和解析非JavaScript
文件的能力
在
module.rules
中配置,也就是說他作為模塊的解析規則而存在,類型為數組
- Plugin 插件
擴展
webpack
的功能,讓webpack
具有更多的靈活性
在
plugins
中單獨配置。類型為數組,每一項是一個plugin
的實例,參數都通過構造函數傳入
9. webpack的構建流程是什么
- 初始化參數:從配置文件和
Shell
語句中讀取與合并參數,得出最終的參數 - 開始編譯:用上一步得到的參數初始化
Compiler
對象,加載所有配置的插件,執行對象的run
方法開始執行編譯 - 確定入口:根據配置中的
entry
找出所有的入口文件 - 編譯模塊:從入口文件出發,調用所有配置的
Loader
對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理 - 完成模塊編譯:在經過第4步使用
Loader
翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內容以及它們之間的依賴關系 - 輸出資源:根據入口和模塊之間的依賴關系,組裝成一個個包含多個模塊的
Chunk
,再把每個Chunk
轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最后機會 - 輸出完成:在確定好輸出內容后,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統
在以上過程中,
Webpack
會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件后會執行特定的邏輯,并且插件可以調用Webpack
提供的API
改變Webpack
的運行結果
10. 是否寫過Loader和Plugin?描述一下編寫loader或plugin的思路
編寫
Loader
時要遵循單一原則,每個Loader
只做一種"轉義"工作。 每個Loader
的拿到的是源文件內容(source)
,可以通過返回值的方式將處理后的內容輸出,也可以調用this.callback()
方法,將內容返回給webpack
。 還可以通過this.async()
生成一個callback
函數,再用這個 `callback`` 將處理后的內容輸出出去
相對于
Loader
而言,Plugin
的編寫就靈活了許多。webpack
在運行的生命周期中會廣播出許多事件,Plugin
可以監聽這些事件,在合適的時機通過Webpack
提供的API
改變輸出結果
11. webpack的熱更新是如何做到的?說明其原理
具體可以參考 這里
12. 如何利用webpack來優化前端性能
- 壓縮代碼。刪除多余的代碼、注釋、簡化代碼的寫法等等方式
- 利用
CDN
加速。在構建過程中,將引用的靜態資源路徑修改為CDN
上對應的路徑 - 刪除死代碼
Tree Shaking)
。將代碼中永遠不會走到的片段刪除掉 - 優化圖片,對于小圖可以使用
base64
的方式寫入文件中 - 按照路由拆分代碼,實現按需加載,提取公共代碼
- 給打包出來的文件名添加哈希,實現瀏覽器緩存文件
13. 如何提高webpack的構建速度
參考 這里
14. 怎么配置單頁應用?怎么配置多頁應用
- 單頁應用可以理解為
webpack
的標準模式,直接在entry
中指定單頁應用的入口即可 - 多頁應用的話,可以使用
webpack
的AutoWebPlugin
來完成簡單自動化的構建,但是前提是項目的目錄結構必須遵守他預設的規范
15. 什么是bundle,什么是chunk,什么是module
bundle
是由 webpack
打包出來的文件,chunk
是指 webpack
在進行模塊的依賴分析的時候,代碼分割出來的代碼塊。module
是開發中的單個模塊
webpack自帶的服務器的跨域問題
devServer: {
proxy: {
'/slider': {
target: 'http://www.cherryvenus.com/',
secure: false,
changeOrigin: true//important 能解決大多數404無法訪問的問題
}
}
},
http-proxy-middleware——解決開發中的跨域問題
npm install --save-dev http-proxy-middleware
復制代碼
var proxyMiddleWare = require("http-proxy-middleware");
var proxyPath = "http://www.cherryvenus.com/";
var proxyOption ={target:proxyPath,changeOrigoin:true};
app.use(proxyMiddleWare("/slider",proxyOption))
復制代碼
webpack熱更新原理
https://www.jianshu.com/p/652fbae768bf
https://weibo.com/ttarticle/p/show?id=2309614199044967749267
問題一覽
- webpack與grunt、gulp的不同?
- 與webpack類似的工具還有哪些?談談你為什么最終選擇(或放棄)使用webpack?
- 有哪些常見的Loader?他們是解決什么問題的?
- 有哪些常見的Plugin?他們是解決什么問題的?
- Loader和Plugin的不同?
- webpack的構建流程是什么?從讀取配置到輸出文件這個過程盡量說全
- 是否寫過Loader和Plugin?描述一下編寫loader或plugin的思路?
- webpack的熱更新是如何做到的?說明其原理?
- 如何利用webpack來優化前端性能?(提高性能和體驗)
- 如何提高webpack的構建速度?
- 怎么配置單頁應用?怎么配置多頁應用?
- npm打包時需要注意哪些?如何利用webpack來更好的構建?
- 如何在vue項目中實現按需加載?
問題解答
1. webpack與grunt、gulp的不同?
三者都是前端構建工具,grunt和gulp在早期比較流行,現在webpack相對來說比較主流,不過一些輕量化的任務還是會用gulp來處理,比如單獨打包CSS文件等。
grunt和gulp是基于任務和流(Task、Stream)的。類似jQuery,找到一個(或一類)文件,對其做一系列鏈式操作,更新流上的數據, 整條鏈式操作構成了一個任務,多個任務就構成了整個web的構建流程。
webpack是基于入口的。webpack會自動地遞歸解析入口所需要加載的所有資源文件,然后用不同的Loader來處理不同的文件,用Plugin來擴展webpack功能。
所以總結一下:
- 從構建思路來說
gulp和grunt需要開發者將整個前端構建過程拆分成多個`Task`,并合理控制所有`Task`的調用關系 webpack需要開發者找到入口,并需要清楚對于不同的資源應該使用什么Loader做何種解析和加工
- 對于知識背景來說
gulp更像后端開發者的思路,需要對于整個流程了如指掌 webpack更傾向于前端開發者的思路
2. 與webpack類似的工具還有哪些?談談你為什么最終選擇(或放棄)使用webpack?
同樣是基于入口的打包工具還有以下幾個主流的:
- webpack
- rollup
- parcel
從應用場景上來看:
- webpack適用于大型復雜的前端站點構建
- rollup適用于基礎庫的打包,如vue、react
- parcel適用于簡單的實驗性項目,他可以滿足低門檻的快速看到效果
由于parcel在打包過程中給出的調試信息十分有限,所以一旦打包出錯難以調試,所以不建議復雜的項目使用parcel
3.有哪些常見的Loader?他們是解決什么問題的?
- file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件
- url-loader:和 file-loader 類似,但是能在文件很小的情況下以 base64 的方式把文件內容注入到代碼中去
- source-map-loader:加載額外的 Source Map 文件,以方便斷點調試
- image-loader:加載并且壓縮圖片文件
- babel-loader:把 ES6 轉換成 ES5
- css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
- style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS。
- eslint-loader:通過 ESLint 檢查 JavaScript 代碼
4.有哪些常見的Plugin?他們是解決什么問題的?
- define-plugin:定義環境變量
- commons-chunk-plugin:提取公共代碼
- uglifyjs-webpack-plugin:通過UglifyES壓縮ES6代碼
5.Loader和Plugin的不同?
不同的作用
- Loader直譯為"加載器"。Webpack將一切文件視為模塊,但是webpack原生是只能解析js文件,如果想將其他文件也打包的話,就會用到loader。 所以Loader的作用是讓webpack擁有了加載和解析非JavaScript文件的能力。
- Plugin直譯為"插件"。Plugin可以擴展webpack的功能,讓webpack具有更多的靈活性。 在 Webpack 運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
不同的用法
- Loader在module.rules中配置,也就是說他作為模塊的解析規則而存在。 類型為數組,每一項都是一個Object,里面描述了對于什么類型的文件(test),使用什么加載(loader)和使用的參數(options)
- Plugin在plugins中單獨配置。 類型為數組,每一項是一個plugin的實例,參數都通過構造函數傳入。
6.webpack的構建流程是什么?從讀取配置到輸出文件這個過程盡量說全
Webpack 的運行流程是一個串行的過程,從啟動到結束會依次執行以下流程:
- 初始化參數:從配置文件和 Shell 語句中讀取與合并參數,得出最終的參數;
- 開始編譯:用上一步得到的參數初始化 Compiler 對象,加載所有配置的插件,執行對象的 run 方法開始執行編譯;
- 確定入口:根據配置中的 entry 找出所有的入口文件;
- 編譯模塊:從入口文件出發,調用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理;
- 完成模塊編譯:在經過第4步使用 Loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內容以及它們之間的依賴關系;
- 輸出資源:根據入口和模塊之間的依賴關系,組裝成一個個包含多個模塊的 Chunk,再把每個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最后機會;
- 輸出完成:在確定好輸出內容后,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統。
在以上過程中,Webpack 會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件后會執行特定的邏輯,并且插件可以調用 Webpack 提供的 API 改變 Webpack 的運行結果。
7.是否寫過Loader和Plugin?描述一下編寫loader或plugin的思路?
Loader像一個"翻譯官"把讀到的源文件內容轉義成新的文件內容,并且每個Loader通過鏈式操作,將源文件一步步翻譯成想要的樣子。
編寫Loader時要遵循單一原則,每個Loader只做一種"轉義"工作。 每個Loader的拿到的是源文件內容(source),可以通過返回值的方式將處理后的內容輸出,也可以調用this.callback()方法,將內容返回給webpack。 還可以通過 this.async()生成一個callback函數,再用這個callback將處理后的內容輸出出去。 此外webpack還為開發者準備了開發loader的工具函數集——loader-utils。
相對于Loader而言,Plugin的編寫就靈活了許多。 webpack在運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
8.webpack的熱更新是如何做到的?說明其原理?
webpack的熱更新又稱熱替換(Hot Module Replacement),縮寫為HMR。 這個機制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。
原理:

首先要知道server端和client端都做了處理工作
- 第一步,在 webpack 的 watch 模式下,文件系統中某一個文件發生修改,webpack 監聽到文件變化,根據配置文件對模塊重新編譯打包,并將打包后的代碼通過簡單的 JavaScript 對象保存在內存中。
- 第二步是 webpack-dev-server 和 webpack 之間的接口交互,而在這一步,主要是 dev-server 的中間件 webpack-dev-middleware 和 webpack 之間的交互,webpack-dev-middleware 調用 webpack 暴露的 API對代碼變化進行監控,并且告訴 webpack,將代碼打包到內存中。
- 第三步是 webpack-dev-server 對文件變化的一個監控,這一步不同于第一步,并不是監控代碼變化重新打包。當我們在配置文件中配置了devServer.watchContentBase 為 true 的時候,Server 會監聽這些配置文件夾中靜態文件的變化,變化后會通知瀏覽器端對應用進行 live reload。注意,這兒是瀏覽器刷新,和 HMR 是兩個概念。
- 第四步也是 webpack-dev-server 代碼的工作,該步驟主要是通過 sockjs(webpack-dev-server 的依賴)在瀏覽器端和服務端之間建立一個 websocket 長連接,將 webpack 編譯打包的各個階段的狀態信息告知瀏覽器端,同時也包括第三步中 Server 監聽靜態文件變化的信息。瀏覽器端根據這些 socket 消息進行不同的操作。當然服務端傳遞的最主要信息還是新模塊的 hash 值,后面的步驟根據這一 hash 值來進行模塊熱替換。
- webpack-dev-server/client 端并不能夠請求更新的代碼,也不會執行熱更模塊操作,而把這些工作又交回給了 webpack,webpack/hot/dev-server 的工作就是根據 webpack-dev-server/client 傳給它的信息以及 dev-server 的配置決定是刷新瀏覽器呢還是進行模塊熱更新。當然如果僅僅是刷新瀏覽器,也就沒有后面那些步驟了。
- HotModuleReplacement.runtime 是客戶端 HMR 的中樞,它接收到上一步傳遞給他的新模塊的 hash 值,它通過 JsonpMainTemplate.runtime 向 server 端發送 Ajax 請求,服務端返回一個 json,該 json 包含了所有要更新的模塊的 hash 值,獲取到更新列表后,該模塊再次通過 jsonp 請求,獲取到最新的模塊代碼。這就是上圖中 7、8、9 步驟。
- 而第 10 步是決定 HMR 成功與否的關鍵步驟,在該步驟中,HotModulePlugin 將會對新舊模塊進行對比,決定是否更新模塊,在決定更新模塊后,檢查模塊之間的依賴關系,更新模塊的同時更新模塊間的依賴引用。
- 最后一步,當 HMR 失敗后,回退到 live reload 操作,也就是進行瀏覽器刷新來獲取最新打包代碼。
9.如何利用webpack來優化前端性能?(提高性能和體驗)
用webpack優化前端性能是指優化webpack的輸出結果,讓打包的最終結果在瀏覽器運行快速高效。
- 壓縮代碼。刪除多余的代碼、注釋、簡化代碼的寫法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin來壓縮JS文件, 利用cssnano(css-loader?minimize)來壓縮css
- 利用CDN加速。在構建過程中,將引用的靜態資源路徑修改為CDN上對應的路徑。可以利用webpack對于output參數和各loader的publicPath參數來修改資源路徑
- 刪除死代碼(Tree Shaking)。將代碼中永遠不會走到的片段刪除掉。可以通過在啟動webpack時追加參數--optimize-minimize來實現
- 提取公共代碼。
10.如何提高webpack的構建速度?
- 多入口情況下,使用CommonsChunkPlugin來提取公共代碼
- 通過externals配置來提取常用庫
- 利用DllPlugin和DllReferencePlugin預編譯資源模塊 通過DllPlugin來對那些我們引用但是絕對不會修改的npm包來進行預編譯,再通過DllReferencePlugin將預編譯的模塊加載進來。
- 使用Happypack 實現多線程加速編譯
- 使用webpack-uglify-parallel來提升uglifyPlugin的壓縮速度。 原理上webpack-uglify-parallel采用了多核并行壓縮來提升壓縮速度
- 使用Tree-shaking和Scope Hoisting來剔除多余代碼
11.怎么配置單頁應用?怎么配置多頁應用?
單頁應用可以理解為webpack的標準模式,直接在entry中指定單頁應用的入口即可,這里不再贅述
多頁應用的話,可以使用webpack的 AutoWebPlugin來完成簡單自動化的構建,但是前提是項目的目錄結構必須遵守他預設的規范。 多頁應用中要注意的是:
- 每個頁面都有公共的代碼,可以將這些代碼抽離出來,避免重復的加載。比如,每個頁面都引用了同一套css樣式表
- 隨著業務的不斷擴展,頁面可能會不斷的追加,所以一定要讓入口的配置足夠靈活,避免每次添加新頁面還需要修改構建配置
12.npm打包時需要注意哪些?如何利用webpack來更好的構建?
Npm是目前最大的 JavaScript 模塊倉庫,里面有來自全世界開發者上傳的可復用模塊。你可能只是JS模塊的使用者,但是有些情況你也會去選擇上傳自己開發的模塊。 關于NPM模塊上傳的方法可以去官網上進行學習,這里只講解如何利用webpack來構建。
NPM模塊需要注意以下問題:
- 要支持CommonJS模塊化規范,所以要求打包后的最后結果也遵守該規則。
- Npm模塊使用者的環境是不確定的,很有可能并不支持ES6,所以打包的最后結果應該是采用ES5編寫的。并且如果ES5是經過轉換的,請最好連同SourceMap一同上傳。
- Npm包大小應該是盡量小(有些倉庫會限制包大小)
- 發布的模塊不能將依賴的模塊也一同打包,應該讓用戶選擇性的去自行安裝。這樣可以避免模塊應用者再次打包時出現底層模塊被重復打包的情況。
- UI組件類的模塊應該將依賴的其它資源文件,例如.css文件也需要包含在發布的模塊里。
基于以上需要注意的問題,我們可以對于webpack配置做以下擴展和優化:
- CommonJS模塊化規范的解決方案: 設置output.libraryTarget='commonjs2'使輸出的代碼符合CommonJS2 模塊化規范,以供給其它模塊導入使用
- 輸出ES5代碼的解決方案:使用babel-loader把 ES6 代碼轉換成 ES5 的代碼。再通過開啟devtool: 'source-map'輸出SourceMap以發布調試。
- Npm包大小盡量小的解決方案:Babel 在把 ES6 代碼轉換成 ES5 代碼時會注入一些輔助函數,最終導致每個輸出的文件中都包含這段輔助函數的代碼,造成了代碼的冗余。解決方法是修改.babelrc文件,為其加入transform-runtime插件
- 不能將依賴模塊打包到NPM模塊中的解決方案:使用externals配置項來告訴webpack哪些模塊不需要打包。
- 對于依賴的資源文件打包的解決方案:通過css-loader和extract-text-webpack-plugin來實現,配置如下:

13.如何在vue項目中實現按需加載?
Vue UI組件庫的按需加載 為了快速開發前端項目,經常會引入現成的UI組件庫如ElementUI、iView等,但是他們的體積和他們所提供的功能一樣,是很龐大的。 而通常情況下,我們僅僅需要少量的幾個組件就足夠了,但是我們卻將龐大的組件庫打包到我們的源碼中,造成了不必要的開銷。
不過很多組件庫已經提供了現成的解決方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安裝以上插件后,在.babelrc配置中或babel-loader的參數中進行設置,即可實現組件按需加載了。

單頁應用的按需加載 現在很多前端項目都是通過單頁應用的方式開發的,但是隨著業務的不斷擴展,會面臨一個嚴峻的問題——首次加載的代碼量會越來越多,影響用戶的體驗。
通過import(*)語句來控制加載時機,webpack內置了對于import(*)的解析,會將import(*)中引入的模塊作為一個新的入口在生成一個chunk。 當代碼執行到import(*)語句時,會去加載Chunk對應生成的文件。import()會返回一個Promise對象,所以為了讓瀏覽器支持,需要事先注入Promise polyfill