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

1、什麼是 webpack

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

當 webpack 處理程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundleweb

  • 主要承擔以下功能:npm

    • 打包:將多個文件 打包成 一個文件,減小服務器壓力和下載帶寬編程

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

    • 優化:性能優化緩存

  • webpack 特色:性能優化

    • 代碼拆分

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

      異步依賴將做爲分割點,造成一個新的塊;在優化了依賴樹以後,每個異步區塊都將做爲一個文件被打包

    • 智能解析

      webpack 有一個智能解析器,幾乎能夠處理任何第三方庫

      不管它們的模塊形式是 CommonJS、 AMD 仍是普通的 JS 文件;甚至在加載依賴的時候,容許使用動態表達式 require("./templates/" + name + ".jade")

    • 快速運行

      webpack 使用異步 I/O 、多級緩存提升運行效率,使得 webpack 以難以使人置信的速度 快速增量編譯

  • webpack 官網

2、安裝

  • 全局安裝

    sudo npm i webpack -g
    複製代碼
  • 局部安裝

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

    // 如下爲局部安裝方式,全局安裝同上
    npm i webpack-cli -D
    複製代碼

3、模塊交互 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 將可以查詢模塊標識符,檢索出背後對應的模塊

4、核心概念:入口 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'
      }
    };
    複製代碼

5、核心概念:出口 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')
      }
    };
    複製代碼
  • 其餘參數配置

6、核心概念: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
    複製代碼

7、核心概念: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 構建過程開始!");
            });
        }
    }
    複製代碼

8、核心概念:模式 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
    }
    複製代碼

9、核心概念:target

  • webpack 可以爲 多種環境 或 target 構建編譯(編譯後代碼 的運行環境)

    默認值:web

    常見值 見 API

10、核心概念:source map 定位代碼中的錯誤

  • 不一樣的 source map(資源映射)

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

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

    整個 source map 做爲一個單獨的文件生成。它爲 bundle 添加了一個引用註釋,以便開發工具知道在哪裏能夠找到它

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

    • 以以下代碼爲例,運行

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

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

    • cheap-eval-source-map

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

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

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

  • 生產環境中 常見的 source map

    • 以以下代碼爲例,運行

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

      構建速度:+++ 、從新構建速度:+++ 、生產環境:yes 、打包後代碼

      • 總結: 須要注意的是不一樣的 devtool 的設置,會致使不一樣的性能差別。

        • "eval" 具備最好的性能,但並不能幫助你轉譯代碼。

        • 若是你能接受稍差一些的 mapping 質量,可使用 cheap-source-map 選項來提升性能

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

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

附言

  • 小夥伴們,有什麼問題 能夠留言,一塊兒交流哈
  • 接下來,我還會發布幾篇 webpack4.X 實戰文章,敬請關注
  • 我是一名熱衷於編程的前端開發,WX:ZXvictory66
相關文章
相關標籤/搜索