使用 socket.io 的時候,打包後臺代碼碰到的問題

前言

一般情況下,我們只會針對前端代碼,用 webpack 或者其他流行的打包工具進行打包。

因爲對於前端而言,打包有好些不言而喻的好處,比如:

  1. 代碼開發的時候更模塊化
  2. 在生產環境下,減少 http 請求,使頁面加載更快
  3. 在 babel 等工具的協助下,讓我們可以在老版本的瀏覽器上運行最新的 js 特性
  4. 可以選擇性的使用 typescript 進行開發,給前端代碼加上類型限制
  5. 。。。

由我上面列的幾條可以看到,對於目前階段,前端項目打包,已經是主流的選擇了。

但是你有沒有碰到後端也要打包的呢?

其實對於 Java 或者 c++ 這種靜態類型的語言而言,這應該是一個比較正常的需求吧,畢竟這些語言寫的代碼,本身就需要編譯了以後才能運行。

但是對於 nodejs 而言,這種打包需求反而不是太常見。

畢竟,nodejs 本身就是 JavaScript 的 runtime,直接就是用來運行 JavaScript 代碼的。

幾種對 nodejs 後臺代碼打包的方案

但是有時候,偏偏這種不尋常的需求就是不期而至。

不過幸運的是,這種需求雖然不同尋常,但是也並非沒有解決之道。

簡單的搜索一下,發現主要有以下幾種方式:

  1. ncc:https://github.com/vercel/ncc
  2. pkg: https://github.com/vercel/pkg
  3. bytenode:https://github.com/OsamaAbbas/bytenode

最後一個有點類似於 c++、Java 的編譯,將 js 代碼編譯成字節碼;pkg 也挺有意思的,將代碼和 nodejs 打包成一個可執行的二進制文件;ncc 有點類似於 webpack 打包前端代碼。

本文主要想研究的並非怎麼打包 nodejs 代碼,因此,在這裏不做詳細的贅述。

進入主題

說了這麼就,終於引出來了本文想要研究的一個主題 —— ncc 打包socket.io 的時候,還會需要依賴才能運行。

這其實是很奇怪的一件事情,因爲正常情況下,ncc打包以後,其實是將所有的依賴都打到 bundle 裏面去了。

別問我是怎麼知道的,🧐因爲我在好幾個 nodejs 項目中測試過。

而 ncc 打包以後的代碼,居然需要 socket.io-client 模塊才能運行。

我終於決定搞明白爲什麼,而且有了這篇文章,也是在我碰到了多次這個問題以後的後續了。

因爲這個問題着實太令人困擾了,爲啥偏偏是 socket.io-client 模塊呢?

爲啥後臺用 socket.io 模塊,卻需要我 node_modules 裏有 socket.io-client 才能運行呢?

帶着這樣的困惑,我開始探索起來了。

循序漸進

有人說 nodejs 後臺代碼太難調試,我極度不認同這個說法,這只是一種認知的偏見。

難用的是工具,並非是語言本身。

就像我剛開始學習 c 語言的時候,學着用 gdb 調試程序,那感覺,簡直不要太酸爽。

雖然現在看來是我喜歡的方式,但是對於初學者來說,特別是對於一枚一直習慣了使用 Windows 系統的各種 gui 程序的用戶來說,實在是太痛苦了。

後面寫 js,發現有 Chrome devtool 這種逆天的工具,當時的驚喜感,絲毫不亞於哥倫布發現新大陸。

簡直不要太秀了,有了這個工具的輔助,前端代碼還有啥祕密可言,簡直不要太 easy!

後來有個 vscode,調試 nodejs 代碼,也開始變得極度舒適了。

所以想找到問題出在哪兒,就只能藉助 vscode,來對打包後的代碼進行 debug 了。

執行打包後的代碼的時候,你會發現提示找不到這個文件,如下圖所示。
在這裏插入圖片描述
當然這是我在 Mac 系統下測試顯示的情況,Windows 下稍有不同,因爲這個地方,Windows 的代碼沒有對路徑進行轉換處理,而 Mac 下做了,因此在 Windows 下,我更能發現,這個文件是處於 socket.io-client 模塊中的。

