隨著前端工程化的越來越瘋狂,不會點webpack的前端真的吃不香,睡不著。
所謂webpack就是一個現代 JavaScript 應用程式的靜態模組打包器。
開胃菜
吃飯前先來一道開胃菜,看完這遍文章你會學到什麼?
- 瞭解什麼是webpack
- 知道怎麼去打包靜態資源
- 知道幾個(entrt,output,module,plugins等)核心的配置作用
- 不用vue-cli,從0到1跑起自己的vue專案
- 不用create-react-app,從0到1跑起自己的react專案
- 搭建一個既能跑vue專案也能跑react專案的配置
以上這些都是你將會學到的。
溫馨提示:建議跟著一起敲,這會加深你對每一個知識的理解和固定; 還有內容有點多,需要你靜下心來慢慢的品嚐,你會收穫到你意想不到的知識。
入門webpack
1.1初始化專案
先我們先在自己舒服的地方建立一個資料夾,資料夾裡面初始化專案。
mkdir myWebpackPro
npm init -y
複製程式碼
然後我們安裝webpack webpack-cli 到專案
npm i webpack webpack-cli -D
複製程式碼
你也可以用cnpm 或者yarn 來安裝
cnpm i webpack webpack-cli -D / yarn add webpack webpack-cli -D
複製程式碼
接著我們在myWebpack資料夾建立一個src資料夾,在裡面建立一個index.js檔案(這個將來將是我們的入口檔案)。
mkdir src
cd src
touch index.js
複製程式碼
最後我們在與src同級建立一個webpack.config.js(配置webpack的檔案)檔案
touch webpack.config.js
複製程式碼
最終的目錄結構是這樣的
到此為止,我們初始化專案就完成了。
1.2測試webpack能否正常打包
首先,我們在index.js裡面隨便**console.log()**一句
然後到package.json的script下配置一下build命令,先刪除預設的test命令,再新增build命令:
"build":"webpack ./src/index.js"
複製程式碼
最後我們再終端執行npm run build命令
npm run build
複製程式碼
如果執行成功的話在根目錄會多一個dist資料夾裡面會有一個main.js
讓我們開啟main.js看看有沒有把我們剛剛console.log()的那句話打包進去。
現在讓我們真正進入webpack配置。
1.3更改webpack的入口和預設打包的檔名
首先,我們開啟webpack.config.js配置一下entry和output
我們在頂層引進path模組,這是node內建的一個模組,無需單獨安裝,是用來出來檔案路徑的一個模組。我們的打包入口(entry)依舊是剛剛建立的那個index.js檔案,出口(output)也就是打包成功後,輸出的位置(path)和檔名(filename),我們輸出的位置依舊選擇了dist檔案下,但是輸出的檔名,我們該為了index.js(之後我們會將檔名改為動態的)
配置完這些後,我們到package.json改一下打包路徑,將之前的./src/index.js改為./webpack.config.js
我們npm run build之後依舊能打包成功。
輸出的檔名也變成了index.js,現在你會看到dist目錄下還有個main.js,是不是感到很奇怪?不用奇怪,這是我們上一次打包餘留下來的,等下我們將來說如何解決上一次打包餘留下來的檔案。
1.4新建一個index.html模版
首先,我們在src下新建一個跑public資料夾,然後在裡面新建一個index.html模版(用於我們檢視打包的js檔案,之後再用於我們vue或者react專案的唯一html渲染模版)
cd src
mkdir public
touch index.html
複製程式碼
新建完之後我們將剛才打包好的js引進去看看,瀏覽器有沒有列印出我們console.log()。
但是,當我們將output的filename改成動態之後,每次打包輸出的檔名都不一樣,那麼我們每一次打包都要重新引用一次,這樣特別麻煩。
1.5html-webpack-plugin
為了解決上面說的那個問題,我們需要安裝一下html-webpack-plugin外掛。
npm run html-webpack-plugin -D
複製程式碼
安裝完之後我們在webpack.config.js配置一下plugins。
這裡我們配置了html-webpack-plugin,也把輸入檔名改為了動態的了([name].[hash:8].js)。
我們再npm run build,然後你會看到再dist下多一個index.html。接著開啟它,發現控制檯輸出的跟我們console.log()的值一致就對了。(記得在打包前,把之前在index.html手機引進的script標籤去掉,不如打包會在控制檯會報一個找不到檔名的錯)
接下來,我們來解決,打包後自動清除之前打包的程式碼。
1.6 clean-webpack-plugin
現在你開啟dist好很多冗餘的js檔案,每次手動清除的話會非常煩躁。那我們就讓webpack來幫我們做。
首先,安裝clean-webpack-plugin。
npm i clean-webpack-plugin -D
複製程式碼
安裝完之後,我們再配置一下plugins選項。
注意⚠️:CleanWebpackPlugin是具名匯出。
最後,我們在npm run build一下,看看dist目錄下還有沒有多餘的js檔案。
soga,乾淨。
那麼,現在問題又來,我們每次改動一點js程式碼都要重新手動去打包一次,這樣真炒雞麻煩啊,那有沒有自動打包的方法呢?那麼答案來咯,當然是有的。下面我們解決這個問題。
1.7 熱更新
現在我們來解決自動打包的問題。首先,我們安裝一下webpack-dec-server,配合webpack內建的HotModuleReplacementPlugin外掛來完成熱更新。
npm i webpack-dev-server -D
複製程式碼
HotModuleReplacementPlugin不用手動下載,webpack內建。
安裝完之後,我們先來配置一下webpack.config.js檔案
配置完webpack.config.js,我們的package.json新增一條打包命令
配置完後,我們現在用npm run dev命令打包,然後我們回去更新我們index.js檔案的任何東西,儲存之後都會自動更新。
好了,現在基礎功能,我們搭建得差不多了。接下我們配置module,繼續完善最後的基礎功能,比如打包js,css,image。
1.8 打包js檔案
打包js檔案,主要是要將es6,7...的語法轉義成es5的語法,讓不相容es6,7...語法的瀏覽器也能使用。
首先我們先安裝一套包babel-loader,@babel/core,@babel/preset-env,@babel/polyfill。
npm i babel-loader @babel/core @babel/preset-env @babel/polyfill -D
複製程式碼
安裝完之後,我們來配置webpack.config.js的module。
這裡簡單介紹一下,每個loader的作用,babel-laoder主要是打包js檔案,而babel-loader又依賴@babel/core,@babel/preset-env可以轉義es6的map,every,fifler,some...語法,但是不轉義Promise,async,await...語法,所以要用@babel/polyfill來轉義。
1.9 打包css檔案
首先安裝幾個loader,style-loader,css-loader。
npm i style-loader css-loader -D
複製程式碼
安裝完,我們接著配置module
這裡只是簡單配置css檔案,可能有些專案還會用到less,scss等,這裡就不過多闡述,如果你專案用到可以到官方找一下對應的loader配置一下,都是大同小異。
2.0 打包image,font,media檔案
首先還是先安裝幾個loader,url-laoder,file-loader。
npm i url-loader file-loader -D
複製程式碼
安裝完,我們繼續配置module
介紹一下這兩個loader的配置,配置裡我們指定了limit,如果檔案沒有大於這個就用url-loader,base64打包,如果大過這個值,就會用file-loader打包,同時會按options下配置的name輸出到對應的位置。
好,基礎配置就說那麼多了,如果你的專案還有其他的需求可以到官網擼一番。
最終配置如下:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
const config = {
entry: ['@babel/polyfill', path.resolve(__dirname, './src/index.js')],
output: {
filename: '[name].[hash:8].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_module/,
use: [
{
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
}
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(mp4|webm|ogg|mp3|wav)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}
]
}
]
},
devServer: {
port: '3000',
host: '127.0.0.1',
hot: true,
open: true
},
plugins: [
new HtmlWebpackPlugin({
filename: "index.html",
template: path.resolve(__dirname, './src/public/index.html')
}),
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin()
]
}
module.exports = config
複製程式碼
從0到1跑起Vue專案
當你以上的基礎部分都熟悉了,我們從0到1搭建一個vue環境是soeasy的事。明人不說暗話,其實上面的基礎部分一直在為跑起vue專案做鋪墊。
現在我們要跑起vue專案,在以上基礎的配置上,在搞幾個loader就完事了,簡單得我都不好意思往下說了。
好了,現在我們先來安裝幾個東西,vue,vue-loader,vue-template-compiler,vuw-style-loader
npm i vue vue-loader vue-template-compiler vue-style-loader -D
複製程式碼
安裝完之後,我們來配置一下weback.config.js
這是module配置,記得在頂層匯入VueLoaderPlugin
這是plugins配置
配置完webpack.config.js之後,我們來在src下建立一個vue資料夾,然後在裡面建立一個app.vue檔案
cd src
mkdir vue
cd vue
touch App.vue
複製程式碼
目錄
接著在app.vue中,學上你熟悉的vue語法。
寫好之後,我們回到入口檔案也是src下的index,js,我們來重新寫一下里面的邏輯,之前只是console.log()一下,什麼也沒做。
最後我們的index.js檔案是這樣的。
這段程式碼對於用vue的同學再也熟悉不過來。
接著,我們回到src下的public下的index.html加一個根元素加上一個id為root。
最後,我們npm run dev一下,我們的vue專案就跑起來了。
從0到1跑起React專案
我們搭建React專案的配置,還是重基礎配置上面配置。跑起react專案的配置比vue還要簡單。
首先,我們先安裝一些東西。react,react-dom,@babel/preset-react
npm i react react-dom @babel/preset-react -D
複製程式碼
安裝完後,我們配置一下webpack.config.js
它只需要配置一下module下的js項就ok了。
接著,我們去寫一下入口檔案(index.js)的邏輯。
這段程式碼對用react的同學也是熟悉不過的了。
index.html檔案也根vue寫的一樣。
最後,我們npm run dev一下,我們的react專案的跑起來了。
到這裡,我們自己搭建Vue專案環境配置和React專案環境配置都說完了。
那麼我們怎麼可以把Vue環境跟React環境統一在放下同一個環境下,在我們學Vue的時候用Vue環境,在我們寫React的時候用React環境,這是我們接下要做的。
一套配置,兩套環境,既可跑Vue,也可跑React
我們回頭觀察一下Vue的配置跟React的配置有哪裡不一致,哪裡是一致的。
同:
entry,output
image,font,media打包
devServer和部分Plugin
不同的有:- js的loader配置,vue沒有@babel/preset-ract
- css的loader的配置,vue用的是vue-style-loader,react用的是style-loader
- vue的loader,react配置沒有
- plugin,vue多了一個VueLoaderPlugin,react沒有
好了,現在我們找出它們的異同之處了,那就好辦了。
我們需要用一個叫webapck-merge的外掛,我們安裝一下。
npm i webpack-merge -D
複製程式碼
安裝完之後,我們在webapck.config.js同級目錄下新建兩個檔案webpack.vue.js,webpack.react.js,來放它們兩者不同的配置。
touch webpack.vue.js
touch webpack.react.js
複製程式碼
接著我們來寫一下它們的不同配置。
webpack.vue.js
const merge = require('webpack-merge')
const webpackConfig = require('./webpack.config')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const config = {
module:{
rules:[
{
test:/\.vue$/,
use:['vue-loader']
},
{
test: /\.js$/,
exclude: /node_module/,
use: [
{
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
}
]
},
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
},
]
},
plugins:[
new VueLoaderPlugin()
]
}
module.exports = merge(webpackConfig,config)
複製程式碼
webpack.react.js
const merge = require('webpack-merge')
const webpackConfig = require('./webpack.config')
const config = {
module:{
rules:[
{
test: /\.js$/,
exclude: /node_module/,
use: [
{
loader: "babel-loader",
options: {
presets: ['@babel/preset-react','@babel/preset-env']
}
}
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]
}
}
module.exports = merge(webpackConfig,config)
複製程式碼
最後webpack.config.js就成這樣了。
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
const config = {
entry: ['@babel/polyfill', path.resolve(__dirname, './src/index.js')],
output: {
filename: '[name].[hash:8].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(mp4|webm|ogg|mp3|wav)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}
]
}
]
},
devServer: {
port: '3000',
host: '127.0.0.1',
hot: true,
open: true
},
plugins: [
new HtmlWebpackPlugin({
filename: "index.html",
template: path.resolve(__dirname, './src/public/index.html')
}),
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin(),
]
}
module.exports = config
複製程式碼
好了,現在我們把它們的配置拆分完畢了,還剩最後一步我們就大功告成了,那就是在package.json新增兩條命令。
在我們寫vue專案的時候,我們就用npm run vue,在寫react專案的時候,我們就用npm run react。
結尾
好了,到現在為止,我們把從基礎配置到vue到react再到合併兩套環境都做完了。原創不易,希望這篇文章能幫助到你。如果有不到位,歡迎在下面留言;如果把你看得睡著過去的,歡迎來找我,我給你暖被窩,哈哈哈;如果有把你說蒙的了或者還不明白的,歡迎來找我,我把我的剩餘的兩個口罩送一半給你。