本文將站在一個實習生的角度,分享筆者在 LogicFlow 中的實習經驗和對於所遇問題的一些分析解決思路。本篇文章並非把實習總結一條條的羅列出來,而是把實習的經歷和技術文章結合到一塊兒,講述實習生是如何在開源項目中快速成長的,與技術文章相比,閱讀起來相對輕鬆。node
往前數算剛好一全年,當時大三的我剛剛加入春招大軍,正在一場場面試中因被面試官拒絕而懷疑自我,又在一次次被拒後的自我反思中重拾自信,過了兩個多月纔在春招的末尾找到了第一份實習工做,隨即跨越半個中國來到深圳的一家銀行類公司,跟着師兄作了一些零零散散的小項目。在第一份實習中,最主要的收穫僅僅是感覺到了職場與校園之間的一些差別,而在技術上,因爲受到項目體量的限制,成長速度較爲緩慢。第一份實習接近尾聲時恰逢秋招伊始,或許是受益於第一段實習的經歷,個人簡歷和麪試都得到了不錯的反饋,最終從手裏的 offer 中選擇了滴滴,校招也就此順利收官。git
與滴滴簽約後,想着早些熟悉一下之後的同事和項目,我提早來到北京實習。入職第一天,中午吃飯時從師兄口中得知,團隊正在作一個開源項目(LogicFlow),我實習階段的主要工做就是協助他們作一些開發。程序員
聽到開源項目的時候,個人心裏一顫,在潛意識裏,開源項目開發難度大,且對開發者的技術水平要求高,自覺有些難以勝任,同時又以爲異常幸運,歷來沒有想到能夠在實習階段遇上「造火箭」,將來會有大量的機遇推進我去學習新的知識,就這樣帶着一全年中最大的幸運開始了本身的實習生活。github
剛入職時,組內大佬們就已經完成了 LogicFlow 的核心功能以及對應文檔,此時的 LogicFlow 還未開源,個人起步工做是爲文檔添加可操做的示例。面試
拿到內部倉庫的訪問權限後,我把代碼下載到本地,粗略瀏覽了一下項目目錄的大體結構:shell
LogicFlow
├── docs // 文檔
├── examples // 示例
├── packages
│ ├── core // 核心包
│ │ ├── src
│ │ └── package.json
│ ├── extension // 拓展包
│ │ ├── src
│ │ └── package.json
│ └── site // 調試示例
│ ├── src
│ └── package.json
├── .commitlintrc.js
├── babel.config.js
├── eslintrc.js
├── .gitignore
├── lerna.json
├── package.json
├── developer.md
├── README.md
└── yarn.lock
複製代碼
看完目錄後我獲取到了如下主要信息:npm
看完目錄後肯定了下一步要作的事情:跟着 developer.md 爲項目安裝依賴。json
從 developer.md 中能夠得知安裝依賴的命令:bootstrap
npm run bootstrap
複製代碼
執行完成以後,LogicFlow 的根目錄和 examples、core、extension、site 目錄下都多了一個 node_modules 文件夾,此時我產生了幾個疑問:bash
好奇心驅使我查看了 npm run bootstrap 中的原始命令,在根目錄的 package.json 中,bootstrap 是這樣定義的:
{
"scripts": {
"bootstrap": "yarn && lerna bootstrap",
}
}
複製代碼
很明顯,npm run bootstrap
先經過 yarn 根據根目錄的 package.json 爲項目安裝了全局依賴,而後經過 lerna bootstrap 爲 examples、core、extension 和 site 各自安裝了依賴。
到目前爲止,我能夠肯定 LogicFlow 使用 lerna 這個東西對項目進行了工程化管理,lerna 支持了一個項目中能夠存放多個子項目,同時 lerna 對我來講是一個新的知識盲點。
帶着疑惑,找到了 lerna 的代碼倉庫,在官方 README.md 中,我快速捕捉瞭如下關鍵信息:
同時找到了 lerna 的核心命令 lerna bootstrap,它主要完成了如下內容:
軟鏈關係以下:
/node_modules
/examples
└── node_modules
├── @logicflow/core --> /packages/core // 軟鏈
└── @logicflow/extension --> /packages/extension // 軟鏈
/packages
├── core
│ └── node_modules
├── extension
│ └── node_modules
│ └── @logicflow/core --> /packages/core // 軟鏈
└── site
└── node_modules
├── @logicflow/core --> /packages/core // 軟鏈
└── @logicflow/extension -> /packages/extension // 軟鏈
複製代碼
如今就能夠解釋以前的幾個疑問了:
已經知道,各個包之間能夠直接引用本地的最新代碼進行開發,如今咱們應該在啓動項目以前,先把各個包構建一下以便其餘包引用,如 developer.md 中的構建命令:
# 先構建類型
# LogicFlow 使用 TS 進行開發,不一樣的包之間存在類型依賴
npm run build:types
# 構建源碼
npm run build
複製代碼
在根目錄執行完上面兩個命令以後,就能夠進入 examples 目錄進行開發調試了:
cd examples
npm run start
複製代碼
到了 LogicFlow 開源時,項目的多包管理形式發生了新的變化。在 LogicFlow 正式發佈的過程當中,師兄添加了一個 yarn workspaces 的功能,這一樣又觸及到了個人知識盲區。
有了 yarn workspaces 以後,package.json 發生了變動:
{
"workspaces": ["packages/*", "examples"],
"scripts": {
"bootstrap": "yarn",
}
}
複製代碼
在 package.json 中新增了一個 workspaces 的字段,而 npm run bootstrap 命令只經過執行 yarn 來安裝依賴。安裝依賴以後,與添加 yarn workspace 以前相比,惟一不一樣的點來自於各個包的 node_modules 內部,即各個包中若是有相同的依賴,那麼這些依賴會被提取到根目錄下的 node_modules 中,而整個項目在本地的體積就會大大縮小。
例如,在 core、extension、examples、site 這四個包中都使用了 @babel/core 這個工具,那麼 @babel/core 就會被提取到根目錄下的 node_modules 中,而那四個包的 node_modules 目錄就縮減了下來。
/node_modules
├── @babel/core
├── @logicflow/core --> /packages/core // 軟鏈
└── @logicflow/extension --> /packages/extension // 軟鏈
/examples
└── node_modules
/packages
├── core
│ └── node_modules
├── extension
│ └── node_modules
└── site
└── node_modules
複製代碼
與添加 yarn workspaces 以前相比,最重要的一點是軟鏈(symlink)的功能保存了下來,到此爲止,這個 yarn workspaces 又讓我產生了新的疑惑:
帶着這幾個疑問,又開始了新的探索。
一樣的,我找到了 yarn 對 workspaces 的介紹,文檔中表示,yarn workspaces 可以完成如下任務:
也就是說,yarn workspaces 一樣也是一個 monorepo 的管理工具,可是它所提供的功能僅僅與 lerna 提供的底層功能同樣,爲本地相互依賴的包創建軟鏈,並在此基礎上進行優化,將各個包的共同依賴抽離出來到根目錄。
yarn workspaces 除了提供 lerna 的底層功能之外,其餘高級功能均不支持,這就是爲何有了 yarn workspaces 以後,LogicFlow 仍然保留 lerna 的緣由:
因此,針對於 monorepo 的形式,咱們能夠同時使用 workspaces 和 lerna 來進行項目管理。另外,在 npm 7.x 版本中也已經支持了 workspaces 功能。
從剛加入 LogicFlow 時,項目就已經開始使用 monorepo 的管理形式了,那麼就會有對應的疑問,LogicFlow 爲何要用 monorepo 呢,它的優勢在哪裏,它有沒有什麼缺點呢?
以 LogicFlow 爲例,我總結了 monorepo 爲項目帶來的一些優勢:
monorepo 能夠保證 extension 直接引用到本地 core 的最新代碼,若是是 multirepo 的形式,須要先通過 core 的發包,而後在 extension 中下載使用。
monorepo 能夠在開發過程當中省去對 core 包的頻繁發版與安裝。
monorepo 能夠一次爲多個包安裝依賴,若是是 multirepo,須要爲每一個項目都安裝一次依賴。
使用前文中的 workspaces,還能夠將相同的依賴從各個包中抽離出來,減小整個項目在本地的體積。
在 LogicFlow 中,extension 依賴於 core 的代碼,當 core 發生變動後,extension 經常也要隨之改變,爲了保證這兩個包之間的依賴關係清晰穩定,LogicFlow 始終保持二者的版本號一致,這就須要同步地快速發版,monorepo 能夠保證同時對多個包進行操做。
實際上,monorepo 的優勢基本是由各類工具在 monorepo 的基礎上帶來的,其 monorepo 自己也存在缺點。
在 monorepo 中進行多個包的開發、聯調、上線時,仍然須要執行屢次打包或上線的命令,例如,當 LogicFlow 的 core 和 extension 發生變更後,對應的 examples 也會變化,這就須要先分別對 core 和 extension 進行打包,而後供 examples 的開發使用,因此 monorepo 的每個動做包含了多個項目的步驟,使得管理成本上升。
解決方案:引入 lerna 來管理 monorepo,能夠實現對多個包的同時構建或上線等。
當全部的包都放到一個項目裏,安裝依賴以後整個項目的體積會變大,多個類似的 node_modules 會使得項目體積飆升。
解決方案:使用 workspaces 將不一樣包中相同的依賴安裝到根目錄下,以便依賴的複用。
在一個 git repository 中修改多個包的代碼,會致使多個包的 commits 摻雜在一塊兒,在查看 commit log 的過程當中會增長分析成本。
解決方案:規範 commit 格式,在 commit 中註明改動所屬的包,例如:fix(core): something。
多個包放到同一個倉庫中意味着它們的訪問權限必須是一致的,對於 LogicFlow 這種開源項目並無影響,但當某些項目擁有不一樣訪問權限的包時,monorepo 並不適用。
每一個程序員都會懂得,職業生涯中可以有一個好的項目做爲磨練本身的機會是很是可貴的,開源項目脫離了業務需求中邏輯的重複性和複雜性,保留了對行業內各類前沿技術的應用,是讓開發者快速成長的好機會。可以有機會加入 LogicFlow,對我這個實習生而言是很是幸運的,如同作夢同樣,在 LogicFlow 中所遇到的每個疑問和難題,都像是有位老師在指引我前行。
本篇文章以一個實習生的視角,講述了在第一次面對開源項目 LogicFlow 時所遇到的「新概念」 - monorepo,並分享了筆者對於 monorepo 學習和理解,monorepo 自己瑕不掩瑜,是開源項目能夠考慮使用的一種包的管理形式,在後面的實習階段,筆者還會將其餘所遇到的有意思的新挑戰分享給你們。
更多閱讀資料: