天天看點

webpack5的知識點整理

作者:不學巫術的O小文

webpack5的知識點整理

一、 關于打包的相關知識

1.1、首先我們為什麼需要打包工具?

開發時,我們會使用架構(React、Vue),ES6 子產品化文法,Less/Sass 等 css 預處理器等文法進行開發。

這樣的代碼要想在浏覽器運作必須經過編譯成浏覽器能識别的才能運作(浏覽器隻認識html,css,js)。

是以我們需要打包工具幫我們做完這些事。

除此之外,打包工具還能壓縮代碼、做相容性處理、提升代碼性能等

1.2、常見的打包工具都有哪些?

Grunt:最老牌的打包工具,它運用配置的思想來寫打包腳本,一切皆配置、

Gulp:用代碼方式來寫打包腳本,并且代碼采用流式的寫法、

Parcel:一款速度極快、零配置的web應用程式打包、

Webpack:是子產品化管理工具和打包工具,他的宗旨是一切靜态資源皆可打包、

Rollup:下一代 ES6 子產品化工具,最大的亮點是利用 ES6 子產品設計,利用 tree-shaking生成更簡潔、更簡單的代碼、

Vite:Vite 是 vue 的作者尤雨溪在開發 vue3.0 的時候開發的一個 基于原生 ES-Module 的前端建構工具,是基于浏覽器原生 ES module,利用浏覽器解析 imports,伺服器端按需編譯傳回,把壓力給到了伺服器和浏覽器、

Turbopack:号稱比vite還要快10倍,由 Webpack 的建立者 Tobias Koppers 和 Next.js 團隊使用 Rust 編寫,是針對 JavaScript 和 TypeScript 優化的增量打包工具

關于vite和webpack的比較分析:https://blog.csdn.net/gao_xu_520/article/details/126350004

二、首先webpack的概念官網如是所說:

一、webpack 是一個用于現代 JavaScript 應用程式的 靜态子產品打包工具。當 webpack 處理應用程式時,它會在内部從一個或多個入口點建構一個 依賴圖(dependency graph),然後将你項目中所需的每一個子產品組合成一個或多個 bundles,它們均為靜态資源,用于展示你的内容。

  • 在子產品化程式設計中,開發者将程式分解為功能離散的 chunk,并稱之為 子產品。
  • 每個子產品都擁有小于完整程式的體積,使得驗證、調試及測試變得輕而易舉。 精心編寫的 子產品 提供了可靠的抽象和封裝界限,使得應用程式中每個子產品都具備了條理清晰的設計和明确的目的
  • 何為 webpack 子產品
  • 與 Node.js 子產品相比,webpack 子產品 能以各種方式表達它們的依賴關系。下面是一些示例:
    • ES2015 import 語句
    • CommonJS require() 語句
    • AMD define 和 require 語句
    • css/sass/less 檔案中的 @import 語句。
    • stylesheet url(...) 或者 HTML <img src=...> 檔案中的圖檔連結。
  • 支援的子產品類型
  • Webpack 天生支援如下子產品類型:
    • ECMAScript 子產品
    • CommonJS 子產品
    • AMD 子產品
    • Assets
    • WebAssembly 子產品

通過 loader 可以使 webpack 支援多種語言和預處理器文法編寫的子產品。loader 向 webpack 描述了如何處理非原生子產品,并将相關依賴引入到你的 bundles中。 webpack 社群已經為各種流行的語言和預處理器建立了 loader

  • 靜态:項目中的靜态資源如css、圖檔等檔案
  • 打包:打包:主要幫你壓縮代碼,然後還會加密、混淆代碼或者過個檔案壓縮成一個檔案

二、本質上webpack可識别的js或者json類的檔案,是以需要擴充一些功能幫助webpack對其他類型的檔案進行處理

