1. 程式人生 > >一步步深入學習webpack(入門困惑express和dev-server區別及分別使用dev-server和webpack-hot-middleware實現的熱載入區別)

一步步深入學習webpack(入門困惑express和dev-server區別及分別使用dev-server和webpack-hot-middleware實現的熱載入區別)

最近需要對webpack詳細學習後,給大家分享學習。於是不得不對每一個點進行學習,結果發現webpack涉及到的知識內容好多,自己學習也是一知半解,很多時候腦細胞都死得一片一片的。
注:本文是參考網上多方資料學習後記錄的,如有雷同,請聯絡我。

學習資料:入門Webpack,看這篇就夠了WebPack 簡明學習教程Webpack飛行手冊以及wepack官方文件
一、webpack是什麼
Webpack是一款目前非常流行的前端模組打包工具,可將專案中所載入的模組進行打包,以及將一些瀏覽器不支援的語言進行轉換。

兩個最核心原理:一切皆模組、按需載入。

打包原理:先找到入口檔案,遞迴探索出所有依賴的模組,最後利用Loader進行不同檔案的型別的處理,最終打包為一個檔案。

另外,webpack遵循Common.js規範,也就是專案出現的以require()方式的載入模組,讀取並執行,最後返回的是每個模組的自由變數exports(是對外輸出API的唯一途徑)等。
注意:
Common.js是模組化開發的標準(服務端模組規範),載入同步,載入完成後才能執行後面的操作。但Node.js一般用於伺服器的程式設計,載入模組一般已經存在硬碟,載入比較快,不用考慮非同步載入的模式!
此外還有瀏覽器模式下的AMD(RequireJS在推廣過程中對模組定義提出的概念)和CMD(SeaJS在推廣過程中對模組定義提出的概念)。其中,AMD是預載入,遵循非同步模組定義(^ ^ps:這個還沒懂)在使用它時,它會嘗試第三方類庫修改自身來支援 RequireJS,且外掛型別比較單一;而後者是並行載入js檔案,可以同一時間解析多個檔案,但這時載入順序不一定,外掛型別比較豐富。

後來的後來:在安裝vue後,發現dist目錄下多了許多個檔案,檢視描述,又有了UMD。
UMD:通用模組定義(優勢多個環境下,不用修改就可以使用,相容AMD/Common.js和一般的全域性定義,但是!不支援CMD的!)
UMD的簡單實現:
(1)先判斷是否支援Node.js模組格式(即exports是否存在),存在就是用Common.js;
(2)再判斷是否支援AMD(define是否存在);
(3)如果兩個都不存在,則模組公開全域性;

補充:在過程中有接觸到SASS(css語法超級),後來又有SCSS是SASS的新語法。SASS的基本用法:
(1)允許使用變數,所有變數以

eg:blue:#1875e7;
(2)變數需要嵌在字串中,必須寫在#{}中;
(3)有計算功能,可以在程式碼中使用算式;
(4)巢狀;
(5)註釋風格/* / 和 /!重要註釋*/

webpack使用可以使用不同的Loader,呼叫外部的指令碼或者工具,實現對不同格式的檔案處理。提供兩個工具處理樣式表:
(1)css-loader:使你可以使用類似@import和url()實現require()載入;
(2)style-loader:將計算後的樣式假如頁面,二者組合在一起使用可以將樣式嵌入webpack打包後的JS檔案中;

Babel則是編譯JavaScript的平臺,讓我們可以使用新的JavaScript標準(如:ES7、ES6),也可使用基於javaScript的擴充套件語言,如React的JSX。

二、安裝步驟
1.新建專案檔案,且在終端中進入該目錄;
2.全域性安裝:npm install –g webpack
3.本地安裝:npm install –save-dev webpack
4.初始化: npm init
5.安裝webpack伺服器 npm install –save-dev webpack-dev-server

三、使用
這裡寫圖片描述
在按第二部分安裝好後,我們就可以對webpack進行使用了,使用方法可以通過終端命令或者是配置檔案來進行。一般採用後者,配置好後,就可以直接在teminal中使用webpack系列命令,前者易出錯且難一點。因此,使用webpack進行打包,一般我們需要在專案中新建一個webpack.config.js配置檔案,基本結構如上圖所示,作用就是告訴webpack需要做些什麼。
(1)entry:webpack工作開始的地方,找到所依賴的模組,按順序利用Loader處理
三種資料型別:字串、陣列(陣列中每一項都會被打包,形成互不依賴的檔案)、物件(物件中每一個屬性都會被打包,形成互不依賴的檔案)

