30分鐘掌握 Webpack
本文基於: 峰華前端工程師--30分鐘掌握Webpack
為什麼使用 Webpack
在我們進行傳統網頁開發中,會在 index.html
中引入大量的 js
和 css
檔案,不僅可能會導致命名衝突,還會使頁面體積變大,因為如果引用了第三方庫,需要載入所有的程式碼。而在 node.js
出現後, javascript
專案支援通過 require
支援模組化開發了,並且支出 npm
方便地管理依賴。
藉著 node.js
和瀏覽器js 的一致性,前端專案開始在 node.js
下開發,完成之後把程式碼構建成瀏覽器支援的形式。對於 react
或 vue
這種元件化的開發方式,因為有很多分散的檔案,那麼久特別需要這樣的構建操作。
Webpack
就是進行這一步構建操作的,把 node.js
模組化的程式碼轉化為瀏覽器可執行的程式碼。它提供了 import
和 export
ES6模組化語法的支援,然後通過分析程式碼中 import
匯入的依賴,把需要的程式碼載入進來。在 Webpack
中,任何檔案都可以通過 import
匯入,只要有對應的 loader
就可以了。在打包過程中,還可以通過外掛來干預打包過程,例如剔除不必要的程式碼,形成體積更小的專案。
建立專案
-
開啟命令列工具,我們在這裡建立一個名為
blog
的部落格專案:mkdir blog cd blog yarn init -y (或者npm init)
-
新增
webpack
依賴:yarn add webpack webpack-cli --dev
-
使用
VSCode
開啟專案:code .
初出茅廬
-
在
blog
專案下新建src
檔案下,建立index.js
:console.log("Hello World");
我們先只做一個簡單的輸出.
-
在
blog
專案下新建index.html
:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello World</h1> <script src="./dist/index.js"></script> </body> </html>
-
使用
LiveServer
檢視剛剛所編寫的 html頁面:可以看到瀏覽器成功顯示了 "Hello World",並且控制檯也能夠成功輸出.
-
嘗試使用
webpack
打包開啟控制檯,輸入
npx webpack
npx 能夠直接執行 node_modules
下面安裝的庫的自帶的命令列,而不用寫 node_modules
下一串的絕對路徑。
打包完成後可以看到專案裡面生成了一個 dist
目錄,裡面有一個 main.js
檔案,其內部的內容和我們剛剛所編寫的 index.js
的檔案一模一樣,這是因為我們並沒有使用任何 import
來匯入其他的依賴。
使用 import 匯入依賴
-
在
src
下新建一個data.js
檔案:export function getBlogPosts() { return ["部落格1", "部落格2", "部落格3"]; }
-
在
index.js
中匯入data.js
中的函式並呼叫:import { getBlogPosts } from "./data"; console.log(getBlogPosts());
-
重新使用
webpack
打包以下,檢視結果:npx webpack
現在進入
/dist/main.js
中看一下,程式碼被簡化成了直接輸出剛才我們所編寫的陣列的語句,說明webpack
自動判斷了我們所編寫程式碼的邏輯,並通過import
語句得到了我們所引入的程式碼,分析後生成新的js
檔案. -
在網頁中檢視下結果:
成功地輸出了陣列.
Webpack 配置檔案
webpack
的配置檔案可以說是 webpack
最核心的部分了,我們可以在配置檔案中修改入口和出口檔案、通過 loader
載入不同型別的檔案和使用 plugins
對程式碼做其他的操作。
嘗試修改打包後生成檔案的名稱
-
在專案中新建
webpack.config.js
檔案:const path = require("path"); module.export = { mode: "development", // 設定為開發模式,方便除錯 entry: "./src/index.js", output: { filename: "dist.js", path: path.resolve(__dirname, "dist"), // 設定檔名和目錄 } }
-
執行
npx webpack
命令打包可以看到
dist
資料夾下多了個dist.js
檔案.
使用模組化語法
-
修改
/index.html
的script
標籤:<script src="./dist/dist.js"></script>
將
main.js
修改成為我們剛剛使用webpack
打包生成的dist.js
-
修改
/src/index.js
檔案,將之前編寫的陣列變成ul
元素插入頁面中:const blogs = getBlogPosts(); const ul = document.createElement("ul"); blogs.forEach(blog => { const li = document.createElement("li"); li.innerText = blog; ul.appendChild(li); }) document.body.appendChild(ul);
-
npx webpack
:列表成功插入到了頁面.
引入 css
-
在
src
下新建style.css
檔案:h1 { color: blueviolet; }
這裡只是簡單地改變
h1
標籤的顏色. -
在
/src/index.js
中引入css
檔案:import "./style.css";
-
安裝
loader
:開啟控制檯,輸入:
yarn add --dev style-loader css-loader
-
在
webpack.config.js
中配置loader
module.exports = { mode: "development", output: {...}, ... module: { rules: [{ test: /\.css$/i, use: ["style-loader", "css-loader"], }] } }
module -> rules -> test 內是一個正則表示式,表示以 .css 結尾的檔案.
use 屬性下是所使用的
loader
-
再次使用
npx webpack
打包:可以看到,剛才寫的樣式生效了.
載入圖片
-
webpack
原生支援圖片等靜態檔案,但是需要在webpack.config.js
中編寫配置:module.exports = { ... module: { rules: [ ... { test: /\.(png|svg|jpg|jpeg|gif)$/i, type: "assets/resource", }] } }
-
在
src
下載新建assets/
資料夾,放入一張圖片: -
在
index.js
中引入圖片:import AbcImage from "./assets/abc.png" ... const image = document.createElement("img"); image.src = AbcImage; document.body.prepend(image);
-
npx webpack
:
自動生成 HTML
上述的例子中,我們只是使用 webpack
來打包 js
和 css
檔案,並手動的匯入編寫好的 html
中,使用下面的外掛,就可以自動為我們生成 HTML 檔案。
-
安裝外掛:
yarn add html-webpack-plugin --dev
-
使用外掛:
const HtmlWebpackPlugin = require("html-webpack-plugin"); ... plugins: [new HtmlWebpackPlugin({ title: "部落格列表", // 這裡可以自定義網頁的標題 })],
-
npx webpack
:可以看到生成了和剛才相同的頁面
使用 webpack
打包出來的網頁沒有顯示 <h1>Hello World</h1>
的原因是 這個標籤是我們自己寫的:open_mouth:
-
定義打包好 html 檔案的網頁標題
我們使用
html-webpack-plugins
打包生成的檔名預設是 Webpack App ,其實網頁標題是可以在外掛內傳遞引數來更改的:plugins: [new HtmlWebpackPlugin({ title: "部落格列表", })],
Babel
有時我們的程式碼可能需要執行在更低版本的瀏覽器上,這些瀏覽器可能並不支援我們所寫的更高階的程式碼,這時就需要用到 babel
轉譯工具來使我們的程式碼變成瀏覽器能夠識別的程式碼。
-
安裝
babel-loader
相關依賴:yarn add --dev babel-loader @babel/core @babel/preset-env
-
在
webpack.config.js
中新增配置:rules: [ ... { test: /\.js$/, // 識別js為結尾的檔案 exclude: /node_modules/, //不解釋node_modules/下的檔案 use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"] } } }]
這裡可以在
module.exports
下配置devtool="inline-source-map"
方便檢視打包後的原始碼 -
使用
npx webpack
重新打包下,進入dist/dist.js
檢視相關程式碼:/* 打包前的 */ blogs.forEach(blog => { const li = document.createElement("li"); li.innerText = blog; ul.appendChild(li); })
blogs.forEach(function (blog) { var li = document.createElement("li"); li.innerText = blog; ul.appendChild(li); });
可以看到 箭頭函式已經被轉換成了
.forEach
的形式,增強了對瀏覽器的相容性。
使用 Terser 外掛壓縮打包後的程式碼
-
安裝外掛:
yarn add --dev terser-webpack-plugin
-
配置:
// webpack.config.js const TerserPlugin = require("terser-webpack-plugin"); module.exports = { ... optimization: { minimize: true, minimizer: [new TerserPlugin()], }, }
-
打包:
npx webpack
可以看到我們打包生成的 js 檔案都被緊密地寫在了一起,右鍵屬性檢視檔案大小也要比之前的小一些。:sunglasses:
使用 DevServer 外掛自動打包
-
安裝:
yarn add -dev webpack-dev-server
-
配置:
module.exports = { ... devServer: { static: "./dist", }, }
為了我們以後方便執行開發伺服器,還需要在
package.json
裡新增一個script
:{ ... "scripts": { "start": "webpack serve --open" }, }
-
啟動伺服器:
yarn start // 或 npm run start
-
嘗試一下 "熱更新?"
在
index.js
下新增如下程式碼:const header1 = document.createElement("h1"); header1.innerText = "Hello"; document.body.appendChild(header1);
-
儲存,檢視網頁
這裡不在使用 VsCode 的
Live Server
外掛了,而是在瀏覽器位址列輸入命令列中輸出的地址:成功!:clap:
那麼 webpack 是如何實現熱更新的呢?其實是在我們每次儲存時,外掛自動生成新的
dist.js
並把之前的dist.js
寫入快取,這或多或少會增加我們電腦的開銷。但 webpack 貼心的為我們想到了這一點。 -
每次打包生成新的
/dist.js
配置
webpack.config.js
output: { filename: "[name].[contenthash].js", // name 預設為 main path: path.resolve(__dirname, "dist"), },
更改下
index.js
程式碼,執行npx webpack
可以看到生成了檔案字尾名不同的檔案,這樣可以避免由於瀏覽器快取機制而導致更新不及時的問題。
配置目錄別名:
和之前寫的 http://www.cnblogs.com/hhsk/p/16460701.html 大同小異
- 配置:
// webpack.config.js module.exports = { ... resolve: { alias: { assets: path.resolve(__dirname, "src/assets") } } }
- 執行緒池底層原理詳解與原始碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裡都有
- 【前端必會】webpack loader 到底是什麼
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8原始碼解讀
- 詳解JS中 call 方法的實現
- 列印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang程式碼
- Springboot之 Mybatis 多資料來源實現
- CAS核心思想、底層實現
- 面試突擊86:SpringBoot 事務不回滾?怎麼解決?
- 基於electron vue element構建專案模板之【打包篇】
- MiniWord .NET Word模板引擎,藉由Word模板和資料簡單、快速生成檔案。
- 認識執行緒,初始併發
- 1-VSCode搭建GD32開發環境
- 初識設計模式 - 原型模式
- 執行緒安全問題的產生條件、解決方式
- 2>&1到底是什麼意思?