Vite 原始碼解讀
今年的 iTHome 鐵人賽我挑選的主題之一,是應該沒辦法用來開課賺錢的「Vite 原始碼解讀」。
選擇這個題目的原因是今年八月份我在 {LaravelxVue} Conf 研討會上分享的主題「被 Vue 框架所耽誤的建置工具:Vite」,可惜只有短短的 40 分鐘的時間,沒辦法介紹太細節的內容。所以我決定在這次鐵人賽活動,30 天分期付款地慢慢跟大家一起研究 Vite 的原始碼,看看能不能發現什麼有趣的東西。
今年的 iTHome 鐵人賽我挑選的主題之一,是應該沒辦法用來開課賺錢的「Vite 原始碼解讀」。
選擇這個題目的原因是今年八月份我在 {LaravelxVue} Conf 研討會上分享的主題「被 Vue 框架所耽誤的建置工具:Vite」,可惜只有短短的 40 分鐘的時間,沒辦法介紹太細節的內容。所以我決定在這次鐵人賽活動,30 天分期付款地慢慢跟大家一起研究 Vite 的原始碼,看看能不能發現什麼有趣的東西。
我們身處在軟體工程師的大海、河川、小溪或水溝中,總是常聽到大家問一個古老的問題:「Junior 工程師要怎麼變成 Senior 工程師?」
老實說我沒辦法跟你說你怎麼做就馬上能讓你從 junior 工程師變成 senior 工程師,因為 senior 工程師不像超級賽亞人一樣可以說變就變的,還是有什麼開關或植入晶片就馬上有效果,如果有這種開關或晶片也請幫我安裝一打。
我沒辦法也不太喜歡給那些常在農場文上看到像是「要訓練獨立思考能力」、「要有解決問題的能力」之類的抽象建議,除非有附上實際的訓練及成果檢核方式,不然這樣的建議有說跟沒說可能差不多。不過,我倒是可以跟各位分享我從那些優秀工程師朋友們身上觀察到的 N 項神奇特質,N = 12。我不知道到底是這些特質讓他們變的優秀,還是因為他們優秀才有這些特質,但既然他們能站在那個位置,表示一定有值得學習、致敬的地方。
這篇文章的文字可能有點長,如果大家懶得看文字,也可以點開影片配雞排,不方便看用聽的也行。
另外,如果你對於學習程式或是轉職軟體工程師有興趣,可參考另一篇文章「程式為什麼這麼難學?」。
在前篇文章我跟大家介紹了 senior 工程師的共通特質以及 junior 工程師的自我修練的建議,希望對大家有些幫助。
但如果你不是軟體工程師,可能不知道在哪裡看到招生廣告點進來的,或是剛好正在考慮想要轉職軟體工程師的話,有一些過去以及我們自己帶學生的經驗可供你參考。
同樣,如果懶的看文字,也可以看影片配雞排:
從前面的「所有權(Ownership)」章節開始,接著生命週期(Lifetime)、特徵(Trait)、列舉(Enum),對平常只有撰寫前端或是只有寫 CRUD 的工程師來說(例如我就是),應該開始有一點學習上爬坡感了,這個章節會再繼續的增加一點坡度。
各位過去在寫程式的時候,有沒有遇過執行某些函數照理應該要回傳陣列,然後你會在這個陣列上呼叫 .map
或 .forEach
方法做點事情,但結果你拿到的不是陣列,而是一個 undefined
,然後程式就出錯了...
在寫程式的時候,雖然對電腦來說都是 0 跟 1,但對身為開發者的人類來說有好的命名或識別是很重要的,對自己好,對跟你一起工作的夥伴也好。
這個章節要介紹的「列舉(Enum)」並不是什麼很新或很特別的設計,在其它程式語言也常見,列舉是用來表示某種特定類型的值集合,通常會要把同樣類型的東西放在一起(例如顏色 Color
),並且給它個名字(Red
、Green
或 Blue
)。在程式碼裡使用 Enum 的時候比較不會因為不小心打錯字而造成錯誤,同時程式碼的可讀性也會比較好。
但 Rust 的 Enum 功能除了把項目列出來之外,還有一些其它程式語言的 Enum 所沒有的。
各位看到現在,都還是在學習 Rust 這個程式語言的語法,就算知道 Stack 與 Heap 的差別,也大概了解所有權跟生命週期是怎麼運作的,但如果現在要各位動手寫點程式的話,我猜大概還是不知道怎麼下手。不用太擔心,我也是。
本書前半段的內容主要是希望大家先熟悉 Rust 的設計跟語法,不求馬上就寫出什麼厲害的程式。這個章節要跟大家介紹的主題是「特徵(Trait)」,Trait 在 Rust 裡很常出現,如果能夠理解 Trait 的用途跟語法,應該就更能看懂其它人寫的程式碼或甚至是 Rust 本身的原始碼。
在前面的「所有權(Ownership)」章節曾經介紹 Rust 是如何透過所有權的轉讓與出借,來決定是否要釋放不再使用的記憶體空間,但其實在介紹所有權的時候,我們有省略了一些東西。
Rust 有「借(Borrow)」的設計,不需要複製整份資料,只要用 &
做個參照或切片,就能透過參照直接取用原本的資料。但是想像一下,如果我做了一個 Slice 指向某個 Vector,萬一那個 Vector 因為某些因素被放掉了,那麼這個 Slice 會參照到什麼東西?原本指向的記憶體位置讓出來之後假設運氣好沒有被其它資料佔用的話,也許有機會拿回來,但萬一被其它資料佔用了呢?Rust 編譯器為了確保程式可以正確執行,所以不會允許這種懸空參照(dangling reference)可能造成的不確定性,在編譯階段就會直接被擋下來。
所以如果要正常運作的話,被指到的 Vector 就不能比參照它的 Slice 還早消失對吧。Rust 的編譯器有一個 Borrow Checker(以下簡稱 BC)的設計,它會檢查參照的生命週期,如果 Rust 編譯器發現參照的資料的生命週期比較短,也就是會比較早消失,編譯就不會通過。雖然 BC 的檢查可能會有點囉嗦甚至難理解,但它可以避免常見的像是「使用後釋放(use-after-free)」或「雙重釋放(double-free)」的記憶體問題,也是它被說是比較「安全」的原因。