1、webpack的作用是什么,談談你對它的理解?
現在的前端網頁功能豐富,特別是SPA(single page web application 單頁應用)技術流行后,JavaScript的復雜度增加和需要一大堆依賴包,還需要解決Scss,Less……新增樣式的擴展寫法的編譯工作。
所以現代化的前端已經完全依賴于webpack的輔助了。
現在最流行的三個前端框架,可以說和webpack已經緊密相連,框架官方都推出了和自身框架依賴的webpack構建工具。
react.js+WebPack
vue.js+WebPack
AngluarJS+WebPack
2、webpack的工作原理?
WebPack可以看做是模塊打包機:它做的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Sass,TypeScript等),并將其轉換和打包為合適的格式供瀏覽器使用。在3.0出現后,Webpack還肩負起了優化項目的責任。
3、webpack打包原理
把一切都視為模塊:不管是 css、JS、Image 還是 html 都可以互相引用,通過定義 entry.js,對所有依賴的文件進行跟蹤,將各個模塊通過 loader 和 plugins 處理,然后打包在一起。
按需加載:打包過程中 Webpack 通過 Code Splitting 功能將文件分為多個 chunks,還可以將重復的部分單獨提取出來作為 commonChunk,從而實現按需加載。把所有依賴打包成一個 bundle.js 文件,通過代碼分割成單元片段并按需加載
4、webpack的核心概念
Entry:入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。告訴webpack要使用哪個模塊作為構建項目的起點,默認為./src/index.js
output :出口,告訴webpack在哪里輸出它打包好的代碼以及如何命名,默認為./dist
Module:模塊,在 Webpack 里一切皆模塊,一個模塊對應著一個文件。Webpack 會從配置的 Entry 開始遞歸找出所有依賴的模塊。
Chunk:代碼塊,一個 Chunk 由多個模塊組合而成,用于代碼合并與分割。
Loader:模塊轉換器,用于把模塊原內容按照需求轉換成新內容。
Plugin:擴展插件,在 Webpack 構建流程中的特定時機會廣播出對應的事件,插件可以監聽這些事件的發生,在特定時機做對應的事情。
5、Webpack的基本功能有哪些?
代碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等等
文件優化:壓縮 JavaScript、CSS、html 代碼,壓縮合并圖片等
代碼分割:提取多個頁面的公共代碼、提取首屏不需要執行部分的代碼讓其異步加載
模塊合并:在采用模塊化的項目有很多模塊和文件,需要構建功能把模塊分類合并成一個文件
自動刷新:監聽本地源代碼的變化,自動構建,刷新瀏覽器
代碼校驗:在代碼被提交到倉庫前需要檢測代碼是否符合規范,以及單元測試是否通過
自動發布:更新完代碼后,自動構建出線上發布代碼并傳輸給發布系統。
6、gulp/grunt 與 webpack的區別是什么?
三者都是前端構建工具,grunt和gulp在早期比較流行,現在webpack相對來說比較主流,不過一些輕量化的任務還是會用gulp來處理,比如單獨打包CSS文件等。
grunt和gulp是基于任務和流(Task、Stream)的。
類似jQuery,找到一個(或一類)文件,對其做一系列鏈式操作,更新流上的數據, 整條鏈式操作構成了一個任務,多個任務就構成了整個web的構建流程。
webpack是基于入口的。
webpack會自動地遞歸解析入口所需要加載的所有資源文件,然后用不同的Loader來處理不同的文件,用Plugin來擴展webpack功能。
7、webpack是解決什么問題而生的?
如果像以前開發時一個html文件可能會引用十幾個js文件,而且順序還不能亂,因為它們存在依賴關系,同時對于ES6+等新的語法,less, sass等CSS預處理都不能很好的解決……,此時就需要一個處理這些問題的工具。
8、你是如何提高webpack構件速度的?
多入口情況下,使用CommonsChunkPlugin來提取公共代碼
通過externals配置來提取常用庫
利用DllPlugin和DllReferencePlugin預編譯資源模塊通過DllPlugin來對那些我們
引用但是絕對不會修改的npm包來進行預編譯,再通過DllReferencePlugin將預編譯的模塊加載進來。
使用Happypack 實現多線程加速編譯
使用webpack-uglify-paralle來提升uglifyPlugin的壓縮速度。
原理上webpack-uglify-parallel采用了多核并行壓縮來提升壓縮速度
使用Tree-shaking和Scope Hoisting來剔除多余代碼
9、npm打包時需要注意哪些?如何利用webpack來更好的構建?
Npm是目前最大的 JavaScript 模塊倉庫,里面有來自全世界開發者上傳的可復用模塊。
你可能只是JS模塊的使用者,但是有些情況你也會去選擇上傳自己開發的模塊。
關于NPM模塊上傳的方法可以去官網上進行學習,這里只講解如何利用webpack來構建。
NPM模塊需要注意以下問題:
要支持CommonJS模塊化規范,所以要求打包后的最后結果也遵守該規則。
Npm模塊使用者的環境是不確定的,很有可能并不支持ES6,所以打包的最后結果應該是采用ES5編寫的。并且如果ES5是經過轉換的,請最好連同SourceMap一同上傳。
Npm包大小應該是盡量?。ㄓ行﹤}庫會限制包大?。?/span>
發布的模塊不能將依賴的模塊也一同打包,應該讓用戶選擇性的去自行安裝。這樣可以避免模塊應用者再次打包時出現底層模塊被重復打包的情況。
UI組件類的模塊應該將依賴的其它資源文件,例如.css文件也需要包含在發布的模塊里。
10、前端為什么要進行打包和構建?
代碼層面:
體積更?。═ree-shaking、壓縮、合并),加載更快
編譯高級語言和語法(TS、ES6、模塊化、scss)
兼容性和錯誤檢查(polyfill,postcss,eslint)
研發流程層面:
統一、高效的開發環境
統一的構建流程和產出標準
集成公司構建規范(提測、上線)
11、webpack的構建流程是什么?從讀取配置到輸出文件這個過程盡量說全。
Webpack 的運行流程是一個串行的過程,從啟動到結束會依次執行以下流程:
初始化參數:從配置文件和 Shell 語句中讀取與合并參數,得出最終的參數;
開始編譯:用上一步得到的參數初始化 Compiler 對象,加載所有配置的插件,執行對象的 run 方法開始執行編譯;
確定入口:根據配置中的 entry 找出所有的入口文件;
編譯模塊:從入口文件出發,調用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理;
完成模塊編譯:在經過第4步使用 Loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內容以及它們之間的依賴關系;
輸出資源:根據入口和模塊之間的依賴關系,組裝成一個個包含多個模塊的 Chunk,再把每個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最后機會;
輸出完成:在確定好輸出內容后,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統。
在以上過程中,Webpack 會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件后會執行特定的邏輯,并且插件可以調用 Webpack 提供的 API 改變 Webpack 的運行結果。
12、怎么配置單頁應用?怎么配置多頁應用?
單頁應用可以理解為webpack的標準模式,直接在entry中指定單頁應用的入口即可,這里不再贅述
多頁應用的話,可以使用webpack的 AutoWebPlugin來完成簡單自動化的構建,但是前提是項目的目錄結構必須遵守他預設的規范。多頁應用中要注意的是:
每個頁面都有公共的代碼,可以將這些代碼抽離出來,避免重復的加載。比如,每個頁面都引用了同一套css樣式表
隨著業務的不斷擴展,頁面可能會不斷的追加,所以一定要讓入口的配置足夠靈活,避免每次添加新頁面還需要修改構建配置
13、Loader機制的作用是什么?
webpack默認只能打包js文件,配置里的module.rules數組配置了一組規則,告訴 Webpack 在遇到哪些文件時使用哪些 Loader 去加載和轉換打包成js。
注意:
use屬性的值需要是一個由 Loader 名稱組成的數組,Loader 的執行順序是由后到前的;
每一個 Loader 都可以通過 URL querystring 的方式傳入參數,例如css-loader?minimize中的minimize告訴css-loader要開啟 CSS 壓縮。
14、常用loader
css-loader讀取 合并CSS 文件
style-loader把 CSS 內容注入到 JavaScript 里
sass-loader 解析sass文件(安裝sass-loader,node-sass)
postcss-loader自動添加瀏覽器兼容前綴(postcss.config配置)
url-loader將文件轉換為base64 URI。
vue-loader處理vue文件。
15、Plugin(插件)的作用是什么?
Plugin 是用來擴展 Webpack 功能的,通過在構建流程里注入鉤子實現,它給 Webpack 帶來了很大的靈活性。
Webpack 是通過plugins屬性來配置需要使用的插件列表的。plugins屬性是一個數組,里面的每一項都是插件的一個實例,在實例化一個組件時可以通過構造函數傳入這個組件支持的配置屬性。
16、什么是bundle,什么是chunk,什么是module
bundle:是由webpack打包出來的文件
chunk:是指webpack在進行模塊依賴分析的時候,代碼分割出來的代碼塊
module:是開發中的單個模塊
17、常見Plugins
HtmlWbpackPlugin自動在打包結束后生成html文件,并引入bundle.js
cleanwebPackPlugin打包自動刪除上次打包文件
18、ExtractTextPlugin插件的作用
ExtractTextPlugin插件的作用是提取出 JavaScript 代碼里的 CSS 到一個單獨的文件。
對此你可以通過插件的filename屬性,告訴插件輸出的 CSS 文件名稱是通過[name]_[contenthash:8].css字符串模版生成的,里面的[name]代表文件名稱,[contenthash:8]代表根據文件內容算出的8位 hash 值, 還有很多配置選項可以在ExtractTextPlugin的主頁上查到。
19、sourceMap
是一個映射關系,將打包后的文件隱射到源代碼,用于定位報錯位置
配置方式:
例如:devtool:‘source-map’
加不同前綴意義:
inline:不生成映射關系文件,打包進main.js
cheap: 1.只精確到行,不精確到列,打包速度快 2.只管業務代碼,不管第三方模塊
module:不僅管業務代碼,而且管第三方代碼
eval:執行效率最快,性能最好
最佳實踐:
開發環境:cheap-module-eval-source-map
線上環境:cheap-mudole-source-map
20、HMR熱模塊更新
借助webpack.HotModuleReplacementPlugin(),devServer開啟hot
場景1:實現只刷新css,不影響js
場景2:js中實現熱更新,只更新指定js模塊
if (module.hot) { module.hot.accept(’./library.js’, function() { // Do something with the updated library module… });}
21、webpack如何配置多入口文件?
entry: { home: resolve(__dirname, "src/home/index.js"), about: resolve(__dirname, "src/about/index.js")}
用于描述入口的對象。你可以使用如下屬性:
dependOn: 當前入口所依賴的入口。它們必須在該入口被加載前被加載。
filename: 指定要輸出的文件名稱。
import: 啟動時需加載的模塊。
library: 指定 library 選項,為當前 entry 構建一個 library。
runtime: 運行時 chunk 的名字。如果設置了,就會創建一個新的運行時 chunk。在 webpack 5.43.0 之后可將其設為 false 以避免一個新的運行時 chunk。
publicPath: 當該入口的輸出文件在瀏覽器中被引用時,為它們指定一個公共 URL 地址
22、babel 相關: polyfill 以及 runtime 區別, ES stage 含義,preset–env 作用等等
1.polyfill 以及 runtime 區別
babel-polyfill 的原理是當運行環境中并沒有實現的一些方法,babel-polyfill會做兼容。
babel-runtime 它是將es6編譯成es5去執行。我們使用es6的語法來編寫,最終會通過babel-runtime編譯成es5.也就是說,不管瀏覽器是否支持ES6,只要是ES6的語法,它都會進行轉碼成ES5.所以就有很多冗余的代碼。
babel-polyfill 它是通過向全局對象和內置對象的prototype上添加方法來實現的。比如運行環境中不支持Array.prototype.find 方法,引入polyfill, 我們就可以使用es6方法來編寫了,但是缺點就是會造成全局空間污染。
babel-runtime: 它不會污染全局對象和內置對象的原型,比如說我們需要Promise,我們只需要import Promise from 'babel-runtime/core-js/promise'即可,這樣不僅避免污染全局對象,而且可以減少不必要的代碼。