(2)output:打包後文件的具體配置,打包檔案所在路徑及打包後文件的名字,常用的屬性配置如下:
path:打包後文件所在路徑;
filename:打包後文件的名字(四種常見寫法:自定義、[name].js即入口的檔名、[hash].js打包後的hash值、[chunkhash]該塊打包後的hash值);
publicPath:上線時的公共路徑,主要應用於線上(eg:如果是設定了為static,則線上執行時,http://localhost:port/static/入口路徑);
chunkFilename:’js/[name].js’:按需載入模組時輸出的檔名稱;

(3)module——Loader: 將不同格式的模組轉換為瀏覽器統一可識別的,利用test進行正則匹配。兩種寫法:loaders:[{loader:’style-loader’},{loader:’ ‘},{loader:’ ‘}]或者是使用!號拼接的方法:loader:”loader1!loader2!…”

(4)plugins:外掛用於擴充套件更多的功能需求;
使用較多的是html-webpack-plugin外掛,用於生成HTML(如果需要多頁面,有幾個頁面就需要幾個htmlWebpackPlugin);
還有webpack-dev-middleware中介軟體,好處就是不會向硬碟寫檔案,而在記憶體中,檔案改變時儲存後,只要直接重新整理瀏覽器就可以看到最新結果;
如果想要不用重新整理就能檢測到變化自動更新,則需要webpack-hot-middleware,進行頁面的熱過載的;

(5)devtools:可設定生成不同的sourcemap型別,方便除錯定位;

(5)devServer:本地伺服器,可以監聽程式碼修改,並自動重新整理顯示修改後的結果;

(6)resolve: 設定模組被解析的一些約定(如引入方式等,extention:[“.js”,”.html”,”css”,…],這表明我們在require載入對應字尾名的檔案時,可以省略字尾名);

四、手把手跟著前輩腳步走
正是通過對這篇文章——一步步構造自己的vue2.0+webpack環境的反覆實踐,終於對webpack更熟悉瞭解了。然後由於這篇文章是博主16年底寫的,如今的新版執行,在寫法和使用上可能又很大的差別,因此,雖然博主手把手地寫下了這篇部落格,我也踩了大半天的坑。
1.簡要記錄下自己修改的幾個地方:
(1)安裝未安裝的依賴;
(2)修改現在的loader寫法,module/rules:[];
(3)且在書寫匹配不同的loader時,不能省略字尾eg:vue-loader;
(4)去掉沒有的Fevlist物件屬性;
(5)另外還需要新建出口檔案output;

2.途中的小疑問
(1)利用node.js中的express伺服器和webpack中dev server實現開啟服務有什麼不同嗎?
經查詢,dev server也是一個輕量級的node.js express伺服器,實際上相當於是一個封裝好的express的http伺服器+呼叫webpack-dev-middleware。
例如一般可能會有如下的配置,當伺服器啟動時,啟動命令是:webpack-dev-server –config wepack.config.js(配置檔案路徑),在解析模板列表前會有如圖所示的提示資訊。

devServer: {
  historyApiFallback: true, // 404的頁面會自動跳轉到/頁面
  inline: true, // 檔案改變自動重新整理頁面
  port: 3800, // 伺服器埠 
  },

這裡寫圖片描述

而我們可以使用express伺服器進行更多的擴充套件,結合使用其他的中介軟體來響應http請求及其他的功能,擴充套件性更好,較為靈活。這種方式下的編譯命令一般是:node build/dev-server.js(配置檔案路徑)。
補充:中介軟體,是一個函式,用於訪問請求物件、響應物件和web應用中處於請求-響應迴圈流程中的中介軟體。它的功能包括:執行任何程式碼、修改請求和響應物件、終結請求-響應迴圈和呼叫堆疊中的下一個中介軟體。

(2)熱載入/熱更新,使用devServer和使用webpack-dev-middleware+webpack-hot-middleware區別
devServer正如(1)中一樣,express+webpack-dev-middleware,原始檔改動後,會進行實時編譯,再用webpack-dev-middleware將編譯後文件輸出到記憶體中.
而後面兩種,如果單用前面一種需要手動重新整理瀏覽器,加上webpack-hot-middleware才可以實現瀏覽器的無重新整理更新,也就是HMR,不需要重新整理整個頁面。熱載入卻要重新整理整個頁面。

(⊙o⊙)我天我在說啥,我也搞不清楚了,上面兩個問題僅限於當下的理解,避免不了有錯誤之處。

(3)path.resolve( ),到底是怎麼進行路徑轉換的?

path.resolve('/foo','/bar','baz');     // /bar/baz
path.resolve('/foo/bar','./baz');      // /foo/bar/baz
path.resolve('/foo/bar','/tmp/file/'); // /tmp/file

查詢了官方API,寫得比較隱晦,只寫了結果沒有具體原理,還有看到了這篇文章《JavaScript 標準參考教程(alpha)》,by 阮一峰,其中列了一個小例項來說明。

path.resolve('foo/bar', '/tmp/file/', '..', 'a/../subfile')

其執行效果類似於:

cd foo/bar
cd /tmp/file
cd ..
cd a/../subfile
pwd       //展示整個路徑名

在程式碼裡驗證列印輸出為: /tmp/subfile。最開始進入foo/bar路徑目錄下,然後又進入tmp/file目錄下(末尾的/自動隱藏),又進入當前路徑的上層路徑即tmp下,接著就是又進入當前目錄下的a即tmp/a,然後又是上級tmp/,最後就是subfile,因此最終路徑為tmp/subfile。
即resolve進行路徑轉換時,同級目錄引數,前面的直接被覆蓋!正如例子中(1),bar覆蓋了foo.