今日更新完畢,不定期補充,建議關注收藏點贊。
目錄
- 簡介
- Loader和Plugin的不同?(必會)
- 使用
- webpack默認只能處理js文件 ->引入加載器
- 對JS語法降級,兼容低版本語法
- 合并文件
- 再次打包
- 進階
- 工作原理
- Webpack 的熱更新原理(必會)
- webpack與grunt、gulp的不同?(必會)
- tree shaking
- html-webpack-plugin插件
- webpack的開發服務器:devServer
- 引入
- 使用webpack-dev-server模塊:熱更新
簡介
官網
- webpack作用(自動整合壓縮并剔除無用代碼)
減少文件數量、縮小代碼體積、提高瀏覽器打開速度- 優點
- 專注于處理模塊化的項目,能做到開箱即用,一步到位
- 通過plugin擴展,完整好用又不失靈活
- 通過loaders擴展, 可以讓webpack把所有類型的文件都解析打包
- 社區龐大活躍更新,能為大多數場景找到已有的開源擴展
- webpack定義
nodejs第三方模塊包, 用于識別翻譯壓縮打包整合代碼
支持所有類型文件的打包
支持less/sass => css
支持ES6/7/8 => ES5
壓縮代碼, 提高加載速度
webpack基于node, 所以導出遵守CommonJS規范。
webpack是一個打包模塊化javascript的工具,在webpack里【一切文件皆模塊】,通過loader轉換文件,通過plugin注入鉤子,最后輸出由多個模塊組合成的文件,webpack專注構建【模塊化】項目
python一切皆對象;
JavaScript 的“幾乎一切皆對象” —— 但并不是絕對的。原始類型(Primitive Types)不是對象,它們是 值類型(by value),不可變,不是對象,雖然原始類型不是對象,但當你調用它們的方法時,JS 會臨時把它們“包裝成對象”;特殊情況:null,這個是歷史遺留的 bug ,雖然typeof null 為"object" 但 null 本質上不是對象,也不能調用方法。
- 安裝
- 初始化文件夾包環境, 得到package.json文件
- 下載webpack等模塊包
- 在package.json自定義命令, 為打包做準備
yarn init
yarn add webpack webpack-cli -D#在配置文件中 配置自定義命令
scripts: {"build": "webpack"
}
Loader和Plugin的不同?(必會)
- 不同的作用
? Loader直譯為"加載器"。Webpack將一切文件視為模塊,但是webpack原生是只能解析js文件,如果想將其他文件也打包的話,就會用到loader。 所以Loader的作用是讓webpack擁有了加載和解析非JavaScript文件的能力。
? Plugin直譯為"插件"。Plugin可以擴展webpack的功能,讓webpack具有更多的靈活性。 在 Webpack 運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。 - 不同的用法
? Loader在module.rules中配置,也就是說他作為模塊的解析規則而存在。 類型為數組,每一項都是一個Object,里面描述了對于什么類型的文件(test),使用什么加載器(loader)和使用的參數(options)
? Plugin在plugins中單獨配置。 類型為數組,每一項是一個plugin的實例,參數都通過構造函數傳入。
使用
- 默認src/index.js – 打包入口文件
- 引入到入口的文件才會參與打包
- 上述配置文件中的自定義命令,使得:執行package.json里build命令則執行webpack打包命令
- 默認輸出dist/main.js的打包結果
- 借助webpack, 把模塊和代碼打包后,需要將打包結果引入到項目中生效。不希望“手動引入”這么麻煩的,可以安裝html-webpack-plugin插件。其使用方法見后。
- 更改webpack打包默認的入口和出口
新建webpack.config.js
填入配置,entry設置為入口文件路徑,output對象設置出口路徑和文件名
打包觀察效果
- 例子:webpack打包代碼–jquery實現功能
注意:webpack打包后的js需要引入到html中使用才能生效
步驟:
①:從0準備環境, 初始化包環境, 下載webpack和webpack-cli包, 配置自定義命令build
②:yarn下載jquery, 新建public/index.html,寫入內容
③:src/main.js 引入jquery, 編寫功能代碼
④:執行打包命令
⑤:復制public/index.html到dist/, 然后引入打包后的js, 運行網頁觀察效果
webpack默認只能處理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 代碼 - 處理css文件
css文件引入到入口里,webpack打包css文件依然會報錯。如何讓webpack能處理css文件:使用下面的兩個加載器
css-loader 文檔
style-loader文檔
css-loader 讓webpack能處理css類型文件
style-loader 把css插入到DOM中(插入到head下style標簽內)
- 下載加載器
yarn add css-loader style-loader -D
- webpack.config.js配置
module.exports={//其他配置 這里略module:{rules:[{test:/\.css$/i, //i 忽略大小寫use:["style-loader","css-loader"] }]}
}
- 打包觀察效果:css代碼被打包進js文件中,style-loader會把css代碼插入到head下style標簽內
- 處理less文件
加載器使用less-loader
less-loader加載器作用: 識別less文件
less作用:將less編譯為css
yarn add less less-loader -D
//配置module:{rules:[//其他配置略{test:/\.less$/,use:["style-loader","css-loader","less-loader"] }]}
步驟:新建src/less/index.less,把index.less引入到入口處,下載加載器和less來處理less文件,webpack.config.js針對less配置,(打包)轉換成css后還需要css-loader和style-loader的處理。
- 處理字體文件、圖片文件
webpack5, 使用asset module技術實現字體文件和圖片文件處理, 無需配置額外loader,文檔: https://webpack.docschina.org/guides/asset-modules/
以前用url-loader和file-loader來處理
現在webpack.config.js – 針對圖片文件設置type: “assets“,然后打包,小于8KB文件則轉base64打包在js中, 大于8KB, 文件自動命名輸出到dist下;字體和圖片文件同理。
//配置module:{rules:[//其他配置略{test:/\.(png|jpg|gif|jpeg)$/i,type:'asset'}]}
為什么要區分8kb上下?
圖片翻譯成了base64, 放到了js文件中
-好處: 瀏覽器不用發請求了,直接可以讀取, 速度快
-壞處: 圖片太大,再轉base64
就會讓圖片的體積增大 30% 左右, 得不償失
- 處理字體圖標
- 注意:字體圖標 v.s. 字體文件
字體文件 和 字體圖標(icon fonts) 是兩個相關但不完全一樣的東西。 - 字體文件,用于文本顯示。常見格式包括:
.ttf(TrueType Font)
.otf(OpenType Font)
.woff / .woff2(Web Open Font Format)
.eot(Embedded OpenType) - 字體圖標(Icon Fonts)將圖標圖形設計成字體的形式,用 CSS 和 HTML 字符來顯示圖標。
典型例子:Font Awesome、iconfont 阿里巴巴、Material Icons (Google)
它們通常包含以下資源:
字體文件(.woff, .ttf, .eot, .svg)
一個 style.css 或 iconfont.css,映射圖標 class 到字體字符,通過字體的形式顯示圖標,比如<i class="icon-home"></i>
就能顯示一個小房子圖標。
- 注意:字體圖標 v.s. 字體文件
.icon-home:before {content: "\e600";
}
- 如何處理字體圖標
- src/assets 下 放入fonts字體相關文件夾
- src/main.js 引入 assets/fonts/iconfont.css
import '@iconfont/iconfont.css';
- src/main.js 創建一個i標簽, 使用字體圖標標簽添加到body上;或者html中使用圖標
<i class="icon-home"></i>
- 在webpack.config.js的rules里針對字體圖標文件類型設置asset/resource,直接輸出到dist下:添加針對字體文件的加載器規則, 使用asset/resource(直接輸出文件并配置路徑)
const path = require('path');module.exports = {// 其他配置...module: {rules: [// 處理字體圖標文件{test: /\.(woff2?|eot|ttf|otf|svg)$/,type: 'asset', //或asset/resource,generator: {filename: 'fonts/[hash][ext][query]', // 輸出路徑},},
//其他配置略...],},
};
- 打包后運行網頁觀察效果:在webpack.configjs的rules里針對字體圖標文件類型設置asset/resource, 直接輸出到dist下
對JS語法降級,兼容低版本語法
babel: 一個javascript編譯器, 把高版本js語法降級處理輸出兼容的低版本語法
babel-loader: 可以讓webpack轉譯打包的js代碼
babel官網: https://www.babeljs.cn/
babel-loader文檔: https://webpack.docschina.org/loaders/babel-loader/
- 在src/main.js – 定義箭頭函數, 并打印箭頭函數變量 (千萬不能調用, 為了讓webpack打包函數, 看降級效果)
- 下載加載器
yarn add babel-loader @babel/core @babel/preset-env -D
- 配置到webpack.config.js上
module.exports = {// 其他配置...module: {rules: [{test: /\.js$/,exclude:/(node_modules|bower_components)/,use:{loader:'babel-loader',options:{presets:['@babel/preset-env']//預設:轉碼規則(用bable開發環境本來預設的)}}},
//其他配置略...],},
};
- 打包觀察是否降級
合并文件
- 2個js文件 ->打包成1個js文件
新建src下的資源:add.js – 定義求和函數并導出,index.js – 引入add模塊并使用函數輸出結果
執行yarn build
自定義命令, 進行打包 (確保終端路徑在src的父級文件夾)
打包后默認生成dist和dist/main.js, 觀察其中代碼
再次打包
- 代碼增加后, 如何打包呢?
- 確保在src/index.js引入和使用
- 重新執行yarn build打包命令
進階
- mode 模式
Webpack 的 mode 參數告訴 webpack 使用哪種內置的優化方式。
三種模式:
development 開發模式:優化構建速度,生成未壓縮的代碼,帶有詳細的錯誤信息和注釋。
production 生產模式:優化構建結果,如代碼壓縮、tree shaking,適合上線部署。
none 什么優化都不做,純原始打包。你需要自己手動配置所有優化。
module.exports = {mode: 'development' | 'production' | 'none'
}
- 把css文件都獨立打包提取成一個css文件在dist下
在使用 Webpack 打包時,要將 CSS 提取成獨立的文件,可以使用 mini-css-extract-plugin 插件。
安裝這些依賴:mini-css-extract-plugin+ css-loader+ style-loader。
在 Webpack 配置文件中進行相應的配置:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');module.exports = {entry: './src/index.js', // 入口文件output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js', // 輸出的 JavaScript 文件},module: {rules: [{test: /\.css$/, // 匹配所有 .css 文件use: [MiniCssExtractPlugin.loader, // 提取 CSS'css-loader', // 解析 CSS],},],},plugins: [new MiniCssExtractPlugin({filename: '[name].css', // 輸出的 CSS 文件名}),],mode: 'production', // 使用生產模式
};
運行 Webpack 打包:打包完成后,輸出目錄(dist/)中會生成一個 bundle.js(包含打包后的 JavaScript)和一個單獨的 .css 文件(比如 main.css)。
- 把vue文件讓webpack打包使用(百度vue-loader官網)
想要把App.vue的東西顯示到index.html
(1): 在public/index.html 準備id叫app的div
(2): yarn add vue - 必須下載vue (和其他加載器和插件-具體參考vue-loader官網)
(3): 需要在main.js中引入[App.vue]模塊對象并加入如下代碼
import App from './App.vue' // 引入vue文件
import Vue from 'vue' // 引入vue.js對象new Vue({ render: h => h(App) // 渲染函數, 渲染App組件里的標簽
}).$mount('#app') // 把vue文件的標簽結構 -> 掛載到id為app的標簽里
(4): 打包后運行dist/index.html, 觀察是否把vue文件里的標簽渲染到頁面了
工作原理
- yarn build
所有要被打包的資源都要跟入口產生直接/間接的引用關系
- 總結
yarn build后執行webpack命令,找到配置文件、入口和依賴關系,打包代碼輸出到指定位置 - webpack構建流程:從讀取配置到輸出文件這個過程盡量說全(必會)
Webpack 的運行流程是一個串行的過程,從啟動到結束會依次執行以下流程:- 初始化參數:從配置文件讀取與合并參數,得出最終的參數
- 開始編譯:用上一步得到的參數初始化 Compiler 對象,加載所有配置的插件,開始執行編譯
- 確定入口:根據配置中的 entry 找出所有的入口文件
- 編譯模塊:從入口文件出發,調用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理
- 完成模塊編譯:在經過第4步使用 Loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內容以及它們之間的依賴關系
- 輸出資源:根據入口和模塊之間的依賴關系,組裝成一個個包含多個模塊的 Chunk,再把每個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最后機會
- 輸出完成:在確定好輸出內容后,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統。
在以上過程中,Webpack 會在特定的時間點廣播出特定的事件,插件在監聽到感興趣的事件后會執行特定的邏輯,并且插件可以調用 Webpack 提供的 API 改變 Webpack 的運行結果
Webpack 的熱更新原理(必會)
? webpack 的熱更新又稱熱替換(Hot Module Replacement),縮寫為 HMR。這個機制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。
? HMR的核心就是客戶端從服務端拉去更新后的文件,準確的說是 chunk diff (chunk 需要更新的部分),實際上 WDS(Webpack Dev Server) 與瀏覽器之間維護了一個 Websocket,當本地資源發生變化時,WDS 會向瀏覽器推送更新,并帶上構建時的 hash,讓客戶端與上一次資源進行對比。客戶端對比出差異后會向 WDS 發起 Ajax 請求來獲取更改內容(文件列表、hash),這樣客戶端就可以再借助這些信息繼續向 WDS 發起 jsonp 請求獲取該chunk的增量更新。
? 后續的部分(拿到增量更新之后如何處理?哪些狀態該保留?哪些又需要更新?)由 HotModulePlugin 來完成,提供了相關 API 以供開發者針對自身場景進行處理,像react-hot-loader 和 vue-loader 都是借助這些 API 實現 HMR。
webpack與grunt、gulp的不同?(必會)
? 三者都是前端構建工具,grunt和gulp在早期比較流行,現在webpack相對來說比較主流,不過一些輕量化的任務還是會用gulp來處理,比如單獨打包CSS文件等。
? grunt和gulp是基于任務和流(Task、Stream)的。類似jQuery,找到一個(或一類)文件,對其做一系列鏈式操作,更新流上的數據, 整條鏈式操作構成了一個任務,多個任務就構成了整個web的構建流程。
? webpack是基于入口的。webpack會自動地遞歸解析入口所需要加載的所有資源文件,然后用不同的Loader來處理不同的文件,用Plugin來擴展webpack功能。
- 從構建思路來說
? gulp和grunt需要開發者將整個前端構建過程拆分成多個Task
,并合理控制所有Task
的調用關系。
webpack需要開發者找到入口,并需要清楚對于不同的資源應該使用什么Loader做何種解析和加工 - 對于知識背景來說
gulp更像后端開發者的思路,需要對于整個流程了如指掌。 webpack更傾向于前端開發者的思路。
tree shaking
Tree Shaking 是 Webpack 的一項重要優化技術,用于“搖掉”項目中未被使用的代碼(通常是未被引用的 ES6 模塊導出),從而減小打包體積、提升性能。
Tree shaking 是一種死代碼消除(Dead Code Elimination)技術。它的工作原理基于 ES6 的模塊靜態結構(import/export),可以在編譯階段分析哪些代碼是未被使用的,并從最終的 bundle 中刪除它們。
- 使用 Tree Shaking 的條件
想讓 Webpack 正常進行 tree shaking,需要滿足幾個前提:
- 使用 ES Module(不是 CommonJS)
//commonJS版本
module.exports = { add, multiply } // 無法 tree shake//ES模塊化版本
// utils.js
export function add(a, b) { return a + b }
export function multiply(a, b) { return a * b }// main.js
import { add } from './utils'
console.log(add(2, 3)) // multiply 未使用,將被移除
- mode: ‘production’
Webpack 只在 生產模式 下默認啟用 tree shaking 和代碼壓縮 - 代碼沒有副作用(side effects)
什么叫代碼副作用?副作用,簡單說就是:代碼在運行時除了導出內容,還會對外部環境產生影響。如果只是定義導出,但并沒有什么實質影響,不會修改樣式/打印日志等。
Tree shaking 不會刪除具有副作用的代碼。你可以通過在 package.json 中添加:
{"sideEffects": false //表示你的模塊無副作用,Webpack 就可以放心地去搖樹了。
}
//如果有些文件有副作用(比如 CSS 引入),可以排除它們
{"sideEffects": ["*.css"]
}
- 如何驗證 tree shaking 生效?
打包結果變小(觀察輸出文件體積)
使用 webpack --mode production --analyze + webpack-bundle-analyzer
檢查生產代碼里是否真的去掉了未用的代碼
html-webpack-plugin插件
webpack打包時自動生成html文件,無需手動引入。文檔
- 安裝
yarn add html-webpack-plugin -D #下載
#--save-dev 和 -D 是完全等價的
dependencies 是你項目運行時需要用到的依賴(比如 React、Vue 這些核心庫)。
devDependencies 是你在開發階段才需要用的依賴(比如 Webpack、Babel、ESLint、TypeScript 這些工具)。即- D
- 在webpack.config.js中添加配置
const HtmlWebpackPlugin =require('html-webpack-plugin')
module.exports={//其他配置 這里略plugins:[new HtmlWebpackPlugin({template:'./public/index.html' //webpack打包時自動生成html文件})]
}
webpack的開發服務器:devServer
webpack開發服務器, 把代碼運行在內存中, 自動更新, 實時返回給瀏覽器顯示。
打包在內存中, 速度快;自動更新打包變化的代碼, 實時返回給瀏覽器顯示;
引入
每次修改代碼, 重新 yarn build 打包, 才能看到最新的效果, 實際工作中, 打包 yarn build 非常費時 (30s - 60s);
原因:
從0構建依賴
磁盤讀取對應的文件到內存, webpack開始加載
再用對應的 loader 進行處理
將處理完的內容, 輸出到磁盤指定目錄
解決:起一個開發服務器, 緩存一些已經打包過的內容, 只重新打包修改的文件, 最終運行在內存中給瀏覽器使用
使用webpack-dev-server模塊:熱更新
webpack-dev-server文檔: https://webpack.docschina.org/configuration/dev-server/
- 下載模塊包
yarn add webpack-dev-server -D
- 在package.json-配置自定義命令:自定義webpack開發服務器啟動命令serve在package.json里
"scripts":{"build":"webpack","serve":"webpack serve"
}
- 啟動當前工程里的webpack開發服務器
yarn serve
,webpack-dev-server會給一個地址+端口瀏覽器,訪問即可看到在內存中打包的index.html頁面 - 重新編寫代碼, 觀察控制臺和瀏覽器是否自動打包和更新
- 改變webpack-dev-server配置
webpack-dev-server配置文檔: https://webpack.docschina.org/configuration/dev-server/#devserverafter
在webpack.config.js中添加如下配置,重啟webpack開發服務器即可
都是去文檔中找配置項的名字,在webpack.config.js – devServer選項里添加
module.exports={//其他配置略devServer:{port:8888 //自定義端口號}
}