webpack3.0小案例系列,拋磚引玉,但願你們多提意見,一塊兒學習:css
前兩節文章咱們手把手搭建了一個基於webpack的前端開發工程環境,並講解了一些經常使用插件及loader的基本用法,包括代碼分割、模板讀取、文件清理、ES6編譯及css處理等等,這篇文章我繼續在前兩篇的基礎上,繼續探討:node
webpack對圖片的處理經常使用的有url-loader、file-loader、image-webpack-loader,各個加載器都在打包過程當中有着本身的功能職責,在探討他們的使用方法以前,老規矩,咱們先弄明白他們各自都作了什麼。jquery
一、首先,咱們在src目錄下新建assets文件夾用來放置全部的靜態資源,在該目錄下咱們放入兩張圖片bg_webpack-sm.jpg 和 bg_webpack-lg.jpg,大小分別是6kb和12kb(之因此放兩張不一樣大小的圖片是用於體驗url-loader的limit參數的做用)。webpack
二、打開style.less文件,新增一個container的css類,並在index.html中添加一個類名爲container的divweb
.container{
width:300px;
height: 100px;
background: url('../assets/bg_webpack-lg.jpg')
}
複製代碼
<body>
<div id="app"></div>
<div class="container"></div>
</body>
複製代碼
三、 命令行定位到根目錄下,安裝file-loader,並在webpack配置文件中新增一條處理規則:express
cnpm install file-loader --save-dev
複製代碼
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/,
exclude: /node_modules/,
use: [{
loader: 'file-loader',
options: {}
}]
}
]
}
...
複製代碼
再次執行webpack命令進行編譯,咱們發下在dist目錄下已經打包出了咱們引用的圖片資源npm
如今,圖片文件已經打包成功了,可是咱們發現兩個問題:json
彆着急,爲了解決這兩個問題,咱們須要先對file-loader的部分配置項參數做用有一個大體的瞭解:
name ,指定打包生成後資源文件的name值,file-loader給咱們指定了一些佔位符來自定義name,咱們能夠本身任意搭配佔位符來獲得咱們想要生成的文件名稱的格式,默認狀況下是:[hash].[ext]
名稱 | 描述 |
---|---|
[ext] | 文件的後綴名,默認是原始資源的後綴名 |
[name] | 文件名稱,也就是原始資源的名稱 |
[path] | 文件存放的路徑 |
[hash] | hash值,默認是md5 |
[N] | 數字 |
publicPath ,用來指定打包生成後的css或者url引用中路徑的配置,也就是說pulicPath針對的是路徑,並非文件自己。
outputPath,用來配置打包生成的文件輸出的位置,它針對的是文件存儲的位置,和代碼中的路徑引用無關。
useRelativePath, 配置打包生成後的路徑是否爲相對位置,默認狀況下是false。須要注意的是,開啓useRelativePath後,outputPath的設置會以src目錄中的assets文件夾爲準,設置其餘的名稱不會生效。
emitFile ,配置對打包的資源文件是否須要進行發佈,默認爲true。
從這些配置項中,咱們大體能夠找到以上兩個問題的緣由:
所以針對這兩個問題,咱們對配置文件進行配置:
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/,
exclude: /node_modules/,
use: [{
loader: 'file-loader',
options: {
name: '[hash].[ext]',
outputPath: '/assets/',//定義圖片輸出存放的文件夾位置
useRelativePath: true,//設置路徑爲相對位置
}
}]
}
]
}
...
複製代碼
在配置項中,咱們定義了文件輸出的名稱以hash值來命名,並指定文件輸出到dist下的assets文件夾下,而後開啓路徑爲相對路徑,再次執行webpack編譯,發現文件已經按照設定生成到assets目錄下了。
打開dist下的index.html,圖片成功加載
固然,在設置file-loader的option的時候,因爲paublicPath會去讀取webpack出口中的publicPath的值,所以他們之間是有這聯繫的,出口中設定的publicPath不同就會致使file-loader中設定的要跟着改變,這一點要把握好。
前面咱們說過,url-loader是對file-loader的封裝,所以,使用url-loader和file-loader方法基本同樣,在這裏,咱們就探討一下他們不一樣的地方,也就是limit參數。
一、首先,咱們安裝好url-loader,並將以前的file-loader替換成url-loader,並在index.html頁面中新增類名爲container-sm的div元素。
cnpm install url-loader --save-dev
複製代碼
// webpack.config.js
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/i,
exclude: /node_modules/,
use: [{
loader: 'url-loader',
options: {
limit: 10240,
outputPath: 'assets/',
useRelativePath: true
}
}]
}
]
}
...
複製代碼
配置項中,咱們指定圖片大於10kb的圖片進行文件加載,小於10kb的文件則直接轉換出base64編碼直接寫入到css中,這樣咱們剛剛放入的兩張圖片結果應該是大的一張以圖片資源的方式加載,而小的一張則直接被編碼成base64後寫入到css文件中。最後效果以下:
能夠發現結果和咱們預計的同樣,表示url-loader已經生效。url-loader對咱們處理小型圖片頗有幫助,他能夠有效減少訪問服務端的次數,減少訪問時間,特別是針對一些icon圖標的時候頗有效果。
使用url-loader的時候,咱們須要對limit大小界限值進行權衡;base64編碼能夠減小瀏覽器的訪問次數,可是它的不足是編碼特別長,這樣很容易致使代碼體積變大。而經過路徑的方式能夠減小代碼的體積量,而且瀏覽器在屢次訪問的時候也會對文件進行緩存處理,但畢竟會增長對服務器資源的訪問次數。所以,如何設置limit的大小,須要根據項目的狀況來定
因爲url-loader在對文件處理的時候會增大文件的體積,好比對文件進行base64編碼,就會使文件的體積比原版體積更大,所以,image-webpack-loader就應運而生,它的做用就是在進行url-loader處理以前,首先對靜態資源進行壓縮處理,處理事後的圖片資源再決定是否用base64編碼。
一、首先咱們對image-webpack-loader進行安裝,而後再webpack配置中進行對配置的修改:
cnpm install image-webpack-loader --save-dev
複製代碼
// webpack.config.js
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|svg)$/i,
exclude: /node_modules/,
use: [{
loader: 'url-loader',
options: {
limit: 10240,
outputPath: 'assets/',
useRelativePath: true
}
}, {
loader: 'image-webpack-loader',//新增image-webpack-loader
options: {
mozjpeg: {//設置對jpg格式的圖片壓縮的程度設置
progressive: true,
quality: 65
},
}
}]
}
]
}
...
複製代碼
在配置項中,咱們對圖片進行壓縮處理,並設置對jpg類型的圖片壓縮到65%質量值,最後運行webpack命令,發現兩張圖片都被壓縮成4.75kb大小的圖片,在css中,兩張圖片都已經以base64編碼的方式呈現了。
image-webpack-loader對不一樣類型的圖片都對應有不一樣的處理配置設定,針對不一樣的圖片開發者能夠自定義壓縮比例。
到目前爲止,咱們的小案例已經把經常使用的基本的loader梳理了一遍,可是咱們又發現了一些問題,好比每次更改代碼後都須要進行webpack從新編譯,而且,咱們的文件仍是以文件系統的方式在瀏覽器中打開的,這個彷佛不是webpack給咱們提供的編碼姿式,所以,接下來,咱們將考慮如何讓咱們的項目在服務器上跑起來等一系列問題。
既然咱們指定了webpack最終打包後的文件在dist目錄下,那麼如今咱們只要將dist內的文件在服務器端跑起來不就能夠了嗎,這彷佛可行的,那麼我就先來嘗試一下
一、在根目錄下,新建一個server.js的文件,並安裝express
cnpm install express --save-dev
複製代碼
二、在server.js內,咱們利用express來寫一個簡單的服務器:
//server.js
var path = require('path');
var express = require('express');
var app = express();
var port = process.env.port || 3000;
app.use(express.static(path.join(__dirname, 'dist')));//設置可訪問的靜態資源目錄
app.get('/', function(req, res, next) {
req.url = 'index.html';
next()
})
app.listen(port, function() {
console.log(`server is running at ${port}`)
});
複製代碼
三、打開package.json,在script配置項下新增以下命令:
//package.json
...
"scripts": {
"server": "node server.js",//設置用node運行server.js
"build": "webpack"//設置webpack編譯命令
}
...
複製代碼
這樣咱們就能夠在控制檯經過cnpm來運行項目了:
cnpm run build /*執行webpack打包命令*/
cnpm run server /*讓編譯後的文件經過服務器加載*/
複製代碼
執行完以上命令後,在瀏覽器中輸入:localhost:3000,便可訪問最終打包的文件了,可是,咱們要的熱更新依然沒有,並且仍是須要每次都打包,除了用服務器跑起來彷佛並無解決咱們的問題(黑人鬱悶臉)。
其實解決在開發中的這個實時編譯問題,webpack早已爲咱們提供了簡便的方法。
webpack-dev-server是一個小型的nodejs express服務器,支持兩種模式來自動刷新頁面,而且都提供熱更新,咱們的實踐是以inline模式爲例的
熱更新的好處是隻替換更新的部分,而不須要去頁面重載。
一、安裝webpack-dev-server
cnpm install webpack-dev-server --save-dev
複製代碼
二、安裝完成後,咱們打開package.json文件,在script配置項下新增:
//package.json
...
"scripts": {
"server": "node server.js",//設置用node運行server.js
"build": "webpack",//設置webpack編譯命令
"dev": "webpack-dev-server"
}
...
複製代碼
這樣,咱們只要在命令行輸入 「cnpm run dev 」既能夠把項目運行起來。
三、 用webpack-dev-server運行的時候,默認端口是8080,所以,咱們在運行webpack-dev-server後,在瀏覽器執行 localhost:8080,便可訪問項目,這個時候由於項目是處於開發環境,文件只是存儲在內存中而並無真正打包出來,所以,項目中並不會生成dist文件夾,也正因如此,咱們動態改變代碼的時候,webpack就會自動更新到界面上去。
webpack在配置項中也爲咱們提供了配置webpack-dev-server的節點,也就是devServer配置項,在這個配置項中,咱們能夠更改啓動的端口號,加載模式(iframe或者inline)等等,但須要注意的是webpack3.0已經默認熱更新,若是在devServer中再次設定hot屬性的時候,熱更新反而會失效
...
entry: path.resolve(__dirname, './src/main.js'),
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name]-[chunkhash].js'
},
devServer: {
// hot: true, 不要設置hot熱更新屬性,設定後反而會失效
port: 3000,
inline: true
},
...
複製代碼
webpack優化是一個頗有技術性的話題,展開來講的話估計又是一個比較長的話題,咱們這一節裏先針對咱們目前的項目結構羅列幾項,拋磚引玉。
UglifyJsPlugin是webpack默認提供的代碼壓縮優化器,當在配置項中使用了這個插件以後,打包後的js文件會進行代碼壓縮和註釋刪除等壓縮手段,這個在項目build的時候,會減少打包後項目的體積。
...
plugins: [
//啓用js壓縮
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
}
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index.html'
}),
new cleanWebpackPlugin(
['dist'], {
verbose: false,
dry: false,
root: __dirname
}
)
]
...
複製代碼
webpack的loader加載器設置中,每個loader都容許對處理文件進行指定,包括哪個或者不包括哪個文件夾內的文件,這樣會很大程度上減少掃描的範圍,減少打包時間。實際上,在咱們的項目中咱們已經設定了exclude參數,以排除loader對node_modules中文件的掃描。
{
test: /\.js$/,
use: [{ loader: "babel-loader" }],
exclude: /node_modules/,
include: /src/
}
複製代碼
webpack默認提供的CommonsChunkPlugin插件能夠將代碼中公用的模塊提取出來,好比經常使用的相似jquery、moment這樣的額第三方插件,若是在每一個引用的js打包文件中都進行打包,最終的項目體積就會成倍增長,經過使用CommonsChunkPlugin能夠將這些公用部分提取,有效減少項目體積。
babel編譯是一個比較費時間的過程,對babel處理的設置,咱們不只要設置include && exclude來儘量準肯定位編譯的文件,還能夠充分利用緩存來進一步提高速度,設置babel的cacheDirectory爲true,是一個很好的優化方式。
{
test: /\.js$/,
use: [{ loader: "babel-loader" ,cacheDirectory: true}],
exclude: /node_modules/,
include: /src/
}
複製代碼
這一節咱們從webpack對靜態資源相關的處理以及服務器加載和webpack打包優化等作了總結,其實好多依然講的不全,不少地方也沒有作詳細的解釋,但千里之行始於足下,一步一步來,我相信你終究會獲得你想要的。
仍是不忘說一句,願各位早日成爲一名合格的前端高手,加油!