=
相依性?問:我了解將我的寶石鎖定到特定版本的重要性,但為什麼我不能只在 Gemfile
中為所有相依性指定 =
版本,然後忘記 Gemfile.lock
?
答:您的許多寶石將有自己的相依性,而且它們不太可能指定 =
相依性。此外,寶石嚴格鎖定它們 所有 相依性可能是不明智的。Gemfile.lock
允許您在 Gemfile
中指定您的應用程式在 Gemfile
中需要的相依性版本,同時記住您的應用程式上次正確運作時所使用的所有第三方程式碼的確切版本。
透過在 Gemfile
中指定較寬鬆的相依性(例如 nokogiri ~> 1.4.2
),您可以執行 bundle update nokogiri
,並讓 bundler 處理更新 僅 nokogiri
及其相依性到仍滿足 ~> 1.4.2
版本需求的最新版本。這也允許您說「我想使用目前版本的 nokogiri」(gem 'nokogiri'
在您的 Gemfile
中),而不必查詢確切的版本號碼,同時仍能獲得確保您的應用程式始終以完全相同的第三方程式碼版本執行的優點。
問:我不明白為什麼我需要 bundler 以這種方式管理我的寶石。為什麼我不能只取得我需要的寶石並將它們放在子模組中,然後將每個子模組放在載入路徑上?
答:不幸的是,該解決方案要求您手動解析應用程式中的所有相依性,包括相依性的相依性。即使您成功執行此操作,如果您想更新特定寶石,您仍需要重新執行該工作。例如,如果您想更新 rails
寶石,您需要找出所有依賴於 Rails 相依性的寶石(rack
、erubis
、i18n
、tzinfo
等),並找出滿足 Rails 需求新版本的新版本。
坦白說,這是電腦擅長的問題,而身為開發人員的您不應該花時間處理。
更令人擔憂的是,如果您在手動依賴關係解析過程中犯了錯誤,您將不會收到關於不同依賴關係之間衝突的任何回饋,導致細微的執行時期錯誤。例如,如果您不小心將錯誤版本的 rack
黏貼到子模組中,它很可能會在執行時期中斷,當 Rails 或其他依賴關係嘗試依賴於不存在的方法時。
重點:即使乍看之下它可能看起來比較簡單,但它絕對顯著地更複雜。
--without
群組下載寶石?問:我執行 bundle install --without production
,而 bundler 仍然下載 :production
群組中的寶石。為什麼?
答:Bundler 的 Gemfile.lock
必須包含 Gemfile
中所有依賴關係的確切版本,無論您傳遞什麼選項。如果沒有,將您的應用程式部署到生產環境可能會改變您的所有依賴關係,消除 Bundler 的好處。您將無法再確定您的應用程式在生產環境中使用與您用於開發和測試的相同的寶石。此外,在生產環境中新增依賴關係可能會導致無法部署的應用程式。
例如,想像您有一個僅限生產環境的寶石(我們稱它為 rack-debugging
),它依賴於 rack =1.1
。如果您在執行 bundle install --without production
時沒有評估生產群組,您將部署您的應用程式,只會收到 rack-debugging
與 rails
(依賴於 actionpack
,而 actionpack
依賴於 rack ~> 1.2.1
)衝突的錯誤。
另一個範例:想像一個簡單的 Rack 應用程式在 Gemfile
中有 gem 'rack'
。同樣地,想像您將 rack-debugging
放入 :production
群組中。如果您在透過 bundle install --without production
安裝時沒有評估 :production
群組,您的應用程式將在開發中使用 rack 1.2.1
,而您將在部署時得知 rack-debugging
與您測試過的 Rack 版本衝突。
相反地,透過在呼叫 bundle install
時評估所有群組中的寶石,無論您實際上想要在該環境中使用哪些群組,我們將發現 rack-debugger
需求,並安裝與 Gemfile
中 gem 'rack'
需求也相容的 rack 1.1
。
簡而言之,透過始終評估 Gemfile
中的所有依賴關係,無論您打算在特定環境中使用哪些依賴關係,您可以在切換到不同環境中的不同群組集時避免令人不快的驚喜。而且因為我們只下載(但不安裝)寶石,所以您不必擔心僅在生產環境(或開發環境)中使用的寶石的困難安裝過程。
問:我有一個 C 擴充套件寶石,例如 mysql
,它需要特殊標記才能編譯和安裝。我如何將這些標記傳遞到這些寶石的安裝過程中?
答:首先,mysql2
寶石不存在此問題,它是 mysql
寶石的替代品。一般來說,現代 C 擴充套件會正確地發現所需的標頭。
如果您真的需要將標記傳遞到 C 擴充套件,可以使用 bundle config
指令
$ bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config
Bundler 會將此組態儲存在 ~/.bundle/config
中,而 bundler 會將組態用於同一個使用者執行的任何 bundle install
。因此,一旦您為寶石指定必要的建置標記,您就可以成功地安裝該寶石多次。
問:我沒有網路連線,但我之前已安裝過寶石。我如何讓 bundler 使用我的本機寶石快取,而不是連線到寶石伺服器?
答:在 bundle install 中使用 --local
標記。--local
標記會指示 bundler 使用本機寶石快取,而不是連線到遠端寶石伺服器。
$ bundle install --local
問:當我從 RubyGems.org 進行捆綁處理時,速度非常慢。有什麼方法可以加快速度嗎?
答:首先,透過執行 gem install bundler
更新到 Bundler 的最新版本。多年來,我們已新增許多改進,讓安裝寶石的速度更快。如果您有極高的延遲連線,您也可以透過使用 --full-index
標記來看到改善。這會一次下載寶石資訊,而不是發出許多小型 HTTP 要求。
$ bundle install --full-index
問:如果我在我的寶石中放入一個 Gemfile
會怎樣?
答:當有人安裝您的寶石時,Gemfile
和 Gemfile.lock
檔案會被完全忽略,即使您將它們包含在您上傳到 rubygems.org 的 .gem
檔案中。您寶石中的 Gemfile
只是為了讓開發人員(像您一樣)更容易安裝開發您的寶石所需的依賴項。Gemfile
還提供一種追蹤和安裝僅限開發或僅限測試寶石的簡便方法。從 Bundler in gems 頁面和 How to create a gem with Bundler 指南中閱讀寶石中的 Gemfile。
問:我在撰寫寶石時是否應該提交我的 Gemfile.lock
?
A:是的,您應該提交它。寶石儲存庫中存在 Gemfile.lock
可確保每次儲存庫的新結帳使用完全相同的依賴項組。我們相信這讓儲存庫對新舊貢獻者更友善。理想情況下,任何人都應該能夠複製儲存庫、執行 bundle install
,並通過測試。如果您沒有檢查您的 Gemfile.lock
,新的貢獻者可能會取得不同版本的依賴項,並遇到不知道如何修復的失敗測試。
Q:但我讀過寶石不應該檢查 Gemfile.lock!
A:不檢查 Gemfile.lock 的主要優點是,如果您的其中一個依賴項以中斷方式變更,新的結帳(包括 CI)將立即有失敗的測試。Bundler 團隊建議使用 Dependabot 等工具,而不是強制每個新的結帳(和可能的新的貢獻者)遇到中斷的建置,以自動建立 PR 並在您的依賴項發布新版本時執行測試套件。如果您不想使用依賴項監控機器人,我們建議建立一個額外的每日 CI 建置,在執行 bundle install
之前刪除 Gemfile.lock。這樣,您和其他人監控您的 CI 狀態的人將會是第一個知道任何因依賴項變更而產生的失敗的人。