webpack使用筆記

weixin_33806914發表於2017-11-23

安裝

npm install -g webpack // 全域性安裝
npm install --save-dev webpack //本地安裝

在完成全域性安裝和本地安裝之後,就可以開始進行webpack的使用了。

嘗試打包

安裝完成之後,我們可以嘗試使用webpack進行一次簡單的打包。
webpack最基本的命令就是webpack,可以直接使用webpack命令對檔案進行編譯,例如

webpack main.js bundle.js

上述程式碼就能將main.js檔案打包成bundle.js檔案。

使用配置檔案

也可以在webpack配置檔案中設定好引數後直接執行webpack命令進行打包。在專案根目錄下新建webpack.config.jswebpack會預設其為配置檔案。

module.exports = {
  entry:  __dirname + "/src/main.js", //設定main.js為專案入口
  output: {
     path: __dirname + "/public",//設定public為編譯後的目錄
     filename: "bundle.js"//編譯後輸出檔案的檔名
  }
}

注意:__dirname是指專案根目錄,必須要加上,這樣在打包之後才能準確找到相應目錄。
配置好之後,在命令列中直接輸入webpack就能得到前面的同樣的結果。
接下來也可以在package.json檔案中配置webpack命令的代替方式,如下

"scripts": {
  "start":"webpack"
}

這樣直接輸入 npm run start也能取得同樣的效果。
如果想要執行自定義webpack的配置檔案的話,可以使用如下程式碼

webpack --config webpack.dev.config.js

這樣就能將配置檔案設定為webpack.dev.config.js了。也可以在package.json中去設定

"scripts": {
  "webpack":"webpack --config webpack.dev.config.js"
}

執行 npm run webpack,就能實現和上面程式碼一樣的功能,將配置檔案設定為webpack.dev.config.js並執行。

配置檔案解析

在配置檔案中,entry欄位可以分別設定為以下三種形式:
1.字串
指定這個目錄下的檔案為入口檔案

entry:'main.js' //指定main.js為入口檔案

2.陣列
存在多個入口檔案的時候,使用陣列方式可以新增多個互相不依賴的檔案

entry:['src/main.js','dist/index.js']  //兩個檔案會被打包為一個檔案

3.物件
指定多個檔案打包成多個檔案以供不同頁面使用

{
    entry:{
        'mainEntry':'src/main.js',
        'indexEntry':'src/index.js'
    },
    output:{
        path:'/dist',
        filename:'[name].js' //執行後會打包成mainEntry.js和indexEntry兩個檔案
    }
}

output最常用的兩個屬性分別是filepathfilename
其中filepath是一個絕對路徑,指定打包生成之後的檔案存放的目錄。fliename指定打包生成之後的檔名。
根據上述entry欄位的敘述,我們有時候會同時指定多個入口檔案,如果只是在output.filename中指定一個檔名,那麼會將兩個入口檔案打包到一個檔案中去。這時候我們可以使用佔位符的方式來指定output.filename,這樣就能根據相應的入口檔案打包出相應的檔案了。
佔位符可以設定以下內容:

name 模板名稱,對應上面的mainEntryindexEntry
hash 整體的hash值
chunkhash 分片的hash值

hash和chunkhash

為什麼會有hashchunkhash值呢?其實,hash值是在整個打包過程中每一次版本變化生成的值,這樣一來,一旦某一個資原始檔有發生變化,則整個hash值就會發生改變,從而導致所有打包出來的檔案的檔名都會發生變化。
怎樣避免這個問題呢,那就是使用chunkhashchunkhash是根據具體的模組的變化來生成的值,所以某一個檔案的變化只會影響到它自己的chunkhash值的變化。
例如:

{
    entry:  {
        mainEntry:__dirname + "/app/main.js",
        indexEntry:__dirname + "/app/index.js"
    },
    output: {
        path: __dirname + "/public",
        filename: "[name]-[hash].js"
    }
}

使用namehash的方式來命名打包後的檔案,生成的結果如下

Hash: 8449fbacd884544a83ed
Version: webpack 2.5.1
Time: 57ms
                             Asset     Size  Chunks             Chunk Names
 mainEntry-8449fbacd884544a83ed.js  2.73 kB       0  [emitted]  mainEntry
indexEntry-8449fbacd884544a83ed.js  2.71 kB       1  [emitted]  indexEntry
   [0] ./app/index.js 76 bytes {1} [built]
   [1] ./app/main.js 84 bytes {0} [built]

兩個打包之後的檔案擁有同一個hash8449fbacd884544a83ed,一旦main.jsindex.js其中的一個檔案發生變化,則會引起整體的hash值變化。
如果使用chunkhash的話,如果所示:

