關於webpack問答記錄...

Skyshine發表於2020-01-20

Question

談談你對webpack的看法

webpack是一個模組打包工具,可以使用它管理專案中的模組依賴,並編譯輸出模組所需的靜態檔案。它可以很好地管理、打包開發中所用到的HTML,CSS,JavaScript和靜態檔案(圖片,字型)等,讓開發更高效。對於不同型別的依賴,webpack有對應的模組載入器,而且會分析模組間的依賴關係,最後合併生成優化的靜態資源。

webpack的基本功能和工作原理?

1、程式碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等等

2、檔案優化:壓縮 JavaScript、CSS、HTML 程式碼,壓縮合並圖片等

3、程式碼分割:提取多個頁面的公共程式碼、提取首屏不需要執行部分的程式碼讓其非同步載入

4、模組合併:在採用模組化的專案有很多模組和檔案,需要構建功能把模組分類合併成一個檔案

5、自動重新整理:監聽本地原始碼的變化,自動構建,重新整理瀏覽器

6、程式碼校驗:在程式碼被提交到倉庫前需要檢測程式碼是否符合規範,以及單元測試是否通過

7、自動釋出:更新完程式碼後,自動構建出線上釋出程式碼並傳輸給釋出系統。

webpack打包原理

1、把一切都視為模組:不管是 CSS、JS、Image 還是 HTML 都可以互相引用,通過定義 entry.js,對所有依賴的檔案進行跟蹤,將各個模組通過 loader 和 plugins 處理,然後打包在一起。

2、按需載入:打包過程中 Webpack 通過 Code Splitting 功能將檔案分為多個 chunks,還可以將重複的部分單獨提取出來作為 commonChunk,從而實現按需載入。把所有依賴打包成一個 bundle.js 檔案,通過程式碼分割成單元片段並按需載入

3、webpack.config.js的配置

