Rails Turbo结合content_for加载JS返回不执行如何禁用缓存
核心原因
Turbo Drive导航时不会全量替换<head>内容,只会做节点差异对比:已经存在的<script type="module">标签不会被移除重插。而ES模块本身有单次执行特性——同地址模块只要在当前页面生命周期里加载过一次,后续再插入相同的import脚本,浏览器也不会重新执行,这就是返回页面后功能失效的根因,不是Turbo主动缓存了你的content_for内容,是默认的head合并逻辑保留了旧脚本标签。
解决方案
按推荐优先级从高到低排列:
给按需加载的脚本加Turbo原生重载标记
这是侵入性最小的官方方案,直接给javascript_import_module_tag加data-turbo-track="reload"属性即可,修改目标页面的注入代码:<% content_for :head do %> <%= javascript_import_module_tag "foo", data: { turbo_track: "reload" } %> <% end %>Turbo在做head节点对比时,只要识别到带该属性的标签在导航后的新页面中不存在、或内容/属性有变化,会自动移除旧标签,等新页面的对应标签插入后,浏览器会重新触发模块执行,不需要修改全局布局逻辑。
针对单页面关闭Turbo缓存
如果该页面本身不需要Turbo的往返缓存加速,可以在页面head里注入Turbo缓存控制标签,让Turbo每次访问都重新渲染全页:<% content_for :head do %> <meta name="turbo-cache-control" content="no-cache"> <%= javascript_import_module_tag "foo" %> <% end %>配置后Turbo不会留存该页面的DOM快照,离开后再返回会完整重新拉取渲染页面,所有head资源都会重新插入执行,缺点是该页面的往返导航速度会略低于缓存场景。
把页面专属脚本移出head区域
Turbo导航时会全量替换<body>内的节点,你可以把页面专属的模块脚本直接放到对应页面的body末尾,不要通过:head注入:<!-- 目标页面body内容的最末尾即可 --> <script type="module">import "foo"</script>每次进入页面时,这段脚本都会随body内容重新被解析执行,不需要额外调整Turbo配置。
注意
不要通过全局配置禁用整个head区域的缓存合并逻辑,会导致全站公共CSS、公共JS每次导航都重复加载,严重拖慢页面性能,只针对需要重载的单资源、单页面做上述配置即可。
内容的提问来源于stack exchange,提问作者derschiw

