Webpack(二):核心特性

上一篇的最後提出了對模塊化打包方案或工具的訴求:

  • 能夠將散落的模塊打包到一起;
  • 能夠編譯代碼中的新特性;
  • 能夠支持不同種類的前端資源模塊。

目前,前端領域有一些工具能夠很好的滿足以上這 3 個需求,其中最爲主流的就是 Webpack、Parcel 和 Rollup。

如何使用 Webpack 實現模塊化打包?

  • Webpack 作爲一個模塊打包工具,本身就可以解決模塊化代碼打包的問題,將零散的 JavaScript 代碼打包到一個 JS 文件中。
  • 對於有環境兼容問題的代碼,Webpack 可以在打包過程中通過 Loader 機制對其實現編譯轉換,然後再進行打包。
  • 對於不同類型的前端模塊類型,Webpack 支持在 JavaScript 中以模塊化的方式載入任意類型的資源文件,例如,我們可以通過 Webpack 實現在 JavaScript 中加載 CSS 文件,被加載的 CSS 文件將會通過 style 標籤的方式工作。
  • Webpack 還具備代碼拆分的能力,它能夠將應用中所有的模塊按照我們的需要分塊打包
🌰
└─ webpack_test
   ├── src
   │   ├── heading.js
   │   └── index.js
   └── index.html
// ./src/heading.js
export default () => {
  const element = document.createElement('h2')
  element.textContent = 'Hello webpack'
  element.addEventListener('click', () => alert('Hello webpack'))
  return element
}
// ./src/index.js
import createHeading from './heading.js'
const heading = createHeading()
document.body.append(heading)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Webpack - 快速上手</title>
</head>
<body>
  <script type="module" src="src/index.js"></script>
</body>
</html>
1. 安裝 Webpack 的核心模塊以及它的 CLI 模塊
npm init --yes   #先初始化一個package.json文件,用來管理npm依賴版本
npm i webpack webpack-cli --save-dev

webpack 是 Webpack 的核心模塊,webpack-cli 是 Webpack 的 CLI 程序,用來在命令行中調用 Webpack。

安裝完成之後,webpack-cli 所提供的 CLI 程序就會出現在 node_modules/.bin 目錄當中,我們可以通過 npx 快速找到 CLI 並運行它,具體操作如下:

npx webpack --version
# v4.43.0

npx 是 npm 5.2 以後新增的一個命令,可以用來更方便的執行遠程模塊或者項目 node_modules 中的 CLI 程序。

2. 運行 Webpack

有了 Webpack 後,就可以直接運行 webpack 命令來打包 JS 模塊代碼:

npx webpack

這個命令在執行的過程中,Webpack 會自動從 src/index.js 文件開始打包,然後根據代碼中的模塊導入操作,自動將所有用到的模塊代碼打包到一起。

完成之後,控制檯會提示:順着 index.js 有兩個 JS 文件被打包到了一起。與之對應的就是項目的根目錄下多出了一個 dist 目錄,我們的打包結果就存放在這個目錄下的 main.js 文件中。

修改 inde.html 中的代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Webpack - 快速上手</title>
</head>
<body>
  <script src="dist/main.js"></script>
</body>
</html>

成功使用。

對於 Webpack 最基本的使用,總結下來就是:先安裝 webpack 相關的 npm 包,然後使用 webpack-cli 所提供的命令行工具進行打包。

配置 Webpack 的打包過程

🌰:需要它的打包入口是 src/main.js

那就需要通過配置文件的方式修改 Webpack 的默認配置,在項目的根目錄下添加一個 webpack.config.js,具體結構如下:

 └─ 02-configuation
    ├── src
    │ ├── heading.js
    │ └── main.js
    ├── index.html
    ├── package.json
+   └── webpack.config.js ···················· Webpack 配置文件

webpack.config.js 是一個運行在 Node.js 環境中的 JS 文件,也就是說我們需要按照 CommonJS 的方式編寫代碼,這個文件可以導出一個對象,我們可以通過所導出對象的屬性完成相應的配置選項。

添加一個 entry 屬性,這個屬性的作用就是指定 Webpack 打包的入口文件路徑。我們將其設置爲 src/main.js,具體代碼如下所示:

// ./webpack.config.js
module.exports = {
  entry: './src/main.js'
}

配置完成之後,回到命令行終端重新運行打包命令,此時 Webpack 就會從 src/main.js 文件開始打包。

還可以通過 output 屬性設置輸出文件的位置

output 屬性的值必須是一個對象,通過這個對象的 filename 指定輸出文件的文件名稱,path 指定輸出的目錄。

具體代碼如下所示:

// ./webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'output')
  }
}
Webpack 工作模式

Webpack 4 新增了一個工作模式的用法,這種用法大大簡化了 Webpack 配置的複雜程度。你可以把它理解爲針對不同環境的幾組預設配置:

  • production 模式下,啓動內置優化插件,自動優化打包結果,打包速度偏慢;
  • development 模式下,自動優化打包速度,添加一些調試過程中的輔助插件;
  • none 模式下,運行最原始的打包,不做任何額外處理。

修改 Webpack 工作模式的方式有兩種:

  • 通過 CLI --mode 參數傳入;
  • 通過配置文件設置 mode 屬性。

官方文檔



如何通過 Loader 實現特殊資源加載?

在這裏插入圖片描述
🌰:通過 Webpack 打包項目中的一個 CSS 文件。

$ npm install css-loader --save-dev 
// ./src/webpack.config.js
module.exports = {
  entry: './src/main.css',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/, // 根據打包過程中所遇到文件路徑匹配是否使用這個 loader
        use: 'css-loader' // 指定具體的 loader
      }
    ]
  }
}

