Rails 6搭配Import Map时Stimulus控制器加载不稳定问题排查
问题:Stimulus控制器切换到ImportMap后偶尔加载失败
将遗留Rails应用升级至Rails 6.1.3.2,同时使用Hotwire与Stimulus,直接从资产管道切换为importmap-rails gem后,出现Stimulus控制器(如测试用的hello控制器)偶尔无法加载的问题——页面刷新后有时看不到Hello World输出。此前使用资产管道时无此异常。
配置详情
Gemfile
gem 'importmap-rails', "~> 1.1.5" gem 'stimulus-rails', "~> 1.1.0" gem 'turbo-rails'
importmap.rb
pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin_all_from "app/javascript/controllers", under: "controllers"
javascript/application.js
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails import "@hotwired/turbo-rails" import "controllers"
javascript/controllers/application.js
import { Application } from "@hotwired/stimulus" const application = Application.start() // Configure Stimulus development experience application.debug = false window.Stimulus = application export { application }
javascript/controllers/index.js
// This file is auto-generated by ./bin/rails stimulus:manifest:update // Run that command whenever you add a new controller or create them with // ./bin/rails generate stimulus controllerName import { application } from "controllers/application" import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" eagerLoadControllersFrom("controllers", application)
manifest.js(遗留配置)
//= link_tree ../images //= link_tree ../fonts //= link_directory ../javascripts .js //= link_directory ../stylesheets .css //= link_tree ../javascripts/admin //= link_tree ../javascripts //= link_tree ../javascripts/devise/ .js //= link_tree ../../javascript .js //= link_tree ../../../vendor/javascript .js
layouts/application.html.erb
<head> <%= render :partial => 'shared/favicon' %> <%# stimulus_include_tags %> <%= javascript_importmap_tags %> <%= javascript_include_tag "turbo", type: "module-shim" %> <%= yield :head %> </head> <body> <div id="wrapper"> <div data-controller="hello"></div> </div> </body>
importmap json输出
{ "imports": { "application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js", "@hotwired/turbo-rails": "/assets/turbo.min-305f0d205866ac9fc3667580728220ae0c3b499e5f15df7c4daaeee4d03b5ac1.js", "@hotwired/stimulus": "/assets/stimulus.min-b8a9738499c7a8362910cd545375417370d72a9776fb4e766df7671484e2beb7.js", "@hotwired/stimulus-loading": "/assets/stimulus-loading-1fc59770fb1654500044afd3f5f6d7d00800e5be36746d55b94a2963a7a228aa.js", "controllers/dropdown_controller": "/assets/controllers/dropdown_controller-fd4f1bf22de2dbf743c9051ba338d61a1fb13147b55fe838504b78a260521b9e.js", "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js", "controllers/modal_controller": "/assets/controllers/modal_controller-ef43a7d5af349eeeb3a040a49503341ef56515c53b447a9f75b3c8b9049b77de.js", "controllers": "/assets/controllers/index-2a439010cf426766c110f1d1d2cce7a57524980516bcc71253f244766cff1e75.js", "controllers/tabs_controller": "/assets/controllers/tabs_controller-62b5446ded99b1c85952eadd043447a7569da4adcfe381745113a9f7e356e4e3.js", "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js" } }
问题分析
- 重复加载Turbo:布局中同时通过
javascript_importmap_tags(关联application.js的import "@hotwired/turbo-rails")和javascript_include_tag加载Turbo,导致Turbo多次初始化,引发与Stimulus的控制器注册冲突。 - 遗留资产管道配置:
manifest.js中保留了大量JS文件的链接规则,导致资产管道和ImportMap同时处理JS资源,造成加载顺序混乱或重复加载。 - 加载时机竞争:Turbo Drive的页面加载机制与Stimulus控制器初始化存在竞争,重复加载Turbo会加剧这种不稳定。
解决方案
移除重复的Turbo引入
删除layouts/application.html.erb中的以下代码:<%= javascript_include_tag "turbo", type: "module-shim" %>javascript_importmap_tags已经通过application.js加载了Turbo,重复引入会导致初始化冲突。清理
manifest.js的遗留配置
切换到ImportMap后,仅保留非JS资源的链接规则,修改后的manifest.js://= link_tree ../images //= link_tree ../fonts //= link_directory ../stylesheets .css移除所有指向JavaScript文件的
link_tree/link_directory配置,避免资源处理冲突。启用Stimulus调试排查
在javascript/controllers/application.js中开启调试模式:application.debug = true打开浏览器控制台,查看Stimulus的调试日志,确认控制器是否被正确注册和连接,定位加载失败的具体原因。
清除缓存并重启服务
执行以下命令清除资产缓存:rails assets:clobber # 生产环境需额外执行:rails assets:precompile重启Rails服务器,确保新配置生效。
内容的提问来源于stack exchange,提问作者Arash Hadipanah
相关产品推荐
相关产品推荐

