謝謝大家看我扯技術,最近在對webpack2
進行的配置進行梳理和學習,webpack
是在去年使用vue
開始接觸的,我的感受webpack
融入到編程過程當中,提供了模塊化,將各類類型的文件都當作模塊,經過不一樣的 loader
進行處理和代碼組織,是一個比較新穎的編程體驗,應該說webpack
的編程適用場景比較普遍,可以比較方便的引入第三方的各類 npm 模塊進行使用, 方便快速開發工做。
打算寫幾篇文章(若是能堅持的話= =)來總結下 webpack
,文章不是教你怎麼使用webpack
,而是讓你更好的瞭解你在使用的webpack
是怎麼去運行的 ,想來想去,第一篇就先介紹下webpack
生成的文件,是怎麼去執行的。html
首先咱們要先經過 webpack 去生成文件(好一句廢話),文章全部的代碼都會在文章最後面給出連接,下面是本文章使用的代碼的目錄:
vue
咱們如今只要關注js
目錄,裏面有兩個入口 app.js
、bar.js
,而後會引用 es5,es6中的各類測試模塊,具體你們能夠看代碼。而後代碼一跑!只見命令行蹭蹭蹭跑出來了好多信息,像下面同樣:
webpack
首先咱們來看下生成的信息:git
Asset
: 這個一看就明白是生成的文件相對於配置中output.path
的路徑,能夠看到圖中生成的文件都是在 output.path
底下的;而後咱們仔細看下文件名,好比第一個0.fb6d7f4.js
,是由[name/chunkname].[hash/chunkhash].js
組成的,這個能夠在output.filename
中配置,關於hash
和chunkhash
的區別,這個後面會專門經過一篇文章進行簡介。es6
Size
: 這個就沒啥好說的,就是生成文件的大小github
Chunks
: 咱們會看到有些 Chunks
是兩個數字,有些是一個,其實還可能出現更多,通過個人一堆實驗= =,發現Chunks
中的第一個數字,就是這個文件的 ChunkId
,然後面的是當前這個文件依賴的文件的ChunkId
,從圖中咱們能夠看到,第一個文件的ChunkId
是0
,它依賴的是ChunkId
爲3
的manifest.a890c12.js
web
Chunk Names
: 這個就是這個生成文件的chunkName
,能夠用於文件命名,能夠看到若是沒有在entry
中指定,那麼chunkName
會等於chunkId
chrome
瞭解了生成的信息,接下來咱們把項目跑起來(能夠用 anywhere
跑項目),經過chrome developer tool
能夠看到請求狀況npm
能夠看到請求了頁面html以後,按順序分別加載了 manifest
,index
,0
,2
文件,這裏咱們先來分析下文件的分割和加載流程。編程
能夠看到頁面的 js 被分割成爲了4個文件,一般來講,一個項目定義了一個 entry point
,webpack
會以這個entry point
做爲入口,進行代碼回溯,若是存在System.import
或者是require.ensure
的異步模塊調用,webpack
會對使用的模塊進行單獨打包,好比文件中的0
、2
這兩個 js,若是沒有異步模塊調用,那麼會將全部的代碼生成在一個文件中,webpack
爲了使得打包的代碼進行優化,可使用CommonsChunkPlugin
插件對代碼進行處理,將庫文件單獨打包,經過規則生成對應的 chunk
文件,其中的manifest
爲 默認的 chunk
,其中包含了打包文件的runtime
信息,還有webpackJsonp
模塊加載的封裝庫,全部的生成模塊都是採用webpackJsonp
進行封裝的。
從上面的圖中能夠看到,瀏覽器按順序分別加載了 manifest
,index
,0
,2
文件,其中manifest
至關於webpack
的runtime
工具,用於作模塊加載,其餘文件是邏輯文件; manifest
中封裝了webpackJsonpCallback
方法和__webpack_require__
方法,下面咱們來進行分析:
webpackJsonpCallback(chunkIds, moreModules, executeModule)
:webpackJsonpCallback
是chunk封裝的包裝方法,webpack
在生成每個chunk
的時候都是經過這個方法進行包裝的,咱們在上面看到的 chunksId
,會做爲第一個參數,被包含進這個chunk
的module
會被以數組的形式傳入第二個參數moreModules
中,若是這個chunk
中包含能夠執行的modules
,須要將 moduleId
傳入第三個參數 executeModule
中,下面是 這個方法的代碼片斷:
這個方法主要作了下面幾件事:
咱們能夠看到這個方法用第一個循環分別將chunkIds
處理進入installedChunks
對象中,installedChunks
對象用於記錄chunk
的加載狀況,分別用0
表示當前的chunkId
已經加載完成,用一個長度爲3的數組表示當前的chunk
正在加載中,數據中其實存儲着加載過程當中的resolve
方法、reject
方法和pormise
對象,這種只在經過require.ensure
或者是System.import
纔會出現。所以咱們能夠看到,第一個for
循環中判斷若是chunkId
在 installedChunks 中存在且不爲0,則判斷是異步加載的模塊已經加載成功,將chunk
的resolve
方法傳入resolves
數組,而後後面運行,而後將chunk
對應的狀態設置爲0
。若是判斷以後不存在,這認爲這是一個同步加載的chunk
,直接設置爲0
,表示chunk
已經加載完畢。
加載 module
的邏輯比較簡單,判斷純不存在這個module
以後,將 其寫入modules
參數之中
module
若是executeModule
存在,則對其中對應moduleId
的模塊進行運行
__webpack_require__
: 這個對象包含了多個方法,主要用於module
和chunk
的加載,處理和運行,下面咱們一個一個分析:
__webpack_require__(moduleId)
:代碼以下
這個方法接收一個moduleId
,構建一個 module 對象存入installedModules
中,而且初始化這個 module
, 最後返回module.export
__webpack_require__.e(chunkId)
: 這個方法用於經過異步的方式加載 chunk 文件,代碼以下:
這個方法整體來講就是加載一個 script
文件,生成一個 promise
對象,當 script 加載完成後運行,又會執行前面的webpackJsonpCallback
註冊chunk
,而後promise.resolve
。這裏面須要注意的是紅框裏面的東西,這個涉及到一個優化點,若是沒有在使用CommonsChunkPlugin
單獨打包manifest
,那麼通常來講他會和你指定的其餘庫經過CommonsChunkPlugin
打包在一塊兒,那麼你會發現即便你只是修改了庫以外的邏輯,庫文件生成的文件的hash
或者是chunkhash
也是會變的,緣由就在於manifest
中紅框部分是動態生成的,致使文件的 hash 產生變化,不利於緩存,所以建議單獨打包manifest
__webpack_require__.oe
:定義一個統一的錯誤處理函數
__webpack_require__.p
:這個是和webpack
的output.publicPath
對應的值
__webpack_require__.o
: Object.prototype.hasOwnProperty
的封裝
前面幾個方法在 ES5
的情景下面已經足夠運行這個模塊系統,咱們都知道webpack2
加入了對ES6 MODULE
的支持,下面幾個__webpack_require__
是爲ES6
使用的:
__webpack_require__.d
:代碼以下:
這個是用於ES6
中命名的export
好比 webpack 遇到這種export
,會對其用__webpack_require__.d
進行包裝,變成:
__webpack_require__.i
:用於返回一個正確的上下文的函數回去,針對的是export
直接爲一個可運行方法的時候
以上就是webpack manifest
中的大部分重要的函數,其實主要就是經過webpackJsonpCallback
來註冊載入對應的chunk
文件,經過__webpack_require__
來處理模塊的關係。
整個webpack
的在運行時都是經過 manifest
去作控制處理的, webpackJsonpCallback
對應的是對加載的chunk
文件的處理,__webpack_require__
是對加載模塊的處理,瞭解這些可使咱們更好的去優化咱們的代碼,幫助咱們去調試代碼,幫助咱們在複雜狀況下去解決問題提供一些其餘的思路。
最後附上代碼:先介紹下,webpack-base
是我在使用webpack
的過程當中本身總結的一套腳手架,文檔尚未完善,若是須要文檔能夠在issue
裏面提,本次的項目在分支上面開發,代碼點擊這裏