- loader:幫助 webpack 将不同類型的檔案轉換為 webpack 可識别的子產品。下文在詳細講解loader           
  • plugin:本質Plugin的本質是一個 node 子產品,這個子產品導出一個JavaScript 類,是處理一些loader不能完成的功能和任務。通過插件我們可以擴充 webpack,加入自定義的建構行為,使 webpack 可以執行更廣泛的任務,擁有更強的建構能力 plugin的工作原理:webpack 就像一條生産線,要經過一系列處理流程後才能将源檔案轉換成輸出結果。 這條生産線上的每個處理流程的職責都是單一的,多個流程之間有存在依賴關系,隻有完成目前處理後才能交給下一個流程去處理。 插件就像是一個插入到生産線中的一個功能,在特定的時機對生産線上的資源做處理。webpack 通過 Tapable 來組織這條複雜的生産線。 webpack 在運作過程中會廣播事件,插件隻需要監聽它所關心的事件,就能加入到這條生産線中,去改變生産線的運作。 webpack 的事件流機制保證了插件的有序性,使得整個系統擴充性很好。 ——「深入淺出 Webpack」 類似于vue元件生命周期的概念,站在代碼邏輯的角度就是:webpack 在編譯代碼過程中,會觸發一系列 Tapable 鈎子事件,插件所做的,就是找到相應的鈎子,往上面挂上自己的任務,也就是注冊事件,這樣,當 webpack 建構的時候,插件注冊的事件就會随着鈎子的觸發而執行了。

三、基礎的使用方法

npm run serve 之後發生了什麼

https://juejin.cn/post/7078924628525056007

基礎的打包工具:npx webpack --config webpack.dev.js

在package中的打包指令是:dev:webpack --config webpack.dev.js

注意:在script中不再需要添加npx。它會自動在node_modules/.bin中去找指令

npm run xxx 發生了什麼?

第一步

webpack5的知識點整理

第二步:在node_modules/.bin中找到檔案

webpack5的知識點整理

第三步:執行腳本:#!/bin/sh:表示這是一個腳本 相當于執行了,./node_modules/.bin/vue-cli-serve serve(最後的serve作為參數傳入)

.bin目錄下的檔案表示軟連接配接, 那這個bin檔案是哪裡來的?

在npm i 的時候在pack-lock.json 中npm i 的時候讀到這個的時候就npm 将bin/vue-cli-serve.js作為了bin聲明了,就是類似 npm i 的時候npm就把這種軟連接配接給配置好了,其實就是一種映射,根據指令一步步找到映射檔案,然後在找到相應的js檔案進行腳本的執行。

總結:1、運作npm run xxx 的時候 npm 會在node_modules/.bin檔案中找執行的腳本,找到則運作

2、沒有找到則從全局的node_modules/.bin中查找,npm i -g就是安裝到全局的目錄中的

3、如果全局中還沒有找到,就從path變量中查找有沒有其他同名的可執行的程式。

基本的使用方法

打開終端,來到項目根目錄。運作以下指令:

  • 初始化package.json
npm init -y           

此時會生成一個基礎的 package.json 檔案。

需要注意的是 package.json 中 name 字段不能叫做 webpack, 否則下一步會報錯

  • 下載下傳依賴
npm i webpack webpack-cli -D           
  • 建立檔案count.js和sum.js和main.js
  • 開發模式
webpack5的知識點整理
npx webpack ./src/main.js --mode=development           
  • 生産模式
npx webpack ./src/main.js --mode=production           

預設 Webpack 會将檔案打包輸出到 dist 目錄下,我們檢視 dist 目錄下檔案情況就好了

Webpack 本身功能比較少,隻能處理 js 資源,一旦遇到 css 等其他資源就會報錯。

是以我們學習 Webpack,就是主要學習如何處理其他資源。

萬惡的eval():https://blog.csdn.net/qq_50892584/article/details/126958601

四、基本配置

五大核心功能:

  1. entry(入口)

訓示 Webpack 從哪個檔案開始打包

  1. output(輸出)

訓示 Webpack 打包完的檔案輸出到哪裡去,如何命名等

  1. loader(加載器)

webpack 本身隻能處理 js、json 等資源,其他資源需要借助 loader,Webpack 才能解析

  1. plugins(插件)

擴充 Webpack 的功能

  1. mode(模式)

主要由兩種模式:

  • 開發模式:development
  • 生産模式:production
webpack5的知識點整理

以上是生産環境基礎配置和打包dist/main.js檔案

開發和生産模式

開發模式:顧名思義就是開發的時候的代碼模式,