在配置對象的 module 屬性中添加一個 rules 數組。這個數組就是我們針對資源模塊的加載規則配置,其中的每個規則對象都需要設置兩個屬性:

  • test :它是一個正則表達式,用來匹配打包過程中所遇到文件路徑,這裏我們是以 .css 結尾;
  • use :它用來指定匹配到的文件需要使用的 loader,這裏用到的是 css-loader

配置完成過後,回到命令行終端重新運行打包命令,打包過程就不會再出現錯誤了,因爲這時 CSS 文件會交給 css-loader 處理過後再由 Webpack 打包。

不過此時 main.css 模塊並沒有工作。只需要再額外添加一個 style-loader,樣式就可以正常工作了。

$ npm install style-loader --save-dev 
module: {
    rules: [
      {
        test: /\.css$/,
        // 對同一個模塊使用多個 loader,注意順序
        use: [
          'style-loader',
          'css-loader'
        ]
      }
    ]
  }


如何利用插件機制橫向擴展 Webpack 的構建能力

clean-webpack-plugin 自動清除輸出目錄的插件
$ npm install clean-webpack-plugin --save-dev

安裝過後,在 Webpack 的配置文件中導入 clean-webpack-plugin 插件,這個插件模塊導出了一個叫作 CleanWebpackPlugin 的成員,我們先把它解構出來,具體代碼如下:

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

回到配置對象中,添加一個 plugins 屬性,這個屬性就是專門用來配置插件的地方,它是一個數組,添加一個插件就是在這個數組中添加一個元素。

絕大多數插件模塊導出的都是一個類型,CleanWebpackPlugin 也不例外,使用它,就是通過這個類型創建一個實例,放入 plugins 數組中,具體代碼如下:

// ./webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new CleanWebpackPlugin()
  ]
}

測試 clean-webpack-plugin 插件的效果:回到命令行終端,再次運行 Webpack 打包,此時之前的打包結果就不會存在了,dist 目錄中存放的就都是我們本次打包的結果。

html-webpack-plugin 用於生成HTML的插件
$ npm install html-webpack-plugin --save-dev

安裝完成過後,回到配置文件,載入這個模塊。

html-webpack-plugin 插件默認導出的就是插件類型,不需要再解構內部成員。

具體如下:

const HtmlWebpackPlugin = require('html-webpack-plugin')

有了這個類型過後,回到配置對象的 plugins 屬性中,同樣需要添加一下這個類型的實例對象,完成這個插件的使用,具體配置代碼如下:

// ./webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin()
  ]
}
copy-webpack-plugin 用於複製文件的插件

安裝 copy-webpack-plugin 插件,安裝完成後,回到配置文件中,導入這個插件類型。然後同樣在 plugins 屬性中添加一個這個類型的實例,具體代碼如下:

// ./webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'Webpack Plugin Sample',
      template: './src/index.html'
    }),
    new CopyWebpackPlugin([
      'public' // 需要拷貝的目錄或者路徑通配符
    ])
  ]
}

這個插件類型的構造函數需要傳入一個字符串數組,用於指定需要拷貝的文件路徑。它可以是一個通配符,也可以是一個目錄或者文件的相對路徑。我們這裏傳入的是 public 目錄,表示將這個目錄下所有文件全部拷貝到輸出目錄中。還可以在這個數組中繼續添加其它路徑,這樣它在工作時可以同時拷貝。

配置完成以後回到命令行終端,再次運行 Webpack,此時 public 目錄下的文件就會同時拷貝到輸出目錄中。


名稱 鏈接
file-loader https://webpack.js.org/loaders/file-loader
url-loader https://webpack.js.org/loaders/url-loader
babel-loader https://webpack.js.org/loaders/babel-loader
style-loader https://webpack.js.org/loaders/style-loader
css-loader https://webpack.js.org/loaders/css-loader
sass-loader https://webpack.js.org/loaders/sass-loader
postcss-loader https://webpack.js.org/loaders/postcss-loader
eslint-loader https://github.com/webpack-contrib/eslint-loader
vue-loader https://github.com/vuejs/vue-loader

Webpack 爲每一個工作環節都預留了合適的鉤子,我們在擴展時只需要找到合適的時機去做合適的事情就可以了。



探索 Webpack 運行機制與核心工作原理

工作過程

在這裏插入圖片描述
Webpack 啓動後,會根據配置,找到項目中的某個指定文件(一般這個文件都會是一個 JS 文件)作爲入口。然後順着入口文件中的代碼,根據代碼中出現的 import(ES Modules)或者是 require(CommonJS)之類的語句,解析推斷出來這個文件所依賴的資源模塊,然後再分別去解析每個資源模塊的依賴,週而復始,最後形成整個項目中所有用到的文件之間的依賴關係樹。

有了這個依賴關係樹過後, Webpack 會遍歷(遞歸)這個依賴樹,找到每個節點對應的資源文件,然後根據配置選項中的 Loader 配置,交給對應的 Loader 去加載這個模塊,最後將加載的結果放入 bundle.js(打包結果)中,從而實現整個項目的打包。

工作原理

Webpack 核心工作過程中的關鍵環節,明確“查閱”源碼的思路:

  • Webpack CLI 啓動打包流程;
  • 載入 Webpack 核心模塊,創建 Compiler 對象
  • 使用 Compiler 對象開始編譯整個項目;
  • 從入口文件開始,解析模塊依賴,形成依賴關係樹
  • 遞歸依賴樹,將每個模塊交給對應的 Loader 處理
  • 合併 Loader 處理完的結果,將打包結果輸出到 dist 目錄。



🔗 相關鏈接:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章