談談webpack?
webpack是一個模塊打包工具,可使用它管理項目中的模塊依賴,並編譯輸出模塊所需的靜態文件。它能夠很好地管理、打包開發中所用到的HTML,CSS,JavaScript和靜態文件(圖片,字體)等,讓開發更高效。對於不一樣類型的依賴,webpack有對應的模塊加載器,並且會分析模塊間的依賴關係,最後合併生成優化的靜態資源。css
webpack的基本功能和工做原理?
代碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等等
文件優化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合並圖片等
代碼分割:提取多個頁面的公共代碼、提取首屏不須要執行部分的代碼讓其異步加載
模塊合併:在採用模塊化的項目有不少模塊和文件,須要構建功能把模塊分類合併成一個文件
自動刷新:監聽本地源代碼的變化,自動構建,刷新瀏覽器
代碼校驗:在代碼被提交到倉庫前須要檢測代碼是否符合規範,以及單元測試是否經過
自動發佈:更新完代碼後,自動構建出線上發佈代碼並傳輸給發佈系統。html
webpack構建過程:
entry裏配置的module開始遞歸解析entry依賴的全部module, 每找到一個module,就會根據配置的loader去找對應的轉換規則。前端
對module進行轉換後,再解析出當前module依賴的module 這些模塊會以entry爲單位分組,一個entry和其全部依賴的module被分到一個組Chunk。webpack
最後webpack會把全部Chunk轉換成文件輸出 在整個流程中webpack會在恰當的時機執行plugin裏定義的邏輯web
webpack打包原理:
將全部依賴打包成一個bundle.js,經過代碼分割成單元片斷按需加載。npm
什麼是entry,output?
entry 入口,告訴webpack要使用哪一個模塊做爲構建項目的起點,默認爲./src/index.js
output 出口,告訴webpack在哪裏輸出它打包好的代碼以及如何命名,默認爲./distjson
什麼是bundle,chunk,module?
- bundle是webpack打包出來的文件
- chunk是webpack在進行模塊的依賴分析的時候,代碼分割出來的代碼塊
- module是開發中的單個模塊
npm打包時須要注意哪些?如何利用webpack來更好的構建?
哪些常見的Loader?他們是解決什麼問題的?
file-loader:把文件輸出到一個文件夾中,在代碼中經過相對 URL 去引用輸出的文件;gulp
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 代碼;
webpack規範
webpack默認遵循commonjs規範 module.exports
使用webpack進行打包時有兩種模式:
- 模式:主要是用於測試,代碼調試等;
- 模式:要考慮性能問題,要壓縮 若是沒有插件 就不會壓縮;
默認狀況下webpack的配置文件叫webpack.config.js,能夠經過--config指定webpack的配置文件名
loader
css須要兩個loader來處理:css-loader style-loader
postcss-loader 他提供了一種方式用 JavaScript 代碼來處理 CSS。它負責把 CSS 代碼解析成抽象語法樹結構(Abstract Syntax Tree,AST),再交由插件來進行處理。
-webkit-transform: rotate(45deg); transform: rotate(45deg);
mini-css-extract-plugin 之前都是之間引入內部樣式,把css專門打包成一個css文件,在index.html文件中引入css
optimize-css-assets-webpack-plugin css壓縮
terser-webpack-plugin css壓縮 js不能壓縮了,而後有一個插件,能壓縮js
file-loader 是讓webpack打包圖片
url-loader可讓圖片轉化base64,也可讓webpack打包圖片
webpack 默認狀況下不支持js的高級語法,因此須要使用babel;
babel轉化; npm i @babel/core @babel/preset-env babel-loader --save-dev
plugins:
html-webpack-plugin 根據模塊生成一個html文件 此時不會在dist文件夾下面新建index文件了
我須要在public新建 index文件
根據這個模板文件 在內存中生成 index.html 而後自動引入bundle.js
clean-webpack-plugin 去掉沒有用到的模塊
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更傾向於前端開發者的思路
有哪些常見的Plugin?他們是解決什麼問題的?
- define-plugin:定義環境變量
- commons-chunk-plugin:提取公共代碼
- uglifyjs-webpack-plugin:經過UglifyES壓縮ES6代碼
什麼是loader,plugins,區別?
不一樣的做用
- 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的實例,參數都經過構造函數傳入。
webpack的構建流程是什麼?從讀取配置到輸出文件這個過程?
Webpack 的運行流程是一個串行的過程,從啓動到結束會依次執行如下流程:
- 初始化參數:從配置文件和 Shell 語句中讀取與合併參數,得出最終的參數;
- 開始編譯:用上一步獲得的參數初始化 Compiler 對象,加載全部配置的插件,執行對象的 run 方法開始執行編譯;
- 肯定入口:根據配置中的 entry 找出全部的入口文件;
- 編譯模塊:從入口文件出發,調用全部配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到全部入口依賴的文件都通過了本步驟的處理;
- 完成模塊編譯:在通過第4步使用 Loader 翻譯完全部模塊後,獲得了每一個模塊被翻譯後的最終內容以及它們之間的依賴關係;
- 輸出資源:根據入口和模塊之間的依賴關係,組裝成一個個包含多個模塊的 Chunk,再把每一個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是能夠修改輸出內容的最後機會;
- 輸出完成:在肯定好輸出內容後,根據配置肯定輸出的路徑和文件名,把文件內容寫入到文件系統。
在以上過程當中,Webpack 會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件後會執行特定的邏輯,而且插件能夠調用 Webpack 提供的 API 改變 Webpack 的運行結果。
是否寫過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 改變輸出結果。
webpack的熱更新是如何作到的?說明其原理?
webpack的熱更新又稱熱替換(Hot Module Replacement),縮寫爲HMR。 這個機制能夠作到不用刷新瀏覽器而將新變動的模塊替換掉舊的模塊。
原理:
![webpack-hmr.png webpack-hmr.png](http://static.javashuo.com/static/loading.gif)
首先要知道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 請求,獲取到最新的模塊代碼。這就是上圖中 七、八、9 步驟。
- 而第 10 步是決定 HMR 成功與否的關鍵步驟,在該步驟中,HotModulePlugin 將會對新舊模塊進行對比,決定是否更新模塊,在決定更新模塊後,檢查模塊之間的依賴關係,更新模塊的同時更新模塊間的依賴引用。
- 最後一步,當 HMR 失敗後,回退到 live reload 操做,也就是進行瀏覽器刷新來獲取最新打包代碼。
webpack來優化前端性能?(提升性能和體驗)
用webpack優化前端性能是指優化webpack的輸出結果,讓打包的最終結果在瀏覽器運行快速高效。
- 代碼。刪除多餘的代碼、註釋、簡化代碼的寫法等等方式。能夠利用webpack的UglifyJsPlugin和ParallelUglifyPlugin來壓縮JS文件, 利用cssnano(css-loader?minimize)來壓縮css
- CDN加速。在構建過程當中,將引用的靜態資源路徑修改成CDN上對應的路徑。能夠利用webpack對於output參數和各loader的publicPath參數來修改資源路徑
- 死代碼(Tree Shaking)。將代碼中永遠不會走到的片斷刪除掉。能夠經過在啓動webpack時追加參數--optimize-minimize來實現
- 公共代碼。
如何提升webpack的構建速度?
- 多入口狀況下,使用CommonsChunkPlugin來提取公共代碼
- 經過externals配置來提取經常使用庫
- 利用DllPlugin和DllReferencePlugin預編譯資源模塊 經過DllPlugin來對那些咱們引用可是絕對不會修改的npm包來進行預編譯,再經過DllReferencePlugin將預編譯的模塊加載進來。
- 使用Happypack 實現多線程加速編譯
- 使用webpack-uglify-parallel來提高uglifyPlugin的壓縮速度。 原理上webpack-uglify-parallel採用了多核並行壓縮來提高壓縮速度
- 使用Tree-shaking和Scope Hoisting來剔除多餘代碼
怎麼配置單頁應用?怎麼配置多頁應用?
單頁應用能夠理解爲webpack的標準模式,直接在entry中指定單頁應用的入口便可,這裏再也不贅述
多頁應用的話,可使用webpack的 AutoWebPlugin來完成簡單自動化的構建,可是前提是項目的目錄結構必須遵照他預設的規範。 多頁應用中要注意的是:
- 每一個頁面都有公共的代碼,能夠將這些代碼抽離出來,避免重複的加載。好比,每一個頁面都引用了同一套css樣式表
- 隨着業務的不斷擴展,頁面可能會不斷的追加,因此必定要讓入口的配置足夠靈活,避免每次添加新頁面還須要修改構建配置