1、編譯代碼(使浏覽器能夠識别),開發時我們有的樣式資源、字型圖示、圖檔資源,html檔案資源等因為webpack預設是不識别這些資源的(隻識别js和json檔案)

2、代碼品質檢查、樹立代碼規範,提前檢查代碼的一些規範,讓代碼更加健壯,提前檢查代規範和統一團隊編碼風格。讓代碼更加優雅和美觀。

生産模式

1、開發完成的代碼打包部署上線

2、優化代碼,讓代碼性能更加好,優化代碼的運作速度,和優化代碼的打包速度。

五、我們要學習的webpack基礎常見配置下篇文章會将

  • 處理樣式資源,css資源、less資源、sass(scss)資源、styl資源
  • 處理圖檔資源:過去在 Webpack4 時,我們處理圖檔資源通過 file-loader 和 url-loader 進行處理
  • 現在 Webpack5 已經将兩個 Loader 功能内置到 Webpack 裡了,我們隻需要簡單配置即可處理圖檔資源
  • 修改輸出資源的名稱和路徑
  • 自動清空上次打包資源
  • 處理字型圖示資源
  • 處理其他資源(例如音視訊)
  • 處理js資源:因為webpack隻能編譯 js 中 ES 子產品化文法,不能編譯其他文法,導緻 js 不能在 IE 等浏覽器運作,是以我們希望做一些相容性處理。
  • 其次開發中,團隊對代碼格式是有嚴格要求的,我們不能由肉眼去檢測代碼格式,需要使用專業的工具來檢測。
    • 針對 js 相容性處理,我們使用 Babel 來完成
    • 針對代碼格式,我們使用 Eslint 來完成
  • 我們先完成 Eslint,檢測代碼格式無誤後,在由 Babel 做代碼相容性處理
  • 處理html資源
  • 開發伺服器和自動化
  • css在處理,提取成單獨檔案和相容性處理以及代碼壓縮
  • html代碼壓縮

