前言
我們在使用webpack時,經常會看到類似以下結構:
build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js
很多時候,webpack的配置我們基本複製粘貼過來的,沒有想過為什麼我們要把配置文件拆解成這麼多。因此,當我們自己去學習配置webpack時,我們經常會出現以下等問題:
- 開發環境構建速度慢
- 打包後頁面空白
- 資源找不到
其實這些問題,都源於我們:
- 不理解
webpack構建開發環境、生產環境,兩種環境配置的思想差異 - 對兩種環境輸出的文件目錄,腦海中沒有一個清晰的理解
所以本文還是跟以前一樣,不會一味的把配置複製過來,而是希望總結相關方法,讓大家更好學會配置。
前期準備
由於講的是配置,所以希望你對webpack有一些基礎。如果你只是剛學習webpack,建議先閲讀一下前兩篇文章,尤其是第二篇:
- 弄懂這幾個概念後,我對webpack有了更新的理解:學習使用
webpack時涉及到的一些概念,讓我們對webpack整體有個大致的瞭解 - 有了這些方法,webpack你也可以自己配:總結配置
webpack時的一些方法。通過這些方法,我們可以很好的理解webpack的一些基礎配置該如何配置
學習大綱
這篇文章主要講解:
webpack開發環境配置的核心思想- 根據核心思想,完成一個開發環境配置
- 解析
devServer配置項一些容易混淆的點 - 總結
webpack開發環境配置核心
備註
文章涉及到的案例已經上傳到 github:
- 為了閲讀方便,文章只貼了相關代碼,建議
fork一下,看看完整代碼;或者跟着文章一起邊看邊敲,這樣印象會更深刻一些 - 創作不易,如果覺得有幫助的話,歡迎
star🌟
開發環境核心思想
在上文我們提到,我們在使用webpack時,經常會看到類似以下目錄:
build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js
為什麼我們需要把配置文件拆解成這麼多,那麼繁瑣呢?
我們先回顧一下,在我們在實際開發中,為了項目能夠穩定安全上線,我們一般會分好幾個環境:
- 開發環境:在本地進行開發,調試的環境
- 測試環境:我們在本地開發完成後,將代碼部署到我們的測試服務器,進行測試
- 生產環境:測試通過,將代碼部署到正式服務器,正式上線
有些更嚴格的測試,還會有預生產環境等
我們的配置應該對環境具有針對性,因此不同的環境,我們的配置當然不能千篇一律。
目的
我們要先清楚開發環境根本的目的是什麼。
開發環境的根本目的,就是在開發過程中,能快速定位到問題,更快能看到效果調試,提高開發效率。
尤其作為前端,離不開跟視覺打交道。我們巴不得Ctrl+S後,立馬出效果,方便我們快速調試。試想一下,如果每次寫完一個效果,要等上幾秒鐘才能看到,這會不會把我們逼瘋?
思想
因此,為了能讓我們儘快看到效果調試,減少webpack的編譯過程,開發環境,配置應該一切從簡:
- 對樣式,我們不需要分離,直接用
style-loader插入到<head /> - 對
js、img、media、font等前端資源文件,不需要分包 - 開啓
source map,方便定位問題 - 使用
webpack提供的devServer配置項,進行本地開發 - 不要壓縮代碼
- 不用沒必要的
loader跟plugins - ...
開發環境配置,也因人而異,以上是我的做法。但是我們要記得,開發環境,配置應該一切從簡,為了讓我們能夠更快看到效果,提高開發效率
開發環境配置
初體驗
通過前一篇文章的講解,相信大家對webpack的基礎配置:
- 處理
css、less、前端資源等文件 - 編譯
es6+語法及api - 處理
html文件
已經掌握了相關的配置方法,並且我們還總結了一份基礎的配置,不太清楚的同學可以看一下先,這個基礎配置還是蠻重要的。
ok,那我們先用 learn-08 這個案例來體驗一下如何進行本地開發調試。為了儘量貼近我們現實中開發的項目,案例裏會:
- 在
html裏面引用圖片 - 使用
less裏面引用圖片 - 在
js裏使用es6+,動態加載圖片 - 使用
devServer配置項
為了閲讀方便,具體的源碼就不放文章了,大家可以去 github 看
然後進行以下步驟:
- 為了語義化,我們把
webpack配置文件命名為webpack.dev.js -
使用命令行啓動
webpack——npm start"scripts": { "start": "webpack server --config ./webpack.dev.js" }
運行結果:
我們會發現:
- 文件編譯處理完成後,不會輸出任何文件
- 此時開啓了一個內部服務器(
http://192.168.0.196:8080/)。如果我們的手機與電腦用的同個網絡,用手機訪問這個鏈接,就能看到效果了。這對調試H5開發是十分高效的(這主要歸功於deveServer配置項,後文會有講解) - 我們修改代碼後,頁面會實時更新
以上幾乎是我們想要的高效開發效果。
分析
初步體驗完後,我們根據上文總結的開發環境配置思想,來看看對開發環境該如何配置:
-
解析樣式不需要分離出
css文件,我們直接將解析出來的樣式插入到<header />中:module: { rules: [ { test: /.(css|less)$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] }, ] }, -
對
js、img、media、font等前端資源文件,不需要分包:output: { path: path.resolve(__dirname, './dist'), filename: '[name]-[chunkhash:5].js', }, module: { rules: [ { test: /\.(png|svg|jpg|jpeg|gif)$/i, type: 'asset', parser: { dataUrlCondition: { maxSize: 1024 * 3 // When the image size is < 3kb it will be converted to base64 } }, generator: { filename: '[name]-[hash:5][ext]' // Set the name of the output file } }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader' } } ] }, -
開啓
source map,方便定位問題;並且不壓縮代碼:{ mode: 'development', devtool: 'inline-cheap-module-source-map' } -
使用
webpack提供的devServer進行本地開發:devServer: { static: { directory: path.join(__dirname, 'static'), }, }, -
沒有安裝其他多餘的
plugin,因為要解析html,所以只安裝瞭解析html的pluginplugins: [ new HtmlWebpackPlugin({ filename: path.resolve(__dirname, './dist/[name].html'), template: path.resolve(__dirname, './src/index.html'), title: 'webpack.dev.config', }) ],我們對比一下基礎配置,會發現開發環境配置跟基礎配置幾乎沒差別,只是多使用了
devServer配置項,來開啓本地服務器調試:
// webpack.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
+ mode: 'development',
+ devtool: 'inline-cheap-module-source-map',
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name]-[chunkhash:5].js',
},
module: {
rules: [
{
test: /.(css|less)$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 1024 * 3 // When the image size is < 3kb it will be converted to base64
}
},
generator: {
filename: '[name]-[contenthash:5][ext][query]' // Set the name of the output file
}
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, './dist/[name].html'),
template: path.resolve(__dirname, './src/index.html'),
title: 'webpack.dev.config',
})
],
+ devServer: {
+ static: {
+ directory: path.join(__dirname, 'static'),
+ },
+ }
}
devServer
還記得我們之前的案例,是怎麼運行我們的代碼的嗎?我們都是打包完以後,用自帶的編輯器(vscode)運行查看結果的。要是我們平時開發是這麼低效的話,那估計項目不用上線了。
因此webpack提供了一個十分人性化的配置項——devServer。
想使用這個配置項,我們需要先npm i webpack-dev-server -D安裝webpack-dev-server依賴
從這麼語義化的名字就知道,它肯定是開發環境下,可以提供某種服務的配置。
這個服務就是,這將會開啓一個本地服務,將我們配置的webpack,實時編譯,保存在內存中,這樣可以方便調試我們的代碼,這很好的滿足了我們本地開發需要高效的目的。
因此這個配置項,只用於我們開發環境配置
devServer.static
文檔解釋:告訴服務器從哪裏提供內容。只有在你希望提供靜態文件時才需要這樣做
錯誤理解
devServe配置項,其實文檔已經寫的挺詳細了,這裏講一個可能容易混淆的配置項——devServe.static。
很多人使用webpack,都是複製粘貼,所以經常會看到下面這種配置:
output: {
path: path.resolve(__dirname, './dist'),
}
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
}
}
因為我們設置的打包後輸出的文件夾一般都是dist,devServe.static配置項指定要提供的靜態文件目錄也是dist。所以,我們自然而然會以為,此時webpack開啓的本地服務器訪問的內容就是dist文件夾裏面的內容。
因此,我們會得出錯誤的結論:devServe.static的作用就是,設置webpack開啓的本地服務器時,訪問的目錄。
但是,我們可以看看上文的 dev.config.js,我們設置打包後輸出的文件夾名稱是dist,devServe.static設置的目錄是static。如果按照我們上文錯誤的理解,由於兩個文件夾設置不同,此時我們服務器應該是404或者空白頁面才對,但是我們依舊可以跑起我們的服務。
這説明devServe.static的作用,並不是設置webpack開啓的本地服務器時,訪問打包輸出文件夾的目錄。
正確理解
分析
我們繼續看 learn-08 這個案例(static文件夾裏面存放了logo.png圖片)。
我們之前想在js裏面引用相關圖片,我們一般會這麼做:
// index.js
const img = new Image();
img.src = require('Your image path');
我們一般是將圖片根據相對路徑require進來,此時圖片相當於是一個模塊(Module),因此這樣圖片會經過webpack編譯打包(添加hash或者轉成base64),最後寫入到我們設置的最終目錄(output.path)。
但是當我們設置了:
devServer: {
static: {
directory: path.join(__dirname, 'static'),
}
}
開啓本地服務器後,會有這一句提示:
Content not from webpack is served from 'your path/static' directory
首先,這説明我們設置的static這個目錄,是不會經過webpack處理打包的,所以在這個文件夾裏面的資源,是不會被webpack解析編譯的,因此它也不會加上hash或轉成base64。
我們再來看看 learn-08 的index.js是如何使用static裏的資源的:
// index.js
loadImage('./logo.png').then(img => {
console.log('I am from index.js');
img.width = 120;
document.querySelector('#js_content .img_content').append(img);
});
我們會看到,我們是直接使用./的方式引入圖片,説明webpack開啓的本地服務器,會將我們設置的static的目錄內容映射到根目錄下。
用過vue-cli的同學應該能很好體會到,這其實就是vue-cli裏面public文件夾的功能
我們可以用以下方式訪問設置的devServer.static.directory文件夾裏的內容:
- 一般情況下
devServer.static.directory會被映射到根目錄,所以我們用http://[devServer.host]:[devServer.port]/[devServer.static.directory]訪問 - 如果想改變訪問的路徑,可以增加
devServer.static.publicPath配置。此時可以用http://[devServer.host]:[devServer.port]/[devServer.static.publicPath]/[devServer.static.directory]訪問
總結
經過上面的分析講解,我們可以得出對devServer.static正確的理解應該是:
- 它是設置一個存放,不經過
webpack編譯的靜態資源目錄(我們可以例如圖片,第三方資源等),所以它不會被加上hash或者被轉成base64;它是一個目錄 - 開啓
webpack本地服務器時,它一般會被映射到我們的項目的根目錄下(可以通過devServe.static.publicPath修改訪問目錄) - 由於它不經過
webpack編譯打包,所以,我們最後一般會用copy-webpack-plugin,將devServer.static.directory複製到output.path根目錄下 - 它的功能就很像是
vue-cli裏面的public文件夾,我們開發的時候,可以通過./或者../訪問到那個資源(具體看目錄關係)
核心
好,通過上面對開發環境配置跟devServer的講解,我們可以知道:
- 開發環境配置一切從簡,所以
img、js等資源會直接映射在根目錄下(css被插入到<head />裏了) - 開發環境
webpack開啓本地服務器後,也會將devServer.static.directory映射在根目錄下
所以運行開發環境配置後,我們的結構目錄大致如下:
dist
├── ecj-cli-b6fa8.png
├── index-c466b.js
├── index.html
└── logo.png
配置因人而異,最重要的是,我們配置完開發環境,生產環境後,對編譯打包輸出內容,目錄,腦海中有一個很好地結構認識,這是非常重要的。
這個目錄結構也請大家牢記,後面的文章會用到
我們可以通過以下方法查看開發環境的結構目錄:
devServer.devMiddleware.writeToDisk: truehttp://[devServer.host]:[devServer.port]/webpack-dev-server- 谷歌瀏覽器
F12 -> Sources
最後
- 本篇文章學習了開發環境如何配置,下篇文章將會講解配置生產環境前一些準備,讓後續我們更好的學習生產環境配置
- 感興趣的同學,可以關注一下這個 👉 專欄
- 文章涉及到的案例已經上傳到 github,真的歡迎
star或fork學習
最後的最後,如果大家覺得文章有幫助到,創作不易,還請大家多點贊轉發;如果有異同點,歡迎評論討論。