yba*_*art 8 javascript ruby ruby-on-rails rails-sprockets import-maps
在应用程序中,我需要从 JS 文件实例化音频文件(我正在使用 AudioContext API),或多或少如下所示:
playAudio(url) {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
let data = await fetch(url).then(response => response.arrayBuffer());
let buffer = await this.audioContext.decodeAudioData(data)
const source = this.audioContext.createBufferSource()
source.buffer = buffer
source.connect(this.audioContext.destination)
source.start()
}
Run Code Online (Sandbox Code Playgroud)
此 JS 文件是在使用 importmap 和 Sprockets 的新 Rails 7 应用程序中加载的 Stimulus 控制器。
在开发环境中,JS 可以猜测路径,因为 Sprockets 将以规范名称(例如/assets/audio/file.wav
)来服务资产。然而,在生产中,在资源预编译期间,Sprockets 在文件名后添加一个哈希值,并且只能使用/assets/audio/file-f11ef113f11ef113f113.wav
.
该文件名无法进行硬编码,因为它取决于预编译(从技术上讲,我可能可以使用哈希对路径进行硬编码,因为文件不会经常更改,但我不想对此哈希进行任何假设)。
除公共文件夹中的其他资产外,Sprockets 在预编译期间生成的清单中引用了该文件。使用Rails.application.assets_manifest.files
我可以访问清单数据并安全地进行映射。
这是我为此编写的助手:
def audio_assets_json
audio_assets = Rails.application.assets_manifest.files.select do |_key, file|
file['logical_path'].start_with?('audio/')
end
JSON.pretty_generate(
audio_assets.to_h { |_k, f| [f['logical_path'], asset_url(f['logical_path'])] }
)
end
Run Code Online (Sandbox Code Playgroud)
但我需要从 JS 文件访问这些数据,并且清单的文件名中也有一个哈希值,所以我的 JS 无法简单地加载它。
我当前的解决方案是将其包含在我的应用程序布局中,效果很好:
<script>
window.assets = <%= audio_assets_json %>
window.asset_url = function(path) {
let result = assets[path]
return result ? result : `/assets/${path}`
}
</script>
Run Code Online (Sandbox Code Playgroud)
此解决方案的问题在于,哈希值被写入应用程序服务器的每个 HTML 响应中,效率不高。此外,助手在运行时调用,这也是低效的:这是在运行时动态生成的,而这应该在部署构建期间静态完成。
.js.erb
我最初的想法是在预编译时由 Sprockets 生成的文件中生成列表。所以我controllers/application.js
用controllers/application.js.erb
这样的方式重命名并调用助手:
<% environment.context_class.instance_eval { include ApplicationHelper } %>
window.assets = <%= audio_assets_json %>
Run Code Online (Sandbox Code Playgroud)
JS 是由 Sprockets 正确生成的,但不知何故importmap
无法看到它,并且 JS 控制台显示以下错误:
Unable to resolve specifier 'controllers/application' from http://localhost:3000/assets/controllers/index-2db729dddcc5b979110e98de4b6720f83f91a123172e87281d5a58410fc43806.js
Run Code Online (Sandbox Code Playgroud)
我尝试添加这一行config/initializers/assets.rb
:
<% environment.context_class.instance_eval { include ApplicationHelper } %>
window.assets = <%= audio_assets_json %>
Run Code Online (Sandbox Code Playgroud)
我尝试添加这一行assets/manifest.js
:
Unable to resolve specifier 'controllers/application' from http://localhost:3000/assets/controllers/index-2db729dddcc5b979110e98de4b6720f83f91a123172e87281d5a58410fc43806.js
Run Code Online (Sandbox Code Playgroud)
但这些都没有帮助。
所以我的问题是:如何使用 importmap 和 Sprockets 静态引用 JS 中的资产 URL?
归档时间: |
|
查看次数: |
992 次 |
最近记录: |