扯淡的話
我認為,學(xué)習(xí)這種工具類型的技能,掌握基礎(chǔ)部分的話,后面的就是只需要記住和主動去學(xué)習(xí)屬性配置就會玩的很好。
這一部分就是通過各種各樣的loader和plugin的屬性配置來將基礎(chǔ)部分的webpack配置。
明顯存在的問題
在lesson1中有很多明顯的問題:
- 1、css代碼冗雜在js代碼中
- 2、打包出來的文件一直為一個bundle.js會引起瀏覽器緩存
- 3、開發(fā)代碼和打包發(fā)布(生產(chǎn))代碼沒有嚴格區(qū)分
- 4、無圖片,json等其他文件類型的處理
那么下面便一點點的解決上述的問題:
抽離CSS代碼
在webpack4之前,可以用extract-text-webpack-plugin這個插件來解決這一問題。webpack4 暫不支持extract-text-webpack-plugin 所以需要使用extract-text-webpack-plugin@next版本 或者使用 mini-css-extract-plugin
配置也是非常簡單:
第一步需要在匹配到css代碼時用到這個插件:
{
test: /\.css$/,
use: [MiniCSSExtractPlugin.loader, 'css-loader'], // 使用MiniCSSExtractPlugin.loader來處理css代碼
exclude: '/node_modules/'
}
第二步是在plugins屬性中配置MiniCSSExtractPlugin
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: 'index.html',
title: 'DevServer'
}),
new MiniCSSExtractPlugin({
filename: '[name].css' // 配置單獨出來的CSS文件名稱,默認為main.css
})
],
build后:

同時,index.html會自動引入bundle.js和main.css這兩個文件。打包生產(chǎn)的時候,直接把dist目錄上傳上去就ok了。
解決瀏覽器緩存問題
瀏覽器自動緩存了js和css文件是生產(chǎn)中常見的一個問題。解決方法卻是很簡單,我們只需將文件名稱完全更改html就會重慶獲取一次全新的js和css文件。為了保證文件名稱的唯一,在打包時我們采用hash值來幫助命名
// 輸出js文件名修改
output: {
filename: '[name].[hash].js',
path: path.resolve(__dirname, 'dist')
},
// 單獨抽離出來的css名稱修改
new MiniCSSExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].css'
})
build結(jié)果:

這個問題的解決方案比較簡單,但是也伴隨著另一個問題,如果我們再修改一次代碼build后,會出現(xiàn)下面這種情況:

它不會清除之前存在的文件。這里有兩個方案供大家選擇:
// 在plugins中添加這個插件配置
new CleanWebpackPlugin(['dist'], { // 接收一個數(shù)組和一個對象,數(shù)組來規(guī)定在指定目錄下刪除哪些文件,對象為配置項
root: path.resolve(__dirname) // 定義開始清空的目錄
})
這時候我們在運行build的時候就會發(fā)現(xiàn)dist文件先被刪除掉,然后生成了新的dist文件。不過還有個小缺陷就是在運行dev命令時,也會刪除掉dist文件。這個問題會在后面的優(yōu)化中解決。
第二個使用rimraf庫來完成刪除dist文件夾。這個庫提供的是rm -rf的刪除能力。關(guān)于這個清除功能,這里就不寫了,我覺得初學(xué)者這里會用上面那個插件就好。
區(qū)分dev和prod
寫到這里,前面的坑實在太多了,我必須要區(qū)分一下開發(fā)和生產(chǎn)這兩種環(huán)境了?,F(xiàn)在我要對整個項目的結(jié)構(gòu)做一些調(diào)整了:

這三個配置文件各司其職,這樣做可以將dev的功能和build的功能以及他們共有的操作抽象出來。
這三個配置文件又是相互之間有聯(lián)系的,這里要用到webpack-merge來關(guān)聯(lián)他們:
base.js:
/*
* @Author: leo
* @Date: 2018-08-28 11:50:44
* @Last Modified by: leo
* @Last Modified time: 2018-08-28 15:30:11
* webpack 基礎(chǔ)配置文件
*/
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCSSExtractPlugin = require('mini-css-extract-plugin')
// 定義resolve函數(shù)便于處理路徑
const resolve = (src) => path.resolve(__dirname, '..', src)
module.exports ={
entry: resolve('src/index.js'),
output: {
filename: '[name].[hash].js',
path: resolve('dist')
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
exclude: '/node_modules/'
},
{
test: /\.vue$/, // 匹配.vue結(jié)尾的文件
loader: 'vue-loader',
exclude: '/node_modules/'
},
{
test: /\.css$/,
use: [MiniCSSExtractPlugin.loader, 'css-loader'],
exclude: '/node_modules/'
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: 'index.html',
title: 'DevServer'
}),
new MiniCSSExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].css'
})
]
}
dev.js
/*
* @Author: leo
* @Date: 2018-08-28 11:51:03
* @Last Modified by: leo
* @Last Modified time: 2018-08-28 15:34:01
* 開發(fā)環(huán)境下的webpack配置
*/
const path = require('path')
// 定義resolve函數(shù)便于處理路徑
const resolve = (path) => path.resolve(__dirname, '..', path)
const merge = require('webpack-merge')
const Base = require('./webpack.config.base')
module.exports = merge(Base, {
devServer: {
historyApiFallback: true,
}
})
prod.js
/*
* @Author: leo
* @Date: 2018-08-28 11:54:53
* @Last Modified by: leo
* @Last Modified time: 2018-08-28 15:30:56
* webpack 生產(chǎn)配置文件
*/
const path = require('path')
// 定義resolve函數(shù)便于處理路徑
const resolve = (src) => path.resolve(__dirname, '..', src)
const merge = require('webpack-merge')
const Base = require('./webpack.config.base')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = merge(Base, {
plugins: [
new CleanWebpackPlugin(['dist'], { // 接收一個數(shù)組和一個對象,數(shù)組來規(guī)定在指定目錄下刪除哪些文件,對象為配置項
root: resolve('') // 定義開始清空的目錄
})
]
})
接下來為修改package.json的命令
"build": "webpack --mode production --config build/webpack.config.prod.js",
"dev": "webpack-dev-server --mode development --config build/webpack.config.dev.js"
這樣最基本的分離工作就完成了,還有些其他的優(yōu)化在后續(xù)會慢慢完善。
我要處理其他文件
上面所有的代碼都是圍繞js,vue文件展開的。在實際開發(fā)中,除了這些之外,我們可能還需要處理JSON文件,圖片文件,還有sass less stylus等css預(yù)處理文件(代碼)等,這就需要webpack豐富的loader來處理了。這一部分可以總結(jié)為拓展loader
- 1、處理json文件
如果是低版本(<= 2.0版本),那么處理json文件需要json-loader??梢栽谶@里看到:

由于我們這里使用的是webpack4,所以json文件是可以直接處理的
- 2、處理圖片文件
對于圖片類型的文件,webpack也有對應(yīng)的url-loader和file-loader兩種加載器來處理。這兩種loader具體有何差別呢?
url-loader相對于是file-loader的一個上層封裝,除了處理文件外,還有一個功能是限制大小,對于小于某個大小的特定圖片,可以轉(zhuǎn)換為Base64來減少請求。
// 安裝依賴
npm i url-loader file-loader --save-dev // url-loader 依賴于file-loader
// loader 配置
{
test: /\.(png|jpg|gif)$/, // 匹配png,jpg,gif這三類圖片
loader: 'url-loader?limit=8192' // 限制大小小于8192b的圖片會轉(zhuǎn)為base64(經(jīng)查閱,8192b作為分割較好)
}
為了測試效果,我準(zhǔn)備了100kb和5kb左右兩張圖片
<div class="icon">
<img src="./assets/star.png" alt="" srcset="" width="200" height="200"> <!-- 100kb -->
<img src="./assets/cz.png" alt="" width="100" height="100"><!-- 5kb -->
</div>
,啟動dev后顯示效果:

通過控制臺可以看到其代碼:

build測試:

可以看到,只打包出100kb那張圖片,而5kb的圖片則被打包到j(luò)s代碼中

將圖片設(shè)置為背景屬性和上面效果基本一致,不過base64代碼會被打包到css代碼中。
- 3、更方便的CSS預(yù)處理器
主流的CSS預(yù)處理器有sass(scss) less stylus,三者功能類似,具體使用哪個就要看個人喜好和項目需要吧。
這里我以sass(scss) 為例。
// 依賴安裝
npm i node-sass sass-loader --save-dev
// loader配置
{
test: /\.(sass|scss)$/, // 匹配sass或scss
use: [MiniCSSExtractPlugin.loader, 'css-loader','sass-loader'] // loader的處理順序是從右到左
}
現(xiàn)在,我們把之前的css代碼改造一下,用上sass的語法
<style lang="scss" scoped>
$height: 200px;
$fontColor: rgb(66, 252, 29);
@mixin bg($url, $w, $h) {
background: url($url) no-repeat 0px 0px;
background-size: $w $h;
}
.body {
color: $fontColor;
.icon-big {
height: $height;
@include bg('./assets/star.png', 200px, 200px);
}
.icon-sm {
height: $height;
@include bg('./assets/cz.png', 50px, 50px);
}
}
</style>
效果:

編譯結(jié)果,是正常的css代碼:

從css代碼到預(yù)處理器代碼,可以說是樣式編碼的一個質(zhì)的飛躍了。
截止到這里,上面比較明顯的待處理的問題都已經(jīng)完整解決。我這部分文章的中心點就是這樣,從0開始的webpack配置,一定要有自己的一些想法,然后一點一點完善,當(dāng)解決完一個問題,也許會出現(xiàn)另一個問題,而這個配置也是在慢慢完善,變得更加強大。
為Vue項目做準(zhǔn)備
既然是以作為Vue項目的webpack配置文件。那一些基礎(chǔ)的Vue依賴也要用一下:
// 安裝依賴
npm i vue-router vuex --save-dev
由于這個文章側(cè)重點是webpack,所以下面我只貼出代碼等。
目錄結(jié)構(gòu):

router/index.js
import Vue from 'vue/dist/vue.esm'
import Router from 'vue-router'
import Home from '../pages/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HOME',
component: Home,
meta: {
title: '首頁'
}
}
]
})
store/index.js
import Vue from 'vue/dist/vue.esm'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
actions: {},
mutations: {},
getters: {}
})
index.js代碼配置
import Vue from 'vue/dist/vue.esm'
import App from './App.vue'
import router from './router'
import store from './store'
const vm = new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
現(xiàn)在把之前的App.vue的代碼移到Home.vue中。App.vue修改為:
<template>
<router-view />
</template>
以上為最基本的vue項目配置
至此,一個可供使用的由webpack構(gòu)建的vue項目已經(jīng)完成。還有許多不足需要優(yōu)化。
后面會慢慢出直到配置出一個完整可用的webpack配置。