// webpack的配置檔案 由於webpack是基於Node構建的,webpack配置檔案中所有的合法node語法都可以用
var path = require('path')
// 如果要配置外掛,需要在匯出的物件上新增plugins節點
var htmlWebpackPlugin = require('html-webpack-plugin')
// 配置匯出物件
module.exports = {
    // 入口檔案
    entry: path.join(__dirname, './src/main.js'),
    /* 
    // 入口檔案的配置項,配置兩個
    entry:{
        entry:'./src/entry.js',
        //這裡我們又引入了一個入口檔案
        entry2:'./src/entry2.js'
    },
    */
    // 指定輸出選項
    output: {
        path: path.join(__dirname, './dist'), // 指定輸出路徑
        /* 
             path:path.resolve(__dirname,'dist'), // 輸出的路徑,用了Node語法
        */
        filename: 'bundle.js' // 指定輸出檔案的名字
    },
    // 外掛物件節點
    plugins: [
        new htmlWebpackPlugin({
            template: path.join(__dirname, './src/index.html'), // 指定模板檔案路徑
            filename: 'index.html' // 設定生成記憶體頁面的的名字
        }),
    ],
    // 配置所有第三方loader(載入程式)模組 例如解讀CSS,圖片如何轉換,壓縮
    module: {
        // 第三方模組的匹配規則
        rules: [
            // 這裡的test於正則的test一樣
            // 處理css檔案的loader
            {test: /\.(css|scss)$/, use: ['style-loader', 'css-loader', 'sass-loader']},
            // 處理圖片路徑的loader 這裡的limit為圖片的大小(單位是位元組)
            {test: /\.(jpg|png|gif|jpeg|bmp)$/, use: 'url-loader?limit=349950&name=[hash:8]-[name].[ext]'},
            // 處理字型圖示的loader
            {test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader'},
            // 把Es6的高階語法轉換成瀏覽器可以識別的低階語言
            {test: /\.js$/, use: 'babel-loader', exclude: /node_modules/},
            // 處理vue檔案的loader
            {test: /\.vue$/, use: 'vue-loader'}
        ]
    },
    // 配置匯入包的路徑
    /*  resolve : {
            alias : { // alias別名 修改vue匯入的路徑
                "vue$" : "vue/dist/vue.js"
            }
        }*/
}
複製程式碼

webpack的優勢

(1) webpack 是以 commonJS 的形式來書寫指令碼的,但對 AMD/CMD 的支援也很全面,方便舊專案進行程式碼遷移。

(2)能被模組化的不僅僅是 JS 了。

(3) 開發便捷,能替代部分 grunt/gulp 的工作,比如打包、壓縮混淆、圖片轉base64等。

(4)擴充套件性強,外掛機制完善

webpack的核心概念

Entry:入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。告訴webpack要使用哪個模組作為構建專案的起點,預設為./src/index.js

output :出口,告訴webpack在哪裡輸出它打包好的程式碼以及如何命名,預設為./dist

Module:模組,在 Webpack 裡一切皆模組,一個模組對應著一個檔案。Webpack 會從配置的 Entry 開始遞迴找出所有依賴的模組。

Chunk:程式碼塊,一個 Chunk 由多個模組組合而成,用於程式碼合併與分割。

Loader:模組轉換器,用於把模組原內容按照需求轉換成新內容。

Plugin:擴充套件外掛,在 Webpack 構建流程中的特定時機會廣播出對應的事件,外掛可以監聽這些事件的發生,在特定時機做對應的事情。

什麼是loader,什麼是plugin

loader用於載入某些資原始檔。因為webpack本身只能打包common.js規範的js檔案,對於其他資源如css,img等,是沒有辦法載入的,這時就需要對應的loader將資源轉化,從而進行載入。使wenbpack擁有載入和解析非js檔案的能力   常見的loader以及作用 1、file-loader:把檔案輸出到一個資料夾中,在程式碼中通過相對 URL 去引用輸出的檔案 2、url-loader:和 file-loader 類似,但是能在檔案很小的情況下以 base64 的方式把檔案內容注入到程式碼中去 3、source-map-loader:載入額外的 Source Map 檔案,以方便斷點除錯 4、image-loader:載入並且壓縮圖片檔案 5、babel-loader:把 ES6 轉換成 ES5 6、css-loader:載入 CSS,支援模組化、壓縮、檔案匯入等特性 7、style-loader:把 CSS 程式碼注入到 JavaScript 中,通過 DOM 操作去載入 CSS。 8、eslint-loader:通過 ESLint 檢查 JavaScript 程式碼

plugin用於擴充套件webpack的功能。不同於loader,plugin的功能更加豐富,比如壓縮打包,優化,不只侷限於資源的載入。

1、UglifyJsPlugin: 壓縮程式碼 2、HotModuleReplacementPlugin 自動重新整理 3、HtmlWebpackPlugin 依據一個簡單的index.html模版,生成一個自動引用你打包後的js檔案的新index.html 4、ExtractTextWebpackPlugin 它會將入口中引用css檔案,都打包都獨立的css檔案中,而不是內嵌在js打包檔案中 5、Tree-shaking 指在打包中去除那些引入了,但是在程式碼中沒有被用到的那些死程式碼 6、在webpack中Tree-shaking是通過uglifySPlugin來Tree-shaking,Css需要使用Purify-CSS

常見的plugin以及作用

define-plugin:定義環境變數 commons-chunk-plugin:提取公共程式碼 uglifyjs-webpack-plugin:通過UglifyES壓縮ES6程式碼

什麼是bundle,什麼是chunk,什麼是module

bundle:是由webpack打包出來的檔案

chunk:是指webpack在進行模組依賴分析的時候,程式碼分割出來的程式碼塊

module:是開發中的單個模組

webpack 和 gulp 的區別?

webpack是一個模組打包器,強調的是一個前端模組化方案,更側重模組打包,我們可以把開發中的所有資源都看成是模組,通過loader和plugin對資源進行處理。

gulp是一個前端自動化構建工具,強調的是前端開發的工作流程,可以通過配置一系列的task,第一task處理的事情(如程式碼壓縮,合併,編譯以及瀏覽器實時更新等)。然後定義這些執行順序,來讓glup執行這些task,從而構建專案的整個開發流程。自動化構建工具並不能把所有的模組打包到一起,也不能構建不同模組之間的依賴關係。

如何自動生成webpack配置檔案?

webpack-cli、vue-cli

什麼是模熱更新?有什麼優點?

模組熱更新是webpack的一個功能,它可以使得程式碼修改之後,不用重新整理瀏覽器就可以更新。在應用過程中替換新增刪出模組,無需重新載入整個頁面,是高階版的自動重新整理瀏覽器。         優點:只更新變更內容,以節省寶貴的開發時間。調整樣式更加快速,幾乎相當於在瀏覽器中更改樣式

webpack-dev-server 和 http伺服器的區別

webpack-dev-server使用記憶體來儲存webpack開發環境下的打包檔案,並且可以使用模組熱更新,比傳統的http服務對開發更加有效。

什麼是長快取?在webpack中如何做到長快取優化?

瀏覽器在使用者訪問頁面的時候,為了加快載入速度,會對使用者訪問的靜態資源進行儲存,但是每一次程式碼升級或者更新,都需要瀏覽器去下載新的程式碼,最方便和最簡單的更新方式就是引入新的檔名稱。

在webpack中,可以在output給出輸出的檔案制定chunkhash,並且分離經常更新的程式碼和框架程式碼,通過NameModulesPlugin或者HashedModulesPlugin使再次打包檔名不變。

什麼是Tree-sharking?

指打包中去除那些引入了但在程式碼中沒用到的死程式碼。在wepack中js treeshaking通過UglifyJsPlugin來進行,css中通過purify-CSS來進行.

webpack構建流程

  1. 初始化引數,從配置檔案和shell語句中讀取與合併引數,得出最終的引數

  2. 開始編譯:用上一步得到的引數初始化 Compiler 物件,載入所有配置的外掛,執行物件的 run 方法開始執行編譯;

  3. 確定入口,通過entry找到入口檔案

  4. 編譯模組:從入口檔案出發,呼叫所有配置的 Loader 對模組進行翻譯(按照loader的規則進行轉換),再找出該模組依賴的模組,再遞迴本步驟直到所有入口依賴的檔案都經過了本步驟的處理;

  5. 完成模組編譯,得到每個模組被翻譯之後的最終的內容和依賴關係

  6. 輸出資源,根據入口和模組之間的依賴關係,組裝成一個個包含多個模組的chunk,在把每個chunk轉換成一個單獨的檔案載入到輸出列表,這步是可以修改輸出內容的最後機會

  7. 輸出完成:在確定好輸出內容後,根據配置確定輸出的路徑和檔名,把檔案內容寫入到檔案系統。

  8. 在整個流程中webpack會在恰當的時機執行plugin裡定義的邏輯

如何提高webpack的構建速度?

多入口情況下,使用CommonsChunkPlugin來提取公共程式碼

通過externals配置來提取常用庫

利用DllPlugin和DllReferencePlugin預編譯資源模組 通過DllPlugin來對那些我們引用但是絕對不會修改的npm包來進行預編譯,再通過DllReferencePlugin將預編譯的模組載入進來。

使用Happypack 實現多執行緒加速編譯

使用webpack-uglify-parallel來提升uglifyPlugin的壓縮速度。 原理上webpack-uglify-parallel採用了多核並行壓縮來提升壓縮速度

使用Tree-shaking和Scope Hoisting來剔除多餘程式碼

如何利用webpack來優化前端效能

壓縮程式碼。uglifyJsPlugin 壓縮js程式碼, mini-css-extract-plugin 壓縮css程式碼

刪除死程式碼(tree shaking),css需要使用Purify-CSS

提取公共程式碼。webpack4移除了CommonsChunkPlugin (提取公共程式碼),用optimization.splitChunks和optimization.runtimeChunk來代替

相關文章