六、webpack進階優化配置下下篇文章會将

  • 提升開發體驗:sourcemap(源代碼映射)是一個用來生成源代碼與建構後代碼一一映射的檔案的方案
  • 提升打包建構速度
    • HotModuleReplacement(HMR/熱子產品替換):在程式運作中,替換、添加或删除子產品,而無需重新加載整個頁面。
    • oneOf:顧名思義就是隻能比對上一個 loader, 剩下的就不比對了,打包時每個檔案都會經過所有 loader 處理,雖然因為 test 正則原因實際沒有處理上,但是都要過一遍。比較慢
    • Include/Exclude:開發時我們需要使用第三方的庫或插件,所有檔案都下載下傳到 node_modules 中了。而這些檔案是不需要編譯可以直接使用的。是以我們在對 js 檔案處理時,要排除 node_modules 下面的檔案。
    • Cache:對 Eslint 檢查 和 Babel 編譯結果進行緩存。
    • Thead:多程序打包:開啟電腦的多個程序同時幹一件事,速度更快。需要注意:請僅在特别耗時的操作中使用,因為每個程序啟動就有大約為 600ms 左右開銷
  • 減少代碼體積
    • Tree Shaking:通常用于描述移除 JavaScript 中的沒有使用上的代碼
    • Babel:Babel 為編譯的每個檔案都插入了輔助代碼,使代碼體積過大!Babel 對一些公共方法使用了非常小的輔助代碼,比如 _extend。預設情況下會被添加到每一個需要它的檔案中。你可以将這些輔助代碼作為一個獨立子產品,來避免重複引入
    • Image Minimizer:開發如果項目中引用了較多圖檔,那麼圖檔體積會比較大,将來請求速度比較慢。
    • 我們可以對圖檔進行壓縮,減少圖檔體積。
    • 注意:如果項目中圖檔都是線上連結,那麼就不需要了。本地項目靜态圖檔才需要進行壓縮
  • 優化代碼性能
    • Code Split:代碼分割(Code Split)主要做了兩件事:
    • 分割檔案:将打包生成的檔案進行分割,生成多個 js 檔案。
    • 按需加載:需要哪個檔案就加載哪個檔案。
    • Preload / Prefetch:
    • Preload:告訴浏覽器立即加載資源。
    • Prefetch`:告訴浏覽器在空閑時才開始加載資源。

它們共同點:

都隻會加載資源,并不執行。

都有緩存。

  • NetWork Cache:通過更新檔案名字來進行對檔案的緩存,根據更新前後的檔案名不一樣,這樣就可以做緩存了。
    • chunkhash:根據不同的入口檔案(Entry)進行依賴檔案解析、建構對應的chunk,生成對應的哈希值,我們js和css是同一個引入,會共享一個哈希值。
    • contenthash:根據檔案内容生成hash值,隻有檔案内容變化了,hash值才會改變,所有檔案的hash值是共享的。
  • core-js:core-js 是專門用來做 ES6 以及以上 API 的 polyfill。
  • polyfill翻譯過來叫做墊片/更新檔。就是用社群上提供的一段代碼,讓我們在不相容某些新特性的浏覽器上,使用該新特性
  • PWA:漸進式網絡應用程式(progressive web application - PWA):是一種可以提供類似于 native app(原生應用程式) 體驗的 Web App 的技術。
  • 其中最重要的是,在 離線(offline) 時應用程式能夠繼續運作功能。
  • 内部通過 Service Workers 技術實作的。

七、項目react腳手架和vue腳手架

  1. 如何搭建 React-Cli 和 Vue-Cli。
  2. 如何對腳手架進行優化。
  3. 未來随着項目越來越大,還可以在優化的方案。

八、loader原理分析以及開發簡單的demo

loader:是什麼,怎麼使用,如何自定義

1、是什麼:幫助webpack将其他子產品轉換為webpack可以識别子產品

2、分類

  • pre: 前置 loader
  • normal: 普通 loader(預設情況下是normal)
  • inline: 内聯 loader
  • post: 後置 loader

3、執行順序

  • 4 類 loader 的執行優級為:pre > normal > inline > post 。
  • 相同優先級的 loader 執行順序為:從右到左,從下到上。

4、開發一個簡單的loader:本質上就是一個函數

5、loader的分類

  • 同步loader
  • 異步loader
  • raw loader
  • pitching loader

6、loader 的API

方法名 含義 用法
this.async 異步回調 loader。傳回 this.callback const callback = this.async()
this.callback 可以同步或者異步調用的并傳回多個結果的函數 this.callback(err, content, sourceMap?, meta?)
this.getOptions(schema) 擷取 loader 的 options this.getOptions(schema)
this.emitFile 産生一個檔案 this.emitFile(name, content, sourceMap)
this.utils.contextify 傳回一個相對路徑 this.utils.contextify(context, request)
this.utils.absolutify 傳回一個絕對路徑 this.utils.absolutify(context, request)

例如:手寫 clean-log-loader

作用:用來清理 js 代碼中的console.log

// loaders/clean-log-loader.js
module.exports = function cleanLogLoader(content) {
  // 将console.log替換為空
  return content.replace(/console\.log\(.*\);?/g, "");
};           

之後文章會在寫

webpack5的知識點整理
  • 手寫 banner-loader 作用:給 js 代碼添加文本注釋
  • 手寫 babel-loader 作用:編譯js代碼,将ES6+文法編譯成ES5-文法
  • 手寫file-loader 作用:将檔案原封不動的輸出出去
  • 手寫style-loader 作用:動态建立style标簽,插入js中的樣式代碼,使樣式生效。

九、plugin原理分析以及開發簡單的demo之後文章會将

1、作用:擴充loader不能做到的功能,可以擴充webpack的功能,加入自定義的建構行為。

2、工作原理

webpack 就像一條生産線,要經過一系列處理流程後才能将源檔案轉換成輸出結果。 這條生産線上的每個處理流程的職責都是單一的,多個流程之間有存在依賴關系,隻有完成目前處理後才能交給下一個流程去處理。 插件就像是一個插入到生産線中的一個功能,在特定的時機對生産線上的資源做處理。webpack 通過 Tapable 來組織這條複雜的生産線。 webpack 在運作過程中會廣播事件,插件隻需要監聽它所關心的事件,就能加入到這條生産線中,去改變生産線的運作。 webpack 的事件流機制保證了插件的有序性,使得整個系統擴充性很好。

——「深入淺出 Webpack」

站在代碼邏輯的角度就是:webpack 在編譯代碼過程中,會觸發一系列 Tapable 鈎子事件,插件所做的,就是找到相應的鈎子,往上面挂上自己的任務,也就是注冊事件,這樣,當 webpack 建構的時候,插件注冊的事件就會随着鈎子的觸發而執行 了。

3、什麼是鈎子

鈎子的本質就是:事件。為了友善我們直接介入和控制編譯過程,webpack 把編譯過程中觸發的各類關鍵事件封裝成事件接口暴露了出來。這些接口被很形象地稱做:hooks(鈎子)。開發插件,離不開這些鈎子

4、plugin本質

1)Plugin 的本質是一個 node 子產品,這個子產品導出一個 JavaScript 類

2)它的原型上需要定義一個apply 的方法

3)通過compiler擷取 webpack 内部的鈎子,擷取 webpack 打包過程中的各個階段

鈎子分為同步和異步的鈎子,異步鈎子必須執行對應的回調

4)通過compilation操作 webpack 内部執行個體特定資料

5)功能完成後,執行 webpack 提供的 cb 回調

十、mini版webpack

https://juejin.cn/post/7146976516692410376#heading-96

1、 npm init -y 建立package.json檔案

2、建立建立minipack.js

3、建立測試檔案夾和檔案

4、下載下傳依賴npm i babylon babel-traverse babel-core babel-preset-env -D

5、啟動項目:node minipack.js

babel-preset-env:這種現象是由于在 .babelrc 檔案中設定了env 選項,需要插件 babel-preset-env 處理

Webpack的打包流程

總結一下webpack完整的打包流程

1)webpack從項目的entry入口檔案開始遞歸分析,調用所有配置的 loader對子產品進行編譯

因為webpack預設隻能識别js代碼,是以如css檔案、.vue結尾的檔案,必須要通過對應的loader解析成js代碼後,webpack才能識别

2)利用babel(babylon)将js代碼轉化為ast抽象文法樹,然後通過babel-traverse對ast進行周遊

3)周遊的目的找到檔案的import引用節點

因為現在我們引入檔案都是通過import的方式引入,是以找到了import節點,就找到了檔案的依賴關系

4)同時每個子產品生成一個唯一的id,并将解析過的子產品緩存起來,如果其他地方也引入該子產品,就無需重新解析,最後根據依賴關系生成依賴圖譜

5)遞歸周遊所有依賴圖譜的子產品,組裝成一個個包含多個子產品的 Chunk(塊)

6)最後将生成的檔案輸出到 output 的目錄中

熱更新原理

什麼是webpack熱更新?

開發過程中,代碼發生變動後,webpack會重新編譯,編譯後浏覽器替換修改的子產品,局部更新,無需重新整理整個頁面

好處:節省開發時間、提升開發體驗

熱更新原理

主要是通過websocket實作,建立本地服務和浏覽器的雙向通信。當代碼變化,重新編譯後,通知浏覽器請求更新的子產品,替換原有的子產品

1) 通過webpack-dev-server開啟server服務,本地server啟動之後,再去啟動websocket服務,建立本地服務和浏覽器的雙向通信

2) webpack每次編譯後,會生成一個Hash值,Hash代表每一次編譯的辨別。本次輸出的Hash值會編譯新生成的檔案辨別,被作為下次熱更新的辨別

3)webpack監聽檔案變化(主要是通過檔案的生成時間判斷是否有變化),當檔案變化後,重新編譯

4)編譯結束後,通知浏覽器請求變化的資源,同時将新生成的hash值傳給浏覽器,用于下次熱更新使用

5)浏覽器拿到更新後的子產品後,用新子產品替換掉舊的子產品,進而實作了局部重新整理

輕松了解webpack熱更新原理 深入淺出 Webpack 帶你深度解鎖Webpack系列(基礎篇)

作者:海闊_天空 連結:https://juejin.cn/post/7146976516692410376 來源:稀土掘金 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

參考文章:

https://blog.csdn.net/gao_xu_520/article/details/126350004 :對vite的簡單了解

https://juejin.cn/post/7146976516692410376#heading-96 :10萬字前端知識體系總結

https://blog.csdn.net/qq_50892584/article/details/126958601:萬惡的 eval()

https://juejin.cn/post/7078924628525056007 : npm run xxx