{
    entry:  {
        mainEntry:__dirname + "/app/main.js",
        indexEntry:__dirname + "/app/index.js"
    },
    output: {
        path: __dirname + "/public",
        filename: "[name]-[chunkhash].js"
    }
}

生成結果如下:

Hash: 41e84bc2e3034e423af1
Version: webpack 2.5.1
Time: 54ms
                             Asset     Size  Chunks             Chunk Names
 mainEntry-d4d7121b09d82bb73a8e.js  2.73 kB       0  [emitted]  mainEntry
indexEntry-252220e65aed8b7f327b.js  2.71 kB       1  [emitted]  indexEntry
   [0] ./app/index.js 76 bytes {1} [built]
   [1] ./app/main.js 84 bytes {0} [built]

同樣也會生成hash值,但是兩個檔案的chunkhash值是互不影響的,其中的一個檔案發生變化,則只會改變發生變化檔案打包後的檔名。
看上去好像chunkhash能取代hash的作用,但是我認為hash的存在肯定有其適用的場景。比如在做靜態資源大版本管理和資料夾命名的時候就能用上,肯定還會有更多其他可能的場景。

使用plugin

在使用hashchunkhash來為打包之後的檔名做版本,每次打包之後會生成新的檔名,我們無法預知每一次打包之後的檔名,所以有什麼辦法可以一次實現html檔案中對打包檔案進行引用呢?
這裡我們可以使用html-webpack-plugin這個外掛來幫我們完成。

  1. 在專案目錄中對外掛進行安裝:
npm install html-webpack-plugin --save-dev
  1. 在配置檔案中對外掛進行引用:
var htmlWebpackPlugin = require('html-webpack-plugin')
  1. 使用並配置外掛引數
    外掛的使用方式是直接在配置檔案中新增一個值為陣列的屬性:
plugins:[
  new htmlWebpackPlugin();  //不加任何引數直接新建外掛物件是最基本使用方式
]

這樣就能在output.path指定的目錄中生成一個新的index.html檔案,這個index.html檔案會將所有打包完成之後的靜態資源進行引用。由於每次重新打包之後的index.html檔案是重新生成的,所以就解決了上面我們打包之後的靜態資原始檔名不斷變化的問題。
由於我們沒有進行任何的引數設定,所以webpack會用預設的模板打包生成一個檔案,我們也可以使用自定義模板的方式進行打包生成。

new htmlWebpackPlugin({
  template:'index.html', //webpack會在根目錄下尋找index.html檔案作為模板
  fliename:'main.html', //還可以自定義打包生成之後的檔名
})

這樣我們就能使用根目錄下的index.html檔案作為模板,在output.path下打包生成一個名為main.html的檔案,這個檔案包含了我們打包之後的靜態資原始檔的引用。
但是我們真實專案中不同型別的靜態資源存放的目錄不一樣,這裡其實可以在filename屬性中來指定帶目錄的檔名。

filename:__dirname+'/dist/views/index.html'

這樣我們就能將打包之後的html檔案和js檔案分開存放了。
另外,我們如果需要進行多頁面開發的話,可以多次建立新的htmlWebpackPlugin物件來配置。大體模板如下:

new htmlWebpackPlugin({
  template:'index.html', 
  fliename:'main.html', 
}),
new htmlWebpackPlugin({
  template:'index.html', 
  fliename:'side.html', 
}),
...

html-webpack-plugin外掛的其他配置引數和使用方法可以去官網檢視。

使用loader編譯ES6程式碼

通過使用loader,webpack能實現對各種各樣的檔案進行處理。
loader需要在配置檔案中的modules下進行配置,主要包括以下欄位:

test 一個匹配該loader所需要處理的檔案擴充名的正規表示式
loader loader的名稱
include/exclude 指定要處理的資料夾/遮蔽不需要處理的資料夾
query 額外選項

使用 babel

babel需要在命令列中安裝單獨的包

npm install --save-dev babel-core babel-loader babel-preset-es2015

以上是本地安裝,需要在專案根目錄下執行。
按照上面的loader配置方法,我們可以按照如下模板來配置babel

module:{
  loaders:[{
    test:/\.js$/, //以.js結尾的檔案都是babel需要處理的
    loader:'babel-loader', //loader的名稱
    exclude:/node_modules/, //忽略node_modules目錄下的所有檔案
  },{} //多個loader用逗號分隔開
  ,...]
}

配置完之後在專案根目錄下建立檔案.babelrc,並在檔案中寫入以下內容:

注:在windows系統下不能直接建立.babelrc檔案,可以在根目錄下開啟命令列輸入type null>.babelrc命令建立

{ "presets": [ "es2015" ] }  

完成之後執行webpack命令,在編譯js檔案的時候就會使用babel-loader將檔案中的ES6程式碼編譯成瀏覽器可執行的ES5程式碼。

相關文章