現在的前端,一定都用過Vue或者React,多多少少都有接觸過webpack,我還清楚地記得第一次看Vue的Webpack配置時,彷彿在看天書通常。webpack做爲前端工程化的核心知識之一,由於其功能太多,配置項又多又雜,初學時也比較難啃。css
這是一個面向初學者的webpack系列博文。從0開始,一步步搭建出完整的、適用於常規環境的webpack配置。html
每章都以樹狀結構擴深知識點,儘量的涵蓋更多更深的知識內容,同時保留每一個章節的全部代碼。前端
首先建立一個文件,而後執行 npm init
webpack
隨後建立對應子文件夾git
.webpackLemo // 文件夾
│
│-- config // 存放配置文件
│
│-- public // 存放模板
│
│-- src // 存放入口文件
│
└─- package.json
複製代碼
咱們有了基本文件夾,接下來開始構建最基本配置,能知足平時寫demo用。github
首先安裝webpack工具庫web
npm i webpack webpack-cli
算法
建立入口文件npm
// src/index.js
console.log("Webpack Lemo");
複製代碼
// public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webpack Lemo</title>
</head>
<body>
<script src="./main.js"></script> //打包後的文件爲 main.js 在這裏手動寫入
</body>
</html>
複製代碼
建立配置文件json
// config/webpack.config.js
const path = require('path');
module.exports = {
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, '../build')
}
}
複製代碼
entry :入口起點配置。簡單來講,由html直接引用的文件稱爲入口起點,從這個起點開始,應用程序啓動執行。例子中的
main
爲入口起點的 [name] 值output:輸出配置。webpack打包完成,怎麼輸出,要輸出哪些文件,輸出到哪等相關信息的配置
output.path
要求接受一個絕對路徑。path.resolve
方法會把一個路徑或路徑片斷的序列解析爲一個絕對路徑,__dirname
指向當前文件的路徑entry 配置裏使用的是相對路徑,這個路徑默認指向代碼被執行時路徑,即 webpackLemo 文件夾的根目錄。可經過設置 context 來修改路徑上下文。
// 與正文中的配置效果等同 { context: path.resolve(__dirname), entry: { main: '../src/index.js' } } 複製代碼
// package.json
{
...
"scripts": {
"dev": "webpack --config ./config/webpack.config.js"
},
...
}
複製代碼
接下來只需在命令行裏執行 npm run dev
就能進行第一次打包
先忽視 warning ,能夠看見webpack自動打包了 src
目錄下的文件,在根目錄下自動生成build文件,並將打包後的入口文件命名爲 main.js 放入build文件中。
而後咱們能夠把 public 目錄下的 index.html 手動複製到 build 目錄下。
完成以上操做後,咱們的目錄會長成這樣
.webpackLemo
│
│-- build // 存放打包後的文件
│ │-- main.js // src/index.js打包生成的文件
│ │-- index.html // 從public中手動複製
│
│-- config
│ │-- webpack.config.js // 新建webpack配置文件
│
│-- public
│ │-- index.html // 新建html模板文件
│
│-- src
│ │-- index.js // 新建入口文件
│
└─- package.json
複製代碼
用瀏覽器打開 ./build/index.html,能夠看見控制檯裏輸出了 在 ./src/index.js 裏寫的 console.log信息
若是每次打包,都須要咱們手動粘貼一次 index.html,那也太麻煩了。若是有一個哥們兒能 幫咱們自動複製index.html文件,而且在index.html中自動引入咱們打包後的文件 那就行了。
這個哥們兒叫作 html-webpack-plugin 。
執行安裝 npm i html-webpack-plugin
而後修改文件
// public/index.html
<!DOCTYPE html>
<html lang="en">
...
<body>
// <script src="./main.js"></script> // 刪除手動寫入的 對main.js的引用
</body>
</html>
複製代碼
// config/webpack.config.js
...
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
output: {
...
filename: '[name].bundle.js', // 添加filename配置
},
plugins: [ // 注意是個數組
new HtmlWebpackPlugin({ // 在plugin中使用 html-webpack-plugin
template: './public/index.html' // 配置模板項地址
}),
]
}
複製代碼
plugins:配置webpack插件的地方
filename 配置項中使用了[name],這裏的[name]爲輸出的模塊名。除了[name],webpack還提供了別的模板語法,可在這裏找到全部信息 output.filename
如今咱們再執行 npm run dev
能夠看見此次打包生成的文件名爲main.bundle.js,而且 build 目錄下的index.html 文件裏自動引入了 main.bundle.js
完成以上操做後,咱們的目錄會長成這樣
.webpackLemo
│
│-- build
│ │-- main.js // 第一次打包生成的文件
│ │-- main.bundle.js // 第二次打包生成的文件
│ │-- index.html // 使用 html-webpack-plugin 後生成的html文件
│
...
複製代碼
能夠看見第二次打包時,咱們修改了輸出配置,生成了新的文件,可是第一次打包的內容仍是被保留了下來。其實第一次打包的內容已經用不上了,有沒有什麼哥們兒能幫咱們自動刪除不須要的內容?
有,這個哥們兒叫作 clean-webpack-plugin
執行安裝 npm i clean-webpack-plugin
而後修改文件
// config/webpack.config.js
...
// 引入clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
...
output: {
path: path.resolve(__dirname, '../build'),
filename: '[name].[contenthash].js', // 咱們再修改一次輸出文件名
},
plugins: [
...
new CleanWebpackPlugin(); // 使用 clean-webpack-plugin
]
}
複製代碼
如今咱們第三次執行 npm run dev
,能夠看見build目錄下頭兩次生成的入口文件都被清除了,只保留了第三次生成的內容。
完成以上操做後,咱們的目錄就長成這樣
.webpackLemo
│
│-- build
│ │-- main.417cd68a8235c5cd4f89.js // 第三次打包生成的文件
│ │-- index.html
│
...
複製代碼
到目前爲止,已經支持了基本功能打包,下一步來處理css樣式和file文件
對css文件的處理有2種方式:
將css代碼以 <style>
標籤的形式嵌入 html 中
生成css文件,以 <link>
標籤的形式在 html 中引入
這裏咱們只討論第一種形式,第二種會在 代碼分割(衛星) 中介紹
咱們須要4個插件
<style>
標籤的形式嵌入 html 中loader和plugin的區別 :
// 官方文檔原文 While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables. // 渣譯 loader通常用來轉換某些類型的modules,而插件能夠用來執行更普遍的任務,例如對包的優化、資源管理、環境注入等 // 大白話 loader是一個轉換器,將A文件進行編譯成B文件,好比:將A.less轉換爲A.css,單純的文件轉換過程。 plugin是一個擴展器,豐富了webpack自己,針對是loader結束後,webpack打包的整個過程,它並不直接操做文件,而是基於事件機制工做,會監聽webpack打包過程當中的某些節點,執行普遍的任務 複製代碼
執行安裝 npm i style-loader css-loader postcss-loader autoprefixer
而後修改文件
// ./config/webpack.config.js
...
module.exports = {
...
module: { // 這裏是對象
rules: [ // 這裏是數組
{ // 數組中的每一個具體配置
test: /\.css$/, // 匹配 .css文件
use: [ // 當匹配上 .css 文件後,會依次使用loader進行處理
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
}
]
}
]
}
}
複製代碼
module:各類模塊應該如何處理,由module進行配置
loader的處理順序爲從下到上。正文中loader處理順序爲:postcss-loader、css-loader、style-loader
// ./src/index.js
import './index.css'
...
複製代碼
// ./src/index.css
body {
width: 100%;
height: 200px;
background-image: linear-gradient(to right, red , yellow);
}
複製代碼
// ./package.json
{
...
"browserslist": [
"iOS >= 6",
"Android >= 4",
"IE >= 9"
]
}
複製代碼
browserslist 用來配置 咱們的應用會在哪些平臺、哪些瀏覽器和瀏覽器版本上使用。 autoprefixer 會讀取該項值,用來以爲須要添加哪些前綴,若是運行在最新的瀏覽器上,也許不會添加相應的前置信息
browserslist 默認值:> 0.5%, last 2 versions, Firefox ESR, not dead
如今執行 npm run dev
,build 目錄裏沒有新增 .css文件,用瀏覽器打開 ./build/index.html 文件,能夠看見背景有個漸變色,從控制檯裏能夠看見樣式代碼以 <style>
標籤的形式嵌入到了html中,而且自帶了廠商前綴
完成以上操做後,咱們的目錄就長成這樣
.webpackLemo
│
│-- src
│ │-- index.js
│ │-- index.css // 新增長的css代碼
│
...
複製代碼
less其實就是css的預處理器,一些代碼裏可能會用sass,可是原理相似,這裏就用less舉例
在上一節的基礎上,額外安裝一個 less-loader
處理less文件
執行安裝 npm i less-loader
而後修改文件
// ./config/webpack.config.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader', // 只增長一行less-loader 處理less文件
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
}
]
}
]
}
}
複製代碼
// ./src/index.js
import './index.less' // 引入less文件
...
複製代碼
// ./src/index.less
body {
width: 100%;
height: 200px;
background-image: linear-gradient(to right, red , yellow);
}
複製代碼
執行 npm run dev
,獲得的效果和處理css同樣
完成以上操做後,咱們的目錄就長成這樣
.webpackLemo
│
│-- src
│ │-- index.js
│ │-- index.css
│ │-- index.less
│
...
複製代碼
其實只要是文件,均可以處理,這裏用圖片文件舉例
可用2種 loader 進行處理
這兩個loader做用比較相似,最大的區別在於 file-loader 會生成文件, url-loader 會把文件數據壓縮成base64直接使用,不會生成文件。二者能一塊兒使用,在某些場景下比使用單一loader效果更好,可參考 這篇博文(衛星)
這裏我用file-loader舉例
執行安裝 npm i file-loader
而後修改文件
// ./config/webpack.config.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
}
複製代碼
// ./src/index.js
...
import img from '../statics/imgs/img.jpg'
const myimg = new Image();
myimg.src = img;
document.body.appendChild(myimg);
...
複製代碼
執行 npm run dev
,能夠看見build文件裏增長了打包後的圖片文件,打開 ./build/index.html 後也能看到相應的圖片被掛載到頁面上
完成以上操做後,咱們的目錄就長成這樣
.webpackLemo
│
│-- build
│ │-- 051fa5032109fbc8005c856a48cf1c52.jpg
│ │-- index.html
│ │-- main.a14556a5d43741e69cdd.js
│
│-- statics // 存放靜態資源
│ │-- imgs // 存放圖片
│ │ │-- img.jpg
│
...
複製代碼
到如今,咱們已經支持css打包和文件打包,本身寫demo時,使用這樣的webpack配置已經OK了,可是我每次改了代碼都要從新執行一次 npm run dev
,真的太麻煩,若是能讓webpack自動刷新頁面就行了。
讓咱們來構建一個開發環境,讓咱們每次更新的時候,webpack能自動幫咱們打包,而且能實時刷新頁面.
要能實現實時刷新頁面,webpack提供了3種能力
這裏咱們採用 webpack-dev-server
執行安裝 npm i webpack-dev-server
而後修改文件
// ./config/webpack.config.js
...
module.exports = {
mode: 'development', // 設置mode爲'development'模式
devtool: 'cheap-module-eval-source-map', // 設置source-map
devServer: {
contentBase: './build',
open: true
},
...
}
複製代碼
mode:至關於設置一套預設優化配置,默認爲
none
。詳細可查看 官網文檔devtool:用於配置source-map,用來加強調試能力,不一樣的值會影響構建和重構建的速度。 詳細可查看 官方文檔
// package.json
{
...
"scripts": {
// 把dev改爲build
"build": "webpack --config ./config/webpack.config.js",
// 這裏改爲dev,並使用新命令項
"dev": "webpack-dev-server --config ./config/webpack.config.js"
},
...
}
複製代碼
接下來執行 npm run dev
,webpack幫咱們啓動了一個端口號爲8080的服務器,並自動打開了瀏覽器,咱們修改代碼,能自動幫咱們打包新代碼,並刷新頁面。
到這裏,一個能打包、能處理css、處理文件、自啓服務器、修改代碼後能自動打包,自動刷新頁面的配置就完成了。這樣一個簡單的配置已經實現我的寫demo的需求,例如跑跑算法代碼,測試一段代碼的輸出等等。
本章使用:
庫
webpack、webpack-cli
webpack工具庫webpack-dev-server
webpack web-serverloader
file-loader
解析經過模塊化方式引入的文件,輸出成文件url-loader
(非必要) 經過模塊化方式引入的文件,以base64的形式輸出style-loader
將css代碼以 <style>
標籤的形式嵌入 html 中css-loader
解析經過模塊化引入的css文件postcss-loader
提供預處理css的一些能力,擁有許多子插件,提供了許多能力less-loader
(非必要) 解析less代碼文件plugins
clean-webpack-plugin
每次打包能清空打包文件夾裏以前的內容html-webpack-plugin
能自動生成Html文件,並自動引入打包生成的js文件autoprefix
postcss-loader的子插件,提供廠商前綴自動補全能力,如 -m-本章節代碼倉庫:代碼倉庫
本章節Github-blog: Github-blog
若是文中有錯誤/不足/須要改進/能夠優化的地方,但願能在評論裏友善提出,做者看到後會在第一時間裏處理
若是你喜歡這篇文章,👍點個贊再走吧,github的星星⭐是對做者持續創做的支持❤️️