为什么bundle install会生成无法直接执行的自身binstub?
问题原理说明
1. 直接执行vendor目录下binstub报错属于预期行为
你执行bundle install --path=vendor/bundle时,所有gem被安装到隔离的vendor目录,没有加入系统/用户级的RubyGems检索路径。默认生成的binstub是RubyGems标准模板,只会从默认gem路径检索对应gem包,自然会报GemNotFoundException错误。
而bundle exec的作用就是在执行命令前,将当前项目vendor目录的gem路径注入Ruby的LOAD_PATH环境变量,让RubyGems能找到隔离安装的依赖,所以可以正常执行。
2. Bundler生成自身binstub的原因
这个行为是Bundler 2.0+版本的设计特性,不属于bug,触发条件如下:
- 当你使用
--path参数做项目依赖隔离安装时,Bundler会默认将当前执行安装操作的Bundler版本作为项目隐式依赖一并安装到vendor目录,避免后续项目执行时出现Bundler版本不兼容的问题 - 如果你的项目Gemfile或Gemfile.lock中显式声明了对bundler的依赖,也会触发Bundler将自身安装到vendor目录并生成binstub
其他项目没有出现该情况的原因
常见差异点如下:
- 其他项目使用的是2.0以下版本的Bundler,没有该默认特性
- 其他项目配置了
without bundler参数,跳过了Bundler自身的安装 - 其他项目没有在Gemfile/Gemfile.lock中声明bundler依赖,也没有使用
--path参数做隔离安装
针对IDEA兼容问题的解决方案
有几种长期解决方式,不需要每次手动删除binstub:
- 配置Bundler跳过安装自身到vendor
在项目根目录执行以下命令,生成本地Bundler配置:
后续执行bundle config set --local without 'bundler'bundle install时就不会把Bundler安装到vendor目录,也不会生成对应的binstub。 - 显式指定binstub生成路径
执行以下命令将可用的项目binstub生成到项目根的bin目录,这些binstub自带Bundler路径注入,可直接执行:
同时在IDEA的Ruby SDK配置中,将rbenv shim路径的优先级调整到vendor目录之前,即可避免IDEA优先读取vendor下的binstub。bundle config set --local bin 'bin' bundle binstubs --all - 使用新版Bundler的推荐配置写法
目前Bundler已经不推荐直接在install命令后加--path参数,你可以将路径配置写入本地配置,后续直接执行bundle install即可,逻辑和之前完全一致:bundle config set --local path 'vendor/bundle'
内容的提问来源于stack exchange,提问作者Damon Maria
相关产品推荐
相关产品推荐