那麼就讓我門找到這段代碼,看一下,他究竟幹了啥。

尋根究底

爲了方便查看,直接在 github 找到這段代碼的源碼

在這裏插入圖片描述

可以看到,他需要從 socliet.io-client 模塊中讀取 socket.io.js 文件,然後賦給 clientSource 這個變量。

而且,在 opts.serveClient 不等於 false 的時候,纔會執行這段邏輯。

在這裏插入圖片描述

所以我們現在就明白了,我們該如何操作來規避這個錯誤了。

創建 io 的時候,傳入配置參數,將 serveClient 設置爲 false,這個錯誤就可以避免了。
在這裏插入圖片描述

但是讓人不解的是,爲啥,socket.io 的源碼裏面,會有這麼段代碼呢?他又是幹啥用的呢?

稍微分析下,可知,我們應該從 clientSource 這個變量入手。

全局搜索一下,很快就能發現,原來是在 serve 這個方法裏提供某種路由服務。
在這裏插入圖片描述

看註釋,結合 socket.io 的特點,不難發現,可以發送 /socket.io/socket.io.js 請求嘗試一下。

serveClient 配置爲 true,再次重啓一下服務。
在這裏插入圖片描述

果不其然,謎底解開了:
在這裏插入圖片描述
這就是提供了 socket.io.js 文件在服務器中的路由位置。

開拓進取

我不清楚這段代碼的意義在哪兒,我姑且揣測一下,可能是爲了讓前端代碼,直接可以從後端服務器上拿到該文件吧。

爲了驗證我的揣測,我於是掏出了塵封已久的 Chrome,用顫抖的手,在地址欄鍵入了一行 url:https://google.com
在這裏插入圖片描述
看到了久違的畫面,我的手愈發的顫抖了,於是按耐住激動不安的心以及顫抖不已的手👋,鄭重的鍵入了 socket.io serverClient 關鍵字,之後順手熟練的按下了回車鍵。

這過程,彷佛已經在我腦海裏演練過無數遍,就如同剛纔那一剎那,按下回車的手絲毫沒有猶豫,內心更是沒有一絲絲的波動。
在這裏插入圖片描述

果不其然,在第二條結果裏面,我找到了我想要的答案
在這裏插入圖片描述

雖然寫的很隱祕,甚至作爲一個外行人壓根看不出來其用意何在。

但是不知爲何,我就是那麼的懂了,不知是作爲一枚根正苗紅的前端的直覺,還是作爲一枚“僞全棧”的直覺。

深入探究

雖然我弄明白了,但是爲了徹底的好人做到底,我又多進行了幾步操作,想看看又沒有人有我一樣的困擾。

果不其然,確實有好些人碰到同樣的問題。
在這裏插入圖片描述

有人在 ncc repository 裏提了 issue,官方貌似也發現了問題所在,做出了對應的 fix bug 的操作,也就是下面 👇 這波結果的緣由了。
在這裏插入圖片描述

這也是讓我極其困惑的一個地方,同樣的一套代碼,在 Mac 系統下,就會打包出上圖的結果,而在 Windows 系統下,並沒有產生出這樣的結果。

所以,總結一下,最好的方式,就是將 serverClient 參數設置爲 false,那麼就皆大歡喜了,即使不帶上那兩個文件,也不會出錯了。

而且爲了進一步驗證我的想法,我再次進行搜索
在這裏插入圖片描述

發現在 stackoverflow 上,大家也討論的很激烈。

有很多年以前的討論,也有近期的討論。

看來還是有很多人沒搞明白這茬的。

綜合看來,這確實是由於 socket.io 模塊,引起的一些誤會,從而導致的一系列連鎖反應。

看來寫文檔,寫代碼,確實需要多站在用戶的角度去思考下問題纔好。

不然,也許很多在我們看來順其自然的事情,在用戶看來確是奇技淫巧了,甚至於有可能會弄巧成拙了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章