webpack 4.x一起學習(二)
接著上一塊https://juejin.im/post/5be29710e51d457e90193cf3
模組:CSS檔案打包
Webpack在生產環境中有一個重要的作用就是減少http的請求數,就是把多個檔案打包到一個js裡,這樣請求數就可以減少好多。在學習CSS打包之前,需要先對webpack.config.js裡的Loaders配置項進行了解。
Loaders(以下所有的配置都是基於3版本的 如果過程中有bug 會進行改進)
Loaders是Webpack最重要的功能之一,他也是Webpack如此盛行的原因。通過使用不同的Loader,Webpack可以的指令碼和工具,從而對不同的檔案格式進行特定處理。
簡單的舉幾個Loaders使用例子:
可以把SASS檔案的寫法轉換成CSS,而不在使用其他轉換工具。
可以把ES6或者ES7的程式碼,轉換成大多瀏覽器相容的JS程式碼。
可以把React中的JSX轉換成JavaScript程式碼。
注意:所有的Loaders都需要在npm中單獨進行安裝,並在webpack.config.js裡進行配置。下面我們對Loaders的配置型簡單梳理一下。
test:用於匹配處理檔案的副檔名的表示式,這個選項是必須進行配置的;
use:loader名稱,就是你要使用模組的名稱,這個選項也必須進行配置,否則報錯;
include/exclude:手動新增必須處理的檔案(資料夾)或遮蔽不需要處理的檔案(資料夾)(可選);
query:為loaders提供額外的設定選項(可選)。
打包CSS檔案
建立index.css檔案 ./src/css/index.css
要打包CSS你必須先要有個CSS檔案,在/src目錄下,我們建立一個css資料夾,在資料夾裡建立index.css檔案。程式碼內容如下
body{
background-color: red; 可以跟我不一樣 完全為了測試
color: white;
}
CSS檔案建立好後,需要引入到入口檔案中,才可以打包到,這裡我們引入到entry.js中。
/src/entery.js中在首行加入程式碼:
import css from './css/index.css';
也就是在entry.js中頂部匯入
import css from './css/index.css';
document.getElementById('title').innerHTML='Hello Webpack';
CSS和引入做好後,我們就需要使用loader來解析CSS檔案了,這裡我們需要兩個解析用的loader,分別是style-loader和css-loader
首先我們先使用npm 安裝(有些腳手架生成的webpack 會自動安裝這些簡單的載入器)
npm install style-loader css-loader --save-dev
一步到位
安裝好之後檢視一下package.json
兩個loader都下載安裝好後,我們就可以配置我們loaders了。
loaders配置:
修改webpack.config.js中module屬性中的配置程式碼如下:
webpack.config.js
const path = require('path')
module.exports={
mode: 'development',
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑文職
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [ =>以前此處是loaders 現在是rules
{
test: /\.css$/, =>正則 這個好理解
use: [ 'style-loader', 'css-loader' ] =>使用css 與 style loader 來載入匹配到的css檔案
}
]
},
//外掛,用於生產模版和各項功能
plugins:[],
//配置webpack開發服務功能
devServer:{
host:'localhost', //伺服器的ip地址
port:1573, //埠
}
}
webpack一下,之前我們在js中引入了css 執行一下html ok 有樣式了
友情提示:小夥伴們在測試的時候,可能會遇到找不到模組的 這種error 建議重新新建配置 重新npm外掛 剛才我就莫名其妙找不到模組了 重新安裝了一下就可以了
loader的三種寫法:
有些小夥伴看到別人的CSS打包的寫法和我的寫法不太一樣,是不是我寫錯了,loader還有幾種寫法,這裡我們就看兩種另外的寫法。
使用use
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
},
把use換成loader。
module:{
rules:[
{
test:/\.css$/,
loader:['style-loader','css-loader']
}
]
},
第三種寫法:用use+loader的寫法:
module:{
rules:[
{
test:/\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader"
}
]
}
]
},
沒有全測 也不知道哪裡需要修改 小夥伴可以自行測試一下
接下來我們來試著壓縮一下js
在Webpack中可以很輕鬆的實現JS程式碼的壓縮,它是通過外掛的方式實現的,這裡我們就先來引入一個uglifyjs-webpack-plugin(JS壓縮外掛,簡稱uglify)。
注意:雖然uglifyjs是外掛,但是webpack版本里預設已經整合,不需要再次安裝。
const path = require('path')
const webpack =require('webpack') =>注意這裡我們引入了webpack
module.exports={
mode: 'development',
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑文職
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
},
//外掛,用於生產模版和各項功能
plugins:[
new webpack.optimize.UglifyJsPlugin() =>因為是webpack整合的 所以要在上方引入webpack
]
}
此時我們webpack一下 你會發現 報錯(報錯的內容就不截圖了)
在webpack4.0版本中已經廢棄了之前 UglifyJsPlugin的用法,用的是optimization.minimize
重新配置一下webpack
const path = require('path')
刪除了webpack模組引入
const UglifyJsPlugin=require('uglifyjs-webpack-plugin');=>需要 npm 手動安裝
module.exports={
mode: 'development',
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑文職
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
},
//外掛,用於生產模版和各項功能
plugins:[
],
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
compress: false
}
})
]
},
}
這裡需要注意一下 webpack打包也是分模式的 預設是mode ‘production(生產環境)’
如果我們沒在config.js中標明webpack 的mode 直接webpack是會有警告的
就是說我們打包的命令完整應該是 webpack --mode production/development
預設是production 此方法打包檔案會小很多 注意一下即可
production 其實預設自帶了uglifyjs-webpack-plugin 外掛 已經不需要使用
也就是我們在production 狀態下 其實可以不需要配置 直接 webpack --mode development 即可
接下來我還是設定預設 production 環境下測試 方便點
外掛配置:HTML檔案的釋出
webpack 構建專案時, 通過指定的入口檔案,會將所有的js css 等以依賴模組的形式打包成一個或多個的指令碼檔案,通常情況下,指令碼檔案會附屬於html 檔案執行,這時候需要將 打包好的指令碼檔案,注入到html 中, html-webpack-plugin 外掛的目的是, 以一個html 為模板, 將打包好的指令碼注入到模板中, 相關的配置如下
先安裝 html-webpack-plugin
npm i html-webpack-plugin -D
安裝好之後 我們在plugins中配置
const path = require('path')
const htmlPlugin = require('html-webpack-plugin'); =>引入模組
module.exports={
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑文職
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
},
//外掛,用於生產模版和各項功能
plugins:[
new htmlPlugin({ =>這是一般情況下的配置 打包html
minify:{
removeAttributeQuotes:true
},
hash:true,
template:'./src/index.html'
})
],
}
minify:是對html檔案進行壓縮
hash:為了開發中js有快取效果,所以加入hash,這樣可以有效避免快取JS。
template:是要打包的html模版路徑和檔名稱。
此時我們webpack --mode production
此時dist下生成了 index.html js是上面的命令生成的 這就是我們常見的狀態了 熟悉vue的小夥伴都知道 npm run build就會生成這倆檔案 此時我們直接開index.html 也是有效果的 如果需要改名的話可以再配置一個引數 filename:‘filename.html’ 一定要加字尾
圖片邁坑:CSS中的圖片處理
在學習Webapck過程中你可能遇到的第一個坑就是CSS中的圖片處理。很多webpack新手都在圖片的坑中無法自拔(有的小夥伴在開發環境中是可以找到圖片的,但是一打包後就找不到圖片了,有的小夥伴是不知道如何正確引入html或者css中的圖片,導致程式出錯)
圖片寫入css 我們先找張圖片先 http://img1.imgtn.bdimg.com/it/u=198855387,108109132&fm=26&gp=0.jpg
注意一定要本地圖片啊 剛才偷懶使用網路圖片發現居然成功了 不能成功 一定要失敗的
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack</title>
</head>
<body>
<div id="tupian"></div>
<script src="./../dist/bundle.js"></script>
</body>
</html>
index.css css還是在js中引入
#tupian{
background-image: url('./../image/1.jpg');
width:466px;
height:453px;
}
我們這時候 通過webpack --mode production 是會失敗的 失敗的原因就是缺少loader的解析
對於圖片我們也需要安裝兩loader
安裝file-loader和url-loade
npm install --save-dev file-loader url-loader
file-loader:解決引用路徑的問題,拿background樣式用url引入背景圖來說,我們都知道,webpack最終會將各個模組打包成一個檔案,因此我們樣式中的url路徑是相對入口html頁面的,而不是相對於原始css檔案所在的路徑的。這就會導致圖片引入失敗。這個問題是用file-loader解決的,file-loader可以解析專案中的url引入(不僅限於css),根據我們的配置,將圖片拷貝到相應的路徑,再根據我們的配置,修改打包後文件引用路徑,使之指向正確的檔案。
url-loader:如果圖片較多,會發很多http請求,會降低頁面效能。這個問題可以通過url-loader解決。url-loader會將引入的圖片編碼,生成dataURl。相當於把圖片資料翻譯成一串字元。再把這串字元打包到檔案中,最終只需要引入這個檔案就能訪問圖片了。當然,如果圖片較大,編碼會消耗效能。因此url-loader提供了一個limit引數,小於limit位元組的檔案會被轉為DataURl,大於limit的還會使用file-loader進行copy。
安裝好之後我們來配置webpack 直接在module中配置loader
const path = require('path')
const htmlPlugin = require('html-webpack-plugin');
module.exports={
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑文職
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [
{
test: /\.css$/, => css的loader
use: [ 'style-loader', 'css-loader' ] =>這邊順帶提一下 其實webpack的loader是從右往左看
=>也就是 先使用css loader 再使用style loader
},
{
test:/\.(png|jpg|gif)/ , =>圖片的loader
use:[{
loader:'url-loader',
options:{
limit:500000 =>不認識limit的小夥伴可以自行百度一下 類似我們的流量 哈哈 好吧其實就是指500000B
}
}]
}
]
},
//外掛,用於生產模版和各項功能
plugins:[
new htmlPlugin({
minify:{
removeAttributeQuotes:true
},
hash:true,
template:'./src/index.html'
})
],
}
接下來我們webpack --mode production 即可 成功生成
為什麼只使用了url-loader
有的小夥伴會發現我們並沒有在webpack.config.js中使用file-loader,但是依然打包成功了。我們需要了解file-loader和url-loader的關係。url-loader和file-loader是什麼關係呢?簡答地說,url-loader封裝了file-loader。url-loader不依賴於file-loader,即使用url-loader時,只需要安裝url-loader即可,不需要安裝file-loader,因為url-loader內建了file-loader。通過上面的介紹,我們可以看到,url-loader工作分兩種情況:
1.檔案大小小於limit引數,url-loader將會把檔案轉為DataURL(Base64格式);
2.檔案大小大於limit,url-loader會呼叫file-loader進行處理,引數也會直接傳給file-loader。
也就是說,其實我們只安裝一個url-loader就可以了。但是為了以後的操作方便,我們這裡就順便安裝上file-loader。
###圖片邁坑:CSS分離與圖片路徑處理
CSS分離:extract-text-webpack-plugin
有些簡單的互動頁面中,你的JavasScript頁面程式碼會非常少,而大部分程式碼都在CSS中,這時候專案組長會要求把CSS單獨提取出來,方便以後更改。遇到這個需求你不要驚慌,已經有大神為我們準備好了物件的外掛(plugin)
這個外掛就可以完美的解決我們提取CSS的需求,但是webpack官方其實並不建議這樣作,他們認為CSS就應該打包到JavasScript當中以減少http的請求數。但現實中的需求往往不是我們前端能控制的,有些需求是我們不能控制的,分離CSS就是這樣一個既合理由不合理的需求,說白了,還是得聽老大的 ,如果小姐姐讓你這樣你做不做呢?
npm install --save-dev extract-text-webpack-plugin
安裝好了自然要用 我們直接在webpack上方 引入 const extractTextPlugin = require("extract-text-webpack-plugin")
引入之後 我們只需在webpack中new 使用 並且還要配置關於css的載入器
const path = require('path')
const htmlPlugin = require('html-webpack-plugin');
const extractTextPlugin = require("extract-text-webpack-plugin")
module.exports={
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑位置
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [
{
// test: /\.css$/,
// use: [ 'style-loader', 'css-loader' ]
test: /\.css$/,
use: extractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test:/\.(png|jpg|gif)/ ,
use:[{
loader:'url-loader',
options:{
limit:500000
}
}]
}
]
},
//外掛,用於生產模版和各項功能
plugins:[
new htmlPlugin({
minify:{
removeAttributeQuotes:true
},
hash:true,
template:'./src/index.html'
}),
new extractTextPlugin("/css/index.css") =>注意外掛的使用 (此處是生成的檔案位置 前面配置了path 預設都是dist檔案下的)
],
}
此時我們webpack一下 是有錯誤的 因為extract-text-webpack-plugin 不支援4版本以上的
我們既然學習4版本的webpack肯定不能降級 好 我們升級
npm install --save-dev [email protected]
安裝好之後 其餘不變 再次 webpack一下 因為此時生成打包了三個檔案 我給截圖一下
這樣就成功分離了 本來是起初我們匯入js中的 此時成功生成了index.css 並且裡面的url是base64形式的,但是我們此時瀏覽dist下的html是沒有東西的 因為我們路徑有問題 這裡是指圖片路徑 不是檔案路徑
圖片路徑問題
利用extract-text-webpack-plugin外掛很輕鬆的就把CSS檔案分離了出來,但是CSS路徑並不正確,很多小夥伴就在這裡搞個幾天還是沒有頭緒,網上也給出了很多的解決方案,我覺的最好的解決方案是使用publicPath解決
publicPath:是在webpack.config.js檔案的output選項中,主要作用就是處理靜態檔案路徑的。
此處增加一個知識 webpack-dev-server 本來是不想配置後面給大家簡單提一下,畢竟單獨測試webpack的真的不多,很多時候都是看webpack或者腳手架生成直接修改
測試publicPath的時候 沒設定伺服器狀態老報錯 使用live-server也不好配置 所以簡單提一下webpack-dev-server的配置
npm install webpack-dev-server –save-dev
先安裝
在webpack.config.js 中配置
plugins:[
new htmlPlugin({
minify:{
removeAttributeQuotes:true
},
hash:true,
template:'./src/index.html'
}),
new extractTextPlugin("/css/index.css")
],
devServer:{ =>注意 與plugins同級
//設定基本目錄結構
contentBase:path.join(__dirname,'dist'),
//伺服器的IP地址,可以使用IP也可以使用localhost
// 不知道自己IP的可以 開啟cmd 輸入ipconfig 檢視
host:'localhost',
//服務端壓縮是否開啟
compress:true,
//配置服務埠號
port:1717
}
在packge.json的 scripts 中輸入"dev": "webpack-dev-server --open"
我們啟動webpack-dev-server的時候只需要npm run dev 即可
啟動webpack-dev-server之後 會啟動熱更新 當我們改變內容儲存的時候會自動進行webpack命令打包 實時更新內容
別忘了我們主要的目的 ,解決圖片路徑問題 使用publicPath
主要看output模組
const path = require('path')
const htmlPlugin = require('html-webpack-plugin');
const extractTextPlugin = require("extract-text-webpack-plugin")
module.exports={
// mode:'development',
//入口檔案的配置項
entry:{
//裡面的entery是可以隨便寫的
entry:'./src/entry.js',
},
//出口檔案的配置項
output:{
//打包的路徑文職
path:path.resolve(__dirname,'dist'),
//打包的檔名稱
filename:'bundle.js',
publicPath:'localhost:1717'
},
//模組:例如解讀CSS,圖片如何轉換,壓縮
module:{
rules: [
{
// test: /\.css$/,
// use: [ 'style-loader', 'css-loader' ]
test: /\.css$/,
use: extractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test:/\.(png|jpg|gif)/ ,
use:[{
loader:'url-loader',
options:{
limit:500000
}
}]
}
]
},
//外掛,用於生產模版和各項功能
plugins:[
new htmlPlugin({
minify:{
removeAttributeQuotes:true
},
hash:true,
template:'./src/index.html'
}),
new extractTextPlugin("/css/index.css")
],
devServer:{
//設定基本目錄結構
contentBase:path.resolve(__dirname,'dist'),
//伺服器的IP地址,可以使用IP也可以使用localhost
host:'localhost',
//服務端壓縮是否開啟
compress:true,
//配置服務埠號
port:1717
}
}