很久沒有發文章了,但是強調一點,大~熊同學最近可沒閑着。學習算法,復習計算機網絡,也順便學習了一下webpack,看了看操作系統(沒辦法,都沒學,要是不學連實習筆試都過不了,傷心~~)。本來比較糾結是寫關於算法的文章呢還是關於webpack的呢。最終決定寫關於webpack 的,一方面,雖然剛剛開始學習webpack,但是他的特性讓人感覺非常爽,然我有一種想分享的沖動;另一方面,算法要寫公式,這個編輯器貌似不太好編輯,截圖也比較麻煩。廢話不說了,這篇文章介紹webpack的四個核心配置項。我寫的不好,你可以參考:中文文檔、英文文檔。當然看看我寫的也是可以的。
1、建立測試項目並安裝webpack
(1)建立項目目錄:mkdir WP
(2)進入項目目錄:cd WP
(3)用npm init建立package.json文件(隨便起一個名字,一路回車就好)
(4)安裝webpack:npm install --save-dev webpack
(5)測試是否安裝成功,法現webpack -v找不到命令,直接在package.json的scripts加上 "webpack": "webpack",然后運行npm run webpack -v 結果正確
(6)建立源文件目錄:mkdir src
(7)用編輯器打開項目:subl .
至此,准備工作完成,我們得到的的項目目錄和package.json文件如下所示:
(寫了半天,發現插入一段代碼后不能到下一行了,按了幾次CTRL+Z, 居然回到這里了,真無語,再來一次)
2、entry和output的使用
為了測試先建立如下項目結構
各個文件內容如下:
//index.js import A from './js/test.js'; function hello(){ console.log("hello"); console.log(A); } hello(); //index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>This is for webpack study</title> </head> <body> <h1>祝大家發財</h1> </body> </html> //webpack.config.js const path = require("path"); module.exports = { entry:"./src/index.js", output:{ path:path.resolve(__dirname,'dist'), filename:"bundle.js" }, // module:{}, // plugins:{} }
直接終端運行一下:
打開項目看一下:
發現生成了一個dist目錄,里面多了一個bundle.js的文件,查看bundle.js發現下面有我們index.js中的內容(這個是之前截的圖,有點不一致了)。假如我們在index.js聲明依賴會如何。先在js目錄下建一個test.js 文件,內容如下:
const A = "大~熊最帥!"; export default A;
然后在index.js中聲明對它的依賴
import A from './js/test.js'; function hello(){ console.log("hello"); console.log(A); } hello();
打包一下:
發現生成了一個bundle.js,然后有兩個文件。查看bundle.js會發現,test.js中的內容也加到里面了。下面在index.html中加上:
<script type="text/javascript" src="../dist/bundle.js"></script>
預覽如圖:
發現引入一個bundle.js就相當於index.js和test.js都進來了,可以正常使用。 通過這樣一個簡單的例子相信你已經感受到了webpack的強大之處,下面詳細介紹entry和output兩個屬性的多種用法。
(1)entry:entry指定打包入口,可以是一個字符串,也可以是一個字符串數組,還可以是一個對象。
A、指定一個字符串的情況上面已經提到了,它適用於單入口的情況。
B、指定一個字符串數組。
在src目錄建立index2.js,並修改配置文件,見下:
//index2.js
function index2(){
console.log("this is index 2");
}
index2();
//webpack.config.js
const path = require("path");
module.exports = {
entry:["./src/index.js","./src/index2.js"],
output:{
path:path.resolve(__dirname,'dist'),
filename:"bundle.js"
},
// module:{},
// plugins:{}
}
打包一下
可以發現我們生成的內容有點不一樣,3后面有個multi,這里從多個入口觸發檢查依賴生成了一個chunk。當你的index2.js和index.js是互不依賴,而你又想把他們打包到一起,那么這種方式正是你需要的。的。下面檢查一下生成的bundle.js是什么樣子。
C:entry值為一個對象的情況
第一種情況,只有一個鍵值,這和A情況是一樣的。
const path = require("path"); module.exports = { entry:{ main:"./src/index.js" }, output:{ path:path.resolve(__dirname,'dist'), filename:"bundle.js" }, // module:{}, // plugins:{} }
第二種情況,多個鍵值對。
const path = require("path"); module.exports = { entry:{ main:"./src/index.js", second:"./src/index2.js" }, output:{ path:path.resolve(__dirname,'dist'), filename:"[name]-bundle.js" }, // module:{}, // plugins:{} }
注意我這里改了一下output,否則報如下錯誤:
按照我的修改做結果是:
可以發現生成了兩個chunk,文件名字分別為main-bundle.sj和second-bundle.js,chunk名字分別為main、second。如果要將從多個入口文件打包的東西放到不同的文件,那么此款適合你。關於那個output是什么意思,馬上開講。
(2)output基本用法
output有很多屬性可用,這里列舉幾個最最常用的屬性。
- path:指定一個絕對路徑,表示生成的chunk應該放在哪里。一般這樣就可以了path:path.resolve(__dirname,'dist'),這個表示生成項目根目錄下dist目錄的絕對路徑
- filename:指定生成的chunk的文件名字。里邊可以有一些特殊值
[name]:表示你在entry指定入口時的那個鍵,上面的是main和second
[hash]:表示當次打包的一個標識,修改之后在打包會變化,一次打包的不同chunk的值相同
[chunkhash]:表示每一個chunk的唯一標識,顯然不同chunk是不一樣的,當某個chunk里的東西改變時二次打包他的chunkhash才會改變,否則保持不變
[id]:表示chunk的編號,上面是0和1
以下重點看看那hash和chunkhash
修改index.js再打包
發現我們只改了一個index.js,另外一個的hash也變了。
下面將配置給為[chunkhash]
const path = require("path"); module.exports = { entry:{ main:"./src/index.js", second:"./src/index2.js" }, output:{ path:path.resolve(__dirname,'dist'), filename:"[name]-[chunkhash]-bundle.js" }, // module:{}, // plugins:{} }
打包一次然后修改index.js再打包一次結果如下:
發現只有我們修改的文件對應的chunk的chunkhash發生了改變,那個second並沒有改變。使用chunkhash可以有效利用緩存,不用全部重新下載。比如,你上線了一個應用,已經被很多用戶訪問,這時在他們的瀏覽器有緩存,如果你修改了一個文件,再次上線,如果用chunkhash,只有你該過的那個chunk的文件名會變,其他的文件緩存還可以用,加快了加載速度。如果用hash的話,所有的文件名都會改變,所有文件都得重新下載,這是不好的。
3、plugins屬性的用法
你可能已將注意到了,src中的html文件並沒有到dist目錄中去。如果我們直接在dist中建立html文件,由於我們的chunk的文件名是變化的,每一次改變都要重新調整引入。下面介紹HtmlWebpackPlugin這款插件來解決這個問題,以此了解plugins配置項。
(1)安裝
(2)配置
const path = require("path"); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry:{ main:"./src/index.js", second:"./src/index2.js" }, output:{ path:path.resolve(__dirname,'dist'), filename:"[name]-[chunkhash]-bundle.js" }, // module:{}, plugins:[ new HtmlWebpackPlugin({ template:"./src/index.html" }) ] }
(3)打包
發現生成了一個index.html文件。
(4)看效果
這里有一個文件找不到,是因為我們的src文件夾下的index.html引入了一個bundle.js但是現在沒有這個東西了,去掉就好。
HtmlWebPlugin插件還有比較多的配置項,也還具備很強大的功能,詳情見官網,這里只是拋磚引玉。
4、module配置項
module配置項是用來指定loader的,loader實質上是用來對我們的資源進行預處理的工具,便於webpack將他們當成模塊。下面以babel-loader為例講解這個配置項。
(1)安裝(截圖時還沒裝完)
(2)配置
const path = require("path"); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry:{ main:"./src/index.js", second:"./src/index2.js" }, output:{ path:path.resolve(__dirname,'dist'), filename:"[name]-[chunkhash]-bundle.js" }, module:{ rules: [ { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: 'babel-loader', options: { presets: ['es2015'] } } ] }, plugins:[ new HtmlWebpackPlugin({ template:"./src/index.html" }) ] }
(3)打包
(4)看效果(這里從打包后生成的文件看效果)
看到第79行,我們源文件是const但是這里變成了var。babel-loader的工作就是將新標准的新特性轉換成瀏覽器支持的寫法,因為這些新特性可能還不被瀏覽器支持,有了這樣的轉化,我們就可以肆無忌憚(這個詞用的很棒)的使用新特性了。比如這里我們用到了es6的新特性const,babel幫我們轉成了var,這樣所有瀏覽器都支持了。
我們來看一下module這個配置。這個對修有一個rules屬性(2.X版本),rules是一個數組,里邊可以定義一系列的處理規則,每一個是一個對象。每一個規則包含一些配置項,核心有test指明對什么文件應用這個規則,use指定處理的loader名字,如果有多個loader可以是一個數組。options是提供一些配置項。還有像exclude等等等諸多配置項,你可以去官網查閱,這里不作展開,點到為止。
5、小結一下
webpack是一款非常非常強大的模塊化工具,她徹底顛覆了傳統的局部思維模式,而是將我們項目看作一個整體,有效的幫助我們解決各種依賴問題,解決各種資源的轉換問題。本文用幾個簡單的例子講解了webpack的四大核心配置項的基本用法,僅作拋磚引玉之用,webpack十分強大,有豐富的loader和plugin可供我們使用,本文介紹的內容只是其冰山一角。更多信息請參考官網。
最后,如果你覺得大~熊同學寫的文章對你有所啟發,請關注一下,他和他的哆啦A夢都會很開心的!!!
參考: