从Bower迁到Yarn后Rails应用部署Heroku:预编译资产失败找不到angular文件
核心问题定位
结合从Bower迁移到Yarn的操作背景,以及给出的所有配置文件,故障本质是Heroku构建阶段无法让Sprockets识别到存放angular等前端依赖的资产路径,具体触发点可以完全从现有配置对应到:
package.json里写的软链创建脚本存在两个硬伤:一是用try/catch静默吞掉所有执行错误,Heroku构建时如果软链创建失败,不会输出任何提示,最终只暴露Sprockets找不到文件的表层错误;二是软链类型写死了junction,这是Windows系统专属的软链参数,在Heroku的Linux构建环境下,这个参数会被文件系统模块直接忽略,软链根本无法创建- 项目的
.gitignore默认会排除vendor/assets/bower_components目录,本地开发时之前手动跑过Bower/Yarn命令,已经提前生成了这个目录所以本地运行正常,但Heroku是全新的无缓存构建环境,从git拉取的代码里根本不存在这个空目录结构 - 资产预编译的执行顺序问题:Heroku默认先执行Yarn安装前端依赖、触发postinstall脚本,再执行Rails资产预编译,如果前面的postinstall脚本因为平台兼容性执行失败,后面的Sprockets流程自然找不到路径下的angular文件
可直接落地的修复步骤
- 修复postinstall脚本的跨平台兼容性
把package.json里原来的postinstall脚本替换成适配全平台的版本,去掉静默吞错的逻辑,执行失败时直接抛出可定位的报错:"postinstall": "node -e \"const fs=require('fs');const path=require('path');const sourcePath=path.resolve('node_modules/@bower_components');const linkPath=path.resolve('vendor/assets/bower_components');fs.rmSync(linkPath,{force:true,recursive:true});fs.symlinkSync(sourcePath,linkPath,process.platform==='win32'?'junction':'dir');\"" - 调整git忽略规则
打开项目根目录的.gitignore文件,找到排除vendor/assets/bower_components的规则行,把它注释掉,避免Heroku拉取代码时把后续要生成的软链路径过滤掉:# 注释原有的排除规则 # /vendor/assets/bower_components - 彻底绕开软链的稳定方案(推荐)
软链本身是构建链路里的脆弱环节,其实完全不需要创建软链——既然所有Bower依赖都已经通过Yarn安装到了node_modules/@bower_components目录下,可以直接把这个原生路径加入Rails的资产搜索范围,省掉软链创建的步骤:
修改config/application.rb里的资产路径配置:
改完之后可以直接删掉# 直接将Yarn安装的bower依赖目录加入资产搜索路径 config.assets.paths << Rails.root.join('node_modules', '@bower_components')package.json里的postinstall脚本,从根源上消除软链创建失败的风险。 - 本地验证后再部署
先在本地执行RAILS_ENV=production bundle exec rake assets:clean assets:precompile,确认预编译过程能正常识别angular、angular-resource等所有依赖文件,没有报错之后再提交代码部署到Heroku,避免把故障带到构建流程里。
容易忽略的踩坑细节
- 不要直接把本地预编译好的静态资产提交到git仓库,Rails 4.2在Heroku的构建流程里会自动完成资产预编译,提前提交静态资产反而容易出现代码和资产版本不匹配的问题
- 本地能跑通预编译,不代表Heroku环境能跑通:本地开发环境经过多次依赖安装,目录结构已经是完整状态,Heroku是全新的干净构建环境,所有路径都需要构建流程自己生成
- 当前配置的Ruby版本为2.2.2,这个版本在Heroku的最新构建栈上已经停止维护,如果修复资产路径后仍然出现隐式构建错误,可以先临时把Ruby版本升级到兼容范围,再验证资产链路的问题。
内容的提问来源于stack exchange,提问作者Layne Johnson
相关产品推荐
相关产品推荐

