實習生在開源項目的求生經歷:認識項目

本文將站在一個實習生的角度,分享筆者在 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

  • LogicFlow 的文檔在 docs 目錄下
  • 我要開發的文檔示例在 examples 目錄下
  • packages 目錄中包含了 LogicFlow 的核心包、拓展包、示例站點
  • 一個歷來沒有見過的文件 - lerna.json
  • 開發者上手指引 - developer.md
  • LogicFlow 項目介紹 - README.md

產生疑惑

看完目錄後肯定了下一步要作的事情:跟着 developer.md 爲項目安裝依賴。json

從 developer.md 中能夠得知安裝依賴的命令:bootstrap

npm run bootstrap
複製代碼

執行完成以後,LogicFlow 的根目錄和 examples、core、extension、site 目錄下都多了一個 node_modules 文件夾,此時我產生了幾個疑問:bash

  • 爲何 LogicFlow 要在一個項目中存放多個項目?
  • npm run bootstrap 命令是如何作到同時爲多個項目安裝依賴的?

好奇心驅使我查看了 npm run bootstrap 中的原始命令,在根目錄的 package.json 中,bootstrap 是這樣定義的:

{
  "scripts": {
    "bootstrap": "yarn && lerna bootstrap",
  }
}
複製代碼

很明顯,npm run bootstrap 先經過 yarn 根據根目錄的 package.json 爲項目安裝了全局依賴,而後經過 lerna bootstrap 爲 examples、core、extension 和 site 各自安裝了依賴。

分析盲點(monorepo 與 lerna)

到目前爲止,我能夠肯定 LogicFlow 使用 lerna 這個東西對項目進行了工程化管理,lerna 支持了一個項目中能夠存放多個子項目,同時 lerna 對我來講是一個新的知識盲點。

帶着疑惑,找到了 lerna 的代碼倉庫,在官方 README.md 中,我快速捕捉瞭如下關鍵信息:

  • lerna 是一個 JavaScript 項目的管理工具,這些項目內部能夠包含多個包
  • 這種一個項目包含多個包的形式被稱爲 multi-package repository(或者 monorepo)

同時找到了 lerna 的核心命令 lerna bootstrap,它主要完成了如下內容:

  • 在項目的每一個包的目錄下執行 npm install,爲其安裝外部依賴
  • 爲相互依賴的兩個包之間創建軟鏈(symlink)

軟鏈關係以下:

/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 // 軟鏈
複製代碼

如今就能夠解釋以前的幾個疑問了:

  • npm run bootstrap 命令是如何作到同時爲多個項目安裝依賴的?
    • npm run bootstrap 在每一個包目錄下執行了 npm install
  • 爲何 LogicFlow 要在一個項目中存放多個項目?
    • extension 依賴於 core,而 examples 和 site 依賴於 extension + core,將它們放到一個項目中能夠實現同時開發、同時發版,且 lerna 的 symlink 能夠保證各個包直接依賴於其餘包在本地的最新代碼
  • 根目錄下那個歷來沒有見過的文件 lerna.json 是幹啥的?
    • 是 lerna 的配置文件,能夠告訴 lerna 項目中存在哪些 packages

成功啓動

已經知道,各個包之間能夠直接引用本地的最新代碼進行開發,如今咱們應該在啓動項目以前,先把各個包構建一下以便其餘包引用,如 developer.md 中的構建命令:

# 先構建類型
# LogicFlow 使用 TS 進行開發,不一樣的包之間存在類型依賴
npm run build:types
 # 構建源碼
npm run build
複製代碼

在根目錄執行完上面兩個命令以後,就能夠進入 examples 目錄進行開發調試了:

cd examples
npm run start
複製代碼

工具優化

到了 LogicFlow 開源時,項目的多包管理形式發生了新的變化。在 LogicFlow 正式發佈的過程當中,師兄添加了一個 yarn workspaces 的功能,這一樣又觸及到了個人知識盲區。

