webpack4.X 實戰(一):全面認識webpack、核心概念

Mr_Hermit發表於2019-02-12

一、什麼是 webpack

webpack 是一個模組打包機,將根據檔案間的依賴關係對其進行靜態分析,然後將這些模組按指定規則生成靜態資源

當 webpack 處理程式時,它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle

  • 主要承擔如下功能:

    • 打包:將多個檔案 打包成 一個檔案,減少伺服器壓力和下載頻寬

    • 轉換:將預編譯語言 轉換成 瀏覽器識別的語言

    • 優化:效能優化

  • webpack 特點:

    • 程式碼拆分

      webpack 有兩種組織模組的依賴方式,同步、非同步

      非同步依賴將作為分割點,形成一個新的塊;在優化了依賴樹之後,每一個非同步區塊都將作為一個檔案被打包

    • 智慧解析

      webpack 有一個智慧解析器,幾乎可以處理任何第三方庫

      無論它們的模組形式是 CommonJS、 AMD 還是普通的 JS 檔案;甚至在載入依賴的時候,允許使用動態表示式 require("./templates/" + name + ".jade")

    • 快速執行

      webpack 使用非同步 I/O 、多級快取提高執行效率,使得 webpack 以難以令人置信的速度 快速增量編譯

  • webpack 官網

webpack4.X 實戰(一):全面認識webpack、核心概念

二、安裝

  • 全域性安裝

    sudo npm i webpack -g
    複製程式碼
  • 區域性安裝

    // 在已經 npm 初始化的專案 根目錄執行
    
    npm i webpack -D
    複製程式碼
  • 提醒:webpack4.x 版本需要額外安裝 webpack-cli

    // 以下為區域性安裝方式,全域性安裝同上
    npm i webpack-cli -D
    複製程式碼

三、模組互動 runtime、manifest

  • 在使用 webpack 構建的典型應用程式或站點中,有三種主要的程式碼型別:

    • 你或你的團隊編寫的原始碼。

    • 你的原始碼會依賴的任何第三方的 library 或 "vendor" 程式碼。

    • webpack 的 runtime 和 manifest,管理所有模組的互動

  • 下面 闡述 runtime

    runtime 包含:在模組互動時,連線模組所需的載入和解析邏輯;包括瀏覽器中的已載入模組的連線,以及懶載入模組的執行邏輯

  • 下面 闡述 manifest

    當編譯器(compiler)開始執行、解析、對映應用程式時,它會保留所有模組的詳細要點,這個資料集合稱為 "Manifest"

    當完成打包併傳送到瀏覽器時,會在執行時通過 manifest 來解析、載入模組

  • runtime 和 manifest 管理模組的互動

    在瀏覽器執行時,runtime 和 manifest 用來連線模組化的應用程式的所有程式碼

    無論你選擇哪種模組語法,那些 import 或 require 語句現在都已經轉換為 __webpack_require__ 方法,此方法指向模組識別符號(module identifier)

    通過使用 manifest 中的資料(每個模組的詳細要點:對映、依賴等),runtime 將能夠查詢模組識別符號,檢索出背後對應的模組

四、核心概念:入口 entry

  • 作用

    告訴 webpack 從哪個檔案開始構建,這個檔案將作為 webpack 依賴關係圖的起點

  • 配置 單入口

    // webpack 配置
    
    module.exports = {
      entry: './path/to/my/entry/file.js'
    };
    複製程式碼
    // webpack 配置
    
    module.exports = {
      entry: {
        main: './src/main.js'
      }
    };
    複製程式碼
  • 配置 多入口

    // 場景一:分離 應用程式(app) 和 第三方庫(vendor) 入口
    // webpack 配置
        
    module.exports = {
      entry: {
        app: './src/app.js',
        vendors: './src/vendors.js'
      }
    };
    複製程式碼
    // 場景二:多頁面應用程式,告訴 webpack 需要 3 個獨立分離的依賴圖
    // webpack 配置
        
    module.exports = {
      entry: {
        pageOne: './src/pageOne/index.js',
        pageTwo: './src/pageTwo/index.js',
        pageThree: './src/pageThree/index.js'
      }
    };
    複製程式碼

五、核心概念:出口 output

  • 作用

    告訴 webpack 在哪裡輸出 構建後的包、包的名稱 等

  • 配置 單出口

    // webpack 配置
    
    const path = require('path');
    
    module.exports = {
      entry: main: './src/main.js',
      output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
      }
    };
    複製程式碼
  • 配置 多出口

    // webpack 配置
    
    const path = require('path');
    
    module.exports = {
      entry: {
        app: './src/app.js',
        vendors: './src/vendors.js'
      },
      output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
      }
    };
    複製程式碼
  • 其他引數配置

六、核心概念:loader

  • 作用

    loader 讓 webpack 能夠去處理那些非 JavaScript 檔案(webpack 自身只理解 JavaScript)

    loader 可以將所有型別的檔案轉換為 webpack 能夠處理的有效模組

  • loader 使用方式:配置(常用)

    // 安裝 loader
    npm install --save-dev css-loader
    複製程式碼
    // webpack 配置
    
    module.exports = {
      module: {
        rules: [{ 
            test: /\.css$/, 
            use: ['style-loader', 'css-loader']
        }]
      }
    };
    
    // 或
    
     module.exports = {
      module: {
        rules: [{ 
            test: /\.css$/, 
            use: ['style-loader', {
                loader: 'css-loader',
                options: {
                    modules: true
                }
            }]
        }]
      }
    };
    複製程式碼
  • loader 使用方式:內聯 (不常用)

    // 在專案檔案中,import 語句時使用
    
    import Styles from 'style-loader!css-loader?modules!./styles.css';
    複製程式碼
  • loader 使用方式:CLI(不常用)

    webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
    
    // 如上 會對 .jade 檔案使用 jade-loader,對 .css 檔案使用 style-loader 和 css-loader
    複製程式碼
  • loader 特性

    • 幾乎所有 loader 都 需要安裝,不需要 在 webpack 配置檔案中通過 require 引入

    • 逆向編譯,鏈式傳遞

    // webpack 配置
        
    module.exports = {
      module: {
        rules: [{ 
            test: /\.css$/, 
            use: ['style-loader', 'css-loader', 'postcss-loader']
        }]
      }
    };
    
    // 如上,css 檔案編譯順序依次為:postcss-loader ---> css-loader ---> style-loader
    // 編譯過程中,第一個loader的值 傳遞給下一個loader,依次傳遞;最後一個loader編譯完成後,將預期值傳遞給 webpack
    複製程式碼

