Webpack入坑筆記(二) 小圖片優化,引入CSS,使用ES6
今天我要進一步深入的瞭解webpack的各種功能,webpack有著無數外掛可以為專案提供各種支援,其中一部分對專案檔案進行預處理的外掛叫做loader(前處理器),比較常用的有:
- css預編譯,less或sass預編譯 css-loader,style-loader,less-loader 把css預編譯並通過style標籤嵌入到頁面
- 小圖片優化生成base64碼 url-loader 減少請求數
- 使用Jquery等類庫
- 支援ES6語法 babel-loader
裝逼(使用新特性提供開發效率) - 程式碼壓縮 節約流量
我們分別來嘗試一下以上提到的功能
css預編譯
在我們的app目錄下新建一個資料夾css /app/css/ 用來存放我們的CSS檔案,新建一個main.css檔案
main.css
h1{
color:blue;
}
安裝前處理器 style-loader,css-loader
npm install style-loader css-loader --save-dev //一行命令要安裝多個外掛,可以用空格隔開
安裝完成後,配置webpack.config,注意以下幾點:
- 所有的前處理器的處理順序是從後往前(從右到左)
- 在webpack 2.0版本後,前處理器不能省略-loader,例如:'style-loader'不能簡寫為'style'
...
module:{
loaders:[{
test: /\.css$/,
loaders:['style-loader', 'css-loader'],
include:APP_PATH
}]
}
...
不要忘了在index.js引用我們的css檔案
require('./css/main.css')
然後執行npm start,你應該能看到藍色的hello world字樣了
使用Less
讓我們接著上一步,如果我要使用sass或者less,應該怎麼辦呢,答案也非常簡單,只需安裝less前處理器,並在配置檔案裡配置對less的預處理即可
npm installless-loader --save-dev
webpack.config配置
module:[
...
{
test:/\.less$/,
loader: ['style-loader','css-loader','less-loader'] //是不是非常簡單,只需要在預處理程式上加一道即可
},
...
]
在/app/下新建目錄 /app/less,新建檔案main.less
@base: red; h1 { color: @base; }; h2 { color:blue; }
在index.js中修改引用
require('./less/main.less');
然後 npm start,編譯成功!又看到了熟悉的hello world,只不過這次第一行變成了紅色,第二行變成了藍色
小圖片優化
首先我們在我們的目錄下新建一個資料夾 /app/images/ 用來存放我們的圖片,這裡我選用了2張貓咪的圖片,一張有270kb,另一張則是21.6kb.我們的目標是當瀏覽器載入40KB以下的圖片時,把圖片轉化成dataurl,這樣可以減少請求數,提高網頁載入的速度.先看下沒有前處理器下,圖片的處理情況
我們的檔案目錄結構:
我們在less中為h1,h2增加背景圖片
@base: red; @height: 300px; h1 { color: @base; background: url('../images/p1.jpg') no-repeat; background-size:; height: @height; }; h2 { color:blue; background: url('../images/p2.jpeg') no-repeat; background-size: contain; height: @height; }
我們在html中用標籤也新增一張圖片,這裡應該通過JS來生成到html中,我們新增一個元件images.js
function printIMG(){
var div=document.createElement('div');
div.innerHTML='Here is a picture from js<br>'
div.innerHTML+='<img src="/app/images/p1.JPG">';
return div;
}
module.exports=printIMG;
在index.js中引用它,注意我們這裡還有個同名的images目錄,但webpack自動識別了require中的images.js
require('./less/main.less');
var sub=require('./sub');
var img=require('./images');
var app=document.createElement('div');
app.innerHTML='<h1>Hello World 1111111</h1>';
app.appendChild(sub());
app.appendChild(img());
document.body.appendChild(app);
執行webpack後,我們看到頁面上多了3張圖片,檢視HTML和CSS後,發現現在所有圖片都是直接引用的url
然而我們的需求是要把40KB以下的圖片全部轉化成base64的形式,現在我們使用url-loader來做這件事,
首先,安裝外掛 url-loader
npm install url-loader --save-dev
然後在webpack.config中配置
...
module: {
loaders: [
...
{
test: /\.(png|jpg|jpeg)$/, //可以定義多種格式
loader: 'url-loader?limit=40000?name=images/[name].[ext]' //在前處理器後可以通過?增加引數,這裡?limit=40000的意思是把所有40000b以下的圖片轉化成base64格式
},
...
]
},
...
然後讓我們再執行下看看結果
這個時候我們發現background裡的圖片已經變成base64格式了(見框1),但框2中的img標籤裡同樣的圖片卻沒有轉化.
這是由於url-loader不支援打包JS裡的src導致的,為了打包時候不丟失圖片,我們可以通過require的方式引用圖片,這樣就可以通過url-loader來打包了,把images.js改一下:
var imgUrl= require('./images/p1.jpg');//注意!字尾名必須是小寫,大寫會報錯
var imgTemp='<img src="'+imgUrl+'" />';
function printIMG(){
var div=document.createElement('div');
div.innerHTML='Here is a picture from j11111111111s<br>'
div.innerHTML+=imgTemp;
return div;
}
module.exports=printIMG;
使用Jquery等類庫
如果要在專案中使用各種類庫,步驟也是和安裝外掛一樣的
首先
npm install jquery --save
然後在需要使用jquery的頁面上require一下
var $=require('jquery');
...
$('body').append('<p>Jquery is work now</p>');
這裡筆者產生了一個問題,為什麼require('jquery')就能直接找到node_modules下的jquery檔案呢
這是因為如果require中的內容如果不包含'/'、'./'或'../'開頭的話,預設會先尋找node_modules目錄下的相關檔案,這裡的require('jquery')等價於 require('./node_modules/jquery')
參考:阮大神的文章
當 Node 遇到 require(X) 時,按下面的順序處理。
(1)如果 X 是內建模組(比如 require('http'))
a. 返回該模組。
b. 不再繼續執行。
(2)如果 X 以 "./" 或者 "/" 或者 "../" 開頭
a. 根據 X 所在的父模組,確定 X 的絕對路徑。
b. 將 X 當成檔案,依次查詢下面檔案,只要其中有一個存在,就返回該檔案,不再繼續執行。X
X.js
X.json
X.nodec. 將 X 當成目錄,依次查詢下面檔案,只要其中有一個存在,就返回該檔案,不再繼續執行。
X/package.json(main欄位)
X/index.js
X/index.json
X/index.node(3)如果 X 不帶路徑
a. 根據 X 所在的父模組,確定 X 可能的安裝目錄。
b. 依次在每個目錄中,將 X 當成檔名或目錄名載入。
(4) 丟擲 "not found"
執行後,可以看到,Jquery的程式碼已經成功輸出了!
支援ES6語法 babel-loader
如果想要使用es6,我們需要安裝babel編譯器,他可以把ES6語法解析成瀏覽器能相容的JavaScript,我們還要安裝適用於babel的ES2015語法轉換器(babel-preset-es2015)
npm install babel-loader babel-preset-es2015 --save-dev
在webpack.config中配置
...
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/,
query: {
presets: ['es2015'] //表示使用es2015語法轉換器
}
},
...
關於babel-loader的設定可以參考這裡
然後我們修改下原來的js檔案,可以使用ES6語法了
sub.js
export default function(){
var h2=document.createElement('h2');
h2.innerHTML='Hello World h2';
return h2;
}
images.js
import imgUrl from './images/p1.jpg';
let imgTemp='<img src="'+imgUrl+'" />';
export default function(){
let div=document.createElement('div');
div.innerHTML='Here is a picture from j11111111111s<br>'
div.innerHTML+=imgTemp;
return div;
}
index.js
//ES6風格
import './less/main.less';
import sub from './sub';
import images from './images'
import $ from 'jquery';
import moment from 'moment';
let app = document.createElement('div');
const myPromise = new Promise(function(resolve,reject){
setTimeout(function(){
console.log('執行完成');
resolve('101');
},5000);
});
myPromise.then((value)=>{
$('body').append('<p>promise result is ' + value + ' now is' + moment().format('YYYY-MM-DD hh:mm:sss')+'</p>');
});
app.innerHTML='<h1>Hello world H1</h1>';
document.body.appendChild(app);
app.appendChild(sub());
app.appendChild(images());
執行一下,依然是我們熟悉的hello world,並且promise的結果也print出來了.
程式碼壓縮
現在我們對webpack基本的功能都有一定的瞭解了,最後生成專案的時候,頁面裡的js和css都是未經過壓縮的,並且我們所引用到的類庫都被打包到了bundle.js裡,導致這個JS檔案非常大,在實際生成專案中,我們通常只上線自己所寫的JS程式碼,所有的類庫都會快取到CDN上來分流,這個需求在webpack中也是可以實現的.首先我們來拆分專案中的Jquery和Moment 這2個庫
修改webpack.config,新增externals屬性可以在webpack打包時排除在externals下的依賴包
例如:我們排除jquery和moment,這樣在webpack打包時就不會把這2個庫打包到bundle.js下了
...
externals:[
{'jquery':'jQuery','moment':'moment'},
],
...
我們可以在template模板中對未打包的檔案進行設定,比如設定CDN,我這裡由於沒有CDN,就用node_modules代替了
<!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>Document</title>
</head>
<body>
hello this is from template
<script src="../node_modules/jquery/dist/jquery.min.js" charset="utf-8"></script>
<script src="../node_modules/moment/min/moment.min.js" charset="utf-8"></script>
</body>
</html>
另一種壓縮是對js本身進行的壓縮 可以通過webpack自帶的外掛進行
...
plugins:[
new webpack.optimize.UglifyJsPlugin({//壓縮JS
compress:{
warnings:false
}
}),
]
...
執行weback 打包後的檔案更小了