新的疑問(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 和 lerna 均可覺得各個包安裝依賴並添加軟鏈,那麼這二者的區別是什麼?
  • 爲何有了 yarn workspaces 以後,仍然要保留 lerna?

帶着這幾個疑問,又開始了新的探索。

workspaces 與 lerna 的對比

一樣的,我找到了 yarn 對 workspaces 的介紹,文檔中表示,yarn workspaces 可以完成如下任務:

  • 能夠爲本地相互依賴的包之間建立軟鏈(symlink)
  • 將各個包之間的依賴安裝到一塊兒,放到根目錄下
  • 各個包使用同一個 yarn.lock 文件,以減小衝突,方便查看

也就是說,yarn workspaces 一樣也是一個 monorepo 的管理工具,可是它所提供的功能僅僅與 lerna 提供的底層功能同樣,爲本地相互依賴的包創建軟鏈,並在此基礎上進行優化,將各個包的共同依賴抽離出來到根目錄。

yarn workspaces 除了提供 lerna 的底層功能之外,其餘高級功能均不支持,這就是爲何有了 yarn workspaces 以後,LogicFlow 仍然保留 lerna 的緣由:

  • 使用 yarn workspaces 來代替 lerna bootstrap 安裝依賴
  • 仍然使用 lerna 所提供的各類高級功能,例如:
    • 使用 lerna version 爲各個包的變動代碼添加 tag
    • 使用 lerna publish 來同時發佈多個包

因此,針對於 monorepo 的形式,咱們能夠同時使用 workspaces 和 lerna 來進行項目管理。另外,在 npm 7.x 版本中也已經支持了 workspaces 功能。

思考總結

從剛加入 LogicFlow 時,項目就已經開始使用 monorepo 的管理形式了,那麼就會有對應的疑問,LogicFlow 爲何要用 monorepo 呢,它的優勢在哪裏,它有沒有什麼缺點呢?

monorepo 的優勢

以 LogicFlow 爲例,我總結了 monorepo 爲項目帶來的一些優勢:

便於代碼引用

monorepo 能夠保證 extension 直接引用到本地 core 的最新代碼,若是是 multirepo 的形式,須要先通過 core 的發包,而後在 extension 中下載使用。img

monorepo 能夠在開發過程當中省去對 core 包的頻繁發版與安裝。

便於依賴管理

monorepo 能夠一次爲多個包安裝依賴,若是是 multirepo,須要爲每一個項目都安裝一次依賴。img

使用前文中的 workspaces,還能夠將相同的依賴從各個包中抽離出來,減小整個項目在本地的體積。

便於快速發版

在 LogicFlow 中,extension 依賴於 core 的代碼,當 core 發生變動後,extension 經常也要隨之改變,爲了保證這兩個包之間的依賴關係清晰穩定,LogicFlow 始終保持二者的版本號一致,這就須要同步地快速發版,monorepo 能夠保證同時對多個包進行操做。

img

monorepo 的缺點

實際上,monorepo 的優勢基本是由各類工具在 monorepo 的基礎上帶來的,其 monorepo 自己也存在缺點。

管理成本

在 monorepo 中進行多個包的開發、聯調、上線時,仍然須要執行屢次打包或上線的命令,例如,當 LogicFlow 的 core 和 extension 發生變更後,對應的 examples 也會變化,這就須要先分別對 core 和 extension 進行打包,而後供 examples 的開發使用,因此 monorepo 的每個動做包含了多個項目的步驟,使得管理成本上升。

解決方案:引入 lerna 來管理 monorepo,能夠實現對多個包的同時構建或上線等。

項目體積變大

當全部的包都放到一個項目裏,安裝依賴以後整個項目的體積會變大,多個類似的 node_modules 會使得項目體積飆升。

解決方案:使用 workspaces 將不一樣包中相同的依賴安裝到根目錄下,以便依賴的複用。

commits 易混亂

在一個 git repository 中修改多個包的代碼,會致使多個包的 commits 摻雜在一塊兒,在查看 commit log 的過程當中會增長分析成本。

解決方案:規範 commit 格式,在 commit 中註明改動所屬的包,例如:fix(core): something。

訪問權限控制缺失

多個包放到同一個倉庫中意味着它們的訪問權限必須是一致的,對於 LogicFlow 這種開源項目並無影響,但當某些項目擁有不一樣訪問權限的包時,monorepo 並不適用。

夢的開始

每一個程序員都會懂得,職業生涯中可以有一個好的項目做爲磨練本身的機會是很是可貴的,開源項目脫離了業務需求中邏輯的重複性和複雜性,保留了對行業內各類前沿技術的應用,是讓開發者快速成長的好機會。可以有機會加入 LogicFlow,對我這個實習生而言是很是幸運的,如同作夢同樣,在 LogicFlow 中所遇到的每個疑問和難題,都像是有位老師在指引我前行。

最後

本篇文章以一個實習生的視角,講述了在第一次面對開源項目 LogicFlow 時所遇到的「新概念」 - monorepo,並分享了筆者對於 monorepo 學習和理解,monorepo 自己瑕不掩瑜,是開源項目能夠考慮使用的一種包的管理形式,在後面的實習階段,筆者還會將其餘所遇到的有意思的新挑戰分享給你們。

更多閱讀資料:

相關文章
相關標籤/搜索