Rails7+StimulusJS部署Heroku遇路由错误:模块资源找不到
问题分析
开发环境正常但生产环境出现ActionController::RoutingError (No route matches [GET] "/assets/modules/seat_builder.js"),核心原因是Asset Pipeline和Importmap的配置冲突:你在manifest.js中让Asset Pipeline处理app/javascript目录下的JS文件,但Importmap已经负责模块的加载逻辑,导致生产环境试图以Asset Pipeline的方式访问模块文件,而非通过Importmap的映射解析。
解决方案
1. 修正app/assets/config/manifest.js配置
移除对app/javascript目录的Asset Pipeline链接,因为Importmap会处理这些模块的加载,不需要Asset Pipeline介入:
// app/assets/config/manifest.js //= link_tree ../images //= link_directory ../stylesheets .css //= link_tree ../../../vendor/javascript .js
(删除//= link_tree ../../javascript .js这一行)
2. 调整控制器中的导入路径为Importmap Pin名称
既然你已经在config/importmap.rb中用pin_all_from配置了模块路径,直接使用pin的名称导入,而非相对路径,避免生产环境的路径解析问题:
// app/javascript/controllers/seating_controller.js import { Controller } from "@hotwired/stimulus"; import SeatBuilder from "modules/seat_builder"; import SeatEditor from "modules/seat_editor"; import SeatReservation from "modules/reservation"; import Contingent from "modules/contingent"; import DiscountInputBuilder from "modules/discount_input_builder"; // Connects to data-controller="seating" export default class extends Controller { // 剩余代码 }
同理,seat_builder.js中的子模块导入也可以改为:
// app/javascript/modules/seat_builder.js import DivadloBroadway from "modules/theaters/divadlo_broadway"; import ObecniDum from "modules/theaters/obecni_dum"; import KostelSvatehoMartinaVeZdi from "modules/theaters/kostel_svateho_martina_ve_zdi"; export default class SeatBuilder { // 剩余代码 }
3. 确保Heroku部署时执行正确的预编译步骤
Heroku默认会运行rails assets:precompile,但可以在部署脚本中明确加入Importmap的相关命令,或者在部署后执行:
heroku run rails importmap:compile
如果存在旧的Asset缓存,先清理再预编译:
heroku run rails assets:clobber heroku run rails assets:precompile
4. 检查config/environments/production.rb配置
确保以下配置正确:
# config/environments/production.rb config.assets.compile = false # 禁用动态编译,依赖预编译的静态文件 config.public_file_server.enabled = true # 启用静态文件服务 config.assets.digest = true # 启用文件名哈希,避免缓存问题
验证部署
重新部署到Heroku后,查看日志确认错误消失,同时可以通过浏览器开发者工具的Network面板,检查JS模块是否通过Importmap正确加载(而非请求/assets/modules/...路径)。
内容的提问来源于stack exchange,提问作者TheCodeSommelier