七、核心概念:plugin

  • 作用

    可以處理各種任務,從打包優化和壓縮,一直到重新定義環境中的變數

  • plugin 使用

    npm i html-webpack-plugin -D
    複製程式碼
    // webpack 配置
    const HtmlWebpackPlugin = require('html-webpack-plugin'); 
    
    module.exports = {
      plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
      ]
    };
    複製程式碼
  • plugin 特性

    有些外掛需要單獨安裝,有些外掛是webpack內建外掛 不需要單獨安裝

    但所有的外掛都 需要 在 webpack 配置檔案中通過 require 引入

  • plugin 剖析:

    webpack 外掛是一個具有 apply 屬性的 JavaScript 物件

    apply 屬性會被 webpack compiler 呼叫,並且 compiler 物件可在整個編譯生命週期訪問

    // ConsoleLogOnBuildWebpackPlugin.js
    
    const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
    
    class ConsoleLogOnBuildWebpackPlugin {
        apply(compiler) {
            compiler.hooks.run.tap(pluginName, compilation => {
                console.log("webpack 構建過程開始!");
            });
        }
    }
    複製程式碼

八、核心概念:模式 mode(webpack 4.x)

  • 作用

    告訴 webpack 使用相應模式的內建優化

  • 使用

    // webpack 配置
    
    module.exports = {
      mode: 'production'
    };
    複製程式碼
    // CLI 引數中
    
    webpack --mode=production
    複製程式碼
  • 兩種模式的區別

    選項 描述
    development 會將 process.env.NODE_ENV 的值設為 development啟用
    NamedChunksPlugin 和 NamedModulesPlugin
    production 會將 process.env.NODE_ENV 的值設為 production。
    啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin,
    ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin,
    SideEffectsFlagPlugin 和 UglifyJsPlugin
    // mode: development
    
    module.exports = {
        + mode: 'development'
        - plugins: [
        -   new webpack.NamedModulesPlugin(),
        -   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
        - ]
    }
    複製程式碼
    // mode: production
    
    module.exports = {
        +  mode: 'production',
        -  plugins: [
        -    new UglifyJsPlugin(/* ... */),
        -    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
        -    new webpack.optimize.ModuleConcatenationPlugin(),
        -    new webpack.NoEmitOnErrorsPlugin()
        -  ]
    }
    複製程式碼
  • 在 webpack 中區分兩種 模式

    if(process.env.NODE_ENV === 'development'){
        //開發環境 do something
    }else{
        //生產環境 do something
    }
    複製程式碼

九、核心概念:target

  • webpack 能夠為 多種環境 或 target 構建編譯(編譯後程式碼 的執行環境)

    預設值:web

    常見值 見 API

十、核心概念:source map 定位程式碼中的錯誤

  • 不同的 source map(資源對映)

    會決定 程式碼中錯誤的顯示方式(打包後程式碼、生成後程式碼、轉換過程式碼、原始碼等 詳細見

    會影響 構建(build)、重新構建(rebuild) 的速度

    整個 source map 作為一個單獨的檔案生成。它為 bundle 新增了一個引用註釋,以便開發工具知道在哪裡可以找到它

  • 開發環境的幾種常見的 source map

    • 以如下程式碼為例,執行

      console.log('js');
      
      class A extends test {}
      複製程式碼
    • eval-source-map

      構建速度:-- 、重新構建速度:+ 、生產環境:no 、顯示原始原始碼

      webpack4.X 實戰(一):全面認識webpack、核心概念

    • cheap-eval-source-map

      構建速度:+ 、重新構建速度:++ 、生產環境:no 、轉換過的程式碼(僅限行)

      webpack4.X 實戰(一):全面認識webpack、核心概念

    • cheap-module-eval-source-map【推薦】

      構建速度:0 、重新構建速度:++ 、生產環境:no 、原始原始碼(僅限行)

      webpack4.X 實戰(一):全面認識webpack、核心概念

  • 生產環境中 常見的 source map

    • 以如下程式碼為例,執行

      console.log('js');
      
      class A extends test {}
      複製程式碼
    • none 【推薦】

      構建速度:+++ 、重新構建速度:+++ 、生產環境:yes 、打包後程式碼

      webpack4.X 實戰(一):全面認識webpack、核心概念

      • 總結: 需要注意的是不同的 devtool 的設定,會導致不同的效能差異。

        • "eval" 具有最好的效能,但並不能幫助你轉譯程式碼。

        • 如果你能接受稍差一些的 mapping 質量,可以使用 cheap-source-map 選項來提高效能

        • 使用 eval-source-map 配置進行增量編譯

        • 在大多數情況下,cheap-module-eval-source-map 是最好的選擇

附言

  • 小夥伴們,有什麼問題 可以留言,一起交流哈
  • 接下來,我還會發布幾篇 webpack4.X 實戰文章,敬請關注
  • 我是一名熱衷於程式設計的前端開發,WX:ZXvictory66

相關文章