1 ruby ruby-on-rails jruby actioncable import-maps
Actioncable - 概述。
\n我正在使用 jruby 9.2.16(因此 ruby 2.5.7)和 Rails 6.1.6.1。
\n我不确定 Actioncable 是否仅在开发中或仅在没有 ssl (wss) 的情况下可以与简单客户端一起使用:
\nvar ws = new WebSocket(\'ws://0.0.0.0:3000/channels\');\nws.onmessage = function(e){ console.log(e.data); }\nRun Code Online (Sandbox Code Playgroud)\n但至少我没有让它在生产中使用 wss 运行“从通道流式传输”,因为它在本地工作(在终端中启动“redis-cli”,然后“监视”)。
\n所以我尝试实现可操作的客户端脚本,因此浪费了 8 天的时间。
\n首先,我对没有任何完整的描述感到困惑。许多人发布特定的解决方案,但这就像赌博:也许你很幸运。
\n其次,文件的命名方式似乎很通用,即使它们仅与可操作相关(文件夹“javascript”或“application.js”)\n不将它们称为“actioncable_files”会产生误导。 ' 和 \'actioncable_app.js\' 和 voil\xc3\xa0 由于多个同名文件而出现问题。
\n下一个问题是,只需更改很多内容,因为文件的有序结构被忽略。Javascript 不再位于 asset 中,但为什么?\n它们可能位于 asset/javascripts/actioncable/ 中?\n因此,manifest.js 必须更改,甚至必须在 application.rb 中添加属性(attr_accessor :importmap)。您在论坛几天后发现的东西。
\n但更令人困惑的是: importmap 是一个 gem,它需要一些目录,并且必须以某种方式安装(rake app:update:bin、rails importmap:install),有人写道,gems 的顺序是相关的,但你不能只卸载Actioncable gem,因为 Rails 依赖于它。可以使用优先级排列来组织依赖关系。
\nimportmaps 在 Firefox 中不起作用,因此您还需要垫片
\n但最终,importmap 所做的一切对我来说都像是重新发明轮子:它加载 javascript 文件。有些事情可以轻松手动完成。\n还可以使用简单的 JavaScript 导入模块。那么浏览器最终可以使用的 javascript 文件应该是什么呢?
\n我找不到该文件,或生成它的任何描述,或者它只是一个链接,或者必须在某个地方进行编译,但在我看来,导入映射似乎完全多余,只会使事情变得非常复杂。我不明白编写一个字符串“xyz”有什么好处,该字符串以一种费力的方式转换为另一个字符串“xyz_2”,也可能找不到。而如果有变量,可以直接使用action_cable_meta_tag相同的思路来加载。
\n从技术上讲,Actioncable 只做了 Faye 之前做过的事情。那么,为什么我们需要所谓的“现代”方式,我认为这只是重新发明轮子呢?
\n因此,我想创建一个关于如何以简单的方式安装 actioncable 的描述 - 无需不必要的工具且清晰。
\n但首先我需要让它自己工作。因此问题是:由于以下原因我该怎么办:
\nvar ws = new WebSocket(\'ws://0.0.0.0:3000/channels\');\nws.onmessage = function(e){ console.log(e.data); }\nRun Code Online (Sandbox Code Playgroud)\n谢谢大家的任何想法!
\n首先,来自importmap-rails:
注意:为了使用Action Cable、Action Text 和 Active Storage 等 Rails 框架中的 JavaScript,您必须运行Rails 7.0+。这是与这些库的 ESM 兼容版本一起发布的第一个版本。 https://github.com/rails/importmap-rails#installation
已接受的挑战。我现在将使用核磁共振成像(稍后我将尝试使用您的版本,看看是否出现任何奇怪的情况)。
$ rails _6.1.6.1_ new cable --skip-javascript
$ cd cable
# https://github.com/rails/importmap-rails#installation
$ bin/bundle add importmap-rails
$ bin/rails importmap:install
# ActionCable guide seems rather crusty. Until this section:
# https://guides.rubyonrails.org/v6.1/action_cable_overview.html#connect-consumer
# A generator for the client side js is mentioned in the code comment.
$ bin/rails g channel chat
# Oops, generated server side rb as well.
# This should really be at the start of the guide.
Run Code Online (Sandbox Code Playgroud)
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
def subscribed
# NOTE: just keep it simple
stream_from "some_channel"
end
end
Run Code Online (Sandbox Code Playgroud)
该目录app/javascript看起来很通用,因为它确实如此。这适用于所有Javascript内容,由shakapacker、jsbundling-rails、importmap-rails等使用。我在这里描述了一下: https ://stackoverflow.com/a/73174481/207090
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("ChatChannel", {
connected() {
// NOTE: We have to check if our set up is online first,
// before chatting and authenticating or anything else.
console.log("ChatChannel connected")
},
disconnected() {},
received(data) {}
});
Run Code Online (Sandbox Code Playgroud)
要广播消息,请在应用程序中的某个位置调用它[原文如此]:
ActionCable.server.broadcast("some_channel", "some message")
Run Code Online (Sandbox Code Playgroud)
好吧,无论如何我们必须制作一个控制器:
ActionCable.server.broadcast("some_channel", "some message")
Run Code Online (Sandbox Code Playgroud)
此外,还必须在某处导入频道才能加载到页面上。javascript_importmap_tags在布局中仅导入应用程序:
https ://github.com/rails/importmap-rails#usage
$ bin/rails g scaffold Message content
$ bin/rails db:migrate
$ open http://localhost:3000/messages
$ bin/rails s
Run Code Online (Sandbox Code Playgroud)
在application.js中导入频道是有意义的。无法导入,./channels/index因为它有require. 我们必须使用节点才能使其工作,或者执行其他操作来导入所有通道。手动方式是最简单的:
<script type="module">import "application"</script>
<!-- ^ -->
<!-- this imports the pinned `application` -->
Run Code Online (Sandbox Code Playgroud)
浏览器控制台显示缺少@rails/actioncable. 还没人告诉我要安装它。使用pin命令添加它:
https://github.com/rails/importmap-rails#using-npm-packages-via-javascript-cdns
// app/javascript/channels/index.js
// NOTE: it works a little differently with importmaps that I haven't mentioned yet.
// skip this index file for now, and import channels in application.js
// app/javascript/application.js
import "./channels/chat_channel"
Run Code Online (Sandbox Code Playgroud)
刷新浏览器:
ChatChannel connected chat_channel:5
Run Code Online (Sandbox Code Playgroud)
我们在页面上得到了 javascript。让我们让它广播:
$ bin/importmap pin @rails/actioncable
Run Code Online (Sandbox Code Playgroud)
ChatChannel connected chat_channel:5
Run Code Online (Sandbox Code Playgroud)
我们知道我们是有联系的。该表单正在提交,MessagesController#create无需刷新我们正在广播到“some_channel”的位置。剩下要做的就是在页面上输出数据: https:
//guides.rubyonrails.org/v6.1/action_cable_overview.html#client-server-interactions-subscriptions
# app/controllers/messages_controller.rb
# POST /messages
def create
@message = Message.create(message_params)
ActionCable.server.broadcast("some_channel", @message.content)
end
Run Code Online (Sandbox Code Playgroud)
行动电缆完成。现在让我们修复importmaps。
有些事情我之前没有提到,理解起来非常重要。
一切正常,但是,仅在开发中,我在这里解释了原因:
https ://stackoverflow.com/a/73136675/207090
URL 和相对或绝对路径不会被映射,更重要的是会绕过资产管道sprockets。要实际使用importmapsapp/javascript/channels ,必须映射(也称为固定)中的所有文件,然后在导入时仅通过固定名称引用。
# config/importmap.rb
# NOTE: luckily there is a command to help with bulk pins
pin_all_from "app/javascript/channels", under: "channels"
pin "application", preload: true
pin "@rails/actioncable", to: "https://ga.jspm.io/npm:@rails/actioncable@7.0.3-1/app/assets/javascripts/actioncable.esm.js"
# NOTE: the big reveal -> follow me ->------------------------------------------------------------------^^^^^^^^^^^^^^^^^^
# NOTE: this only works in rails 7+
# pin "@rails/actioncable", to: "actioncable.esm.js"
# `actioncable.esm.js` is in the asset pipeline so to speak and can be found here:
# https://github.com/rails/rails/tree/v7.0.3.1/actioncable/app/assets/javascripts
Run Code Online (Sandbox Code Playgroud)
有关pin和的一些信息pin_all_from:
/sf/answers/5099899381/
您可以在浏览器或终端中看到创建的导入映射:
$ bin/importmap json
{
"imports": {
"application": "/assets/application-3ac17ae8a9bbfcdc9571d7ffac88746f5a76b18c149fdaf02fa7ed721b3e7c49.js",
"@rails/actioncable": "https://ga.jspm.io/npm:@rails/actioncable@7.0.3-1/app/assets/javascripts/actioncable.esm.js",
"channels": "/assets/channels/index-78e712d4a980790be34a2e859a2bd9a1121f9f3b508bd3f7de89889ff75828a0.js",
"channels/chat_channel": "/assets/channels/chat_channel-0a2f983da2629a4d7edef5b7f05a494670df3f99ec6a22a2e2fee91a5d1c1d05.js",
"channels/consumer": "/assets/channels/consumer-b0ce945e7ae055dba9cceb062a47080dd9c7794a600762c19d38dbde3ba8ff0d.js"
}# ^ ^
} # | |
# names you use urls browser uses
# | to import ^ to actually get it
# | |
# `---> importmaped to ----'
Run Code Online (Sandbox Code Playgroud)
对于importmaps信息(不是importmap-rails gem): https:
//github.com/WICG/import-maps
导入映射不导入任何内容,它们映射name到url. 如果您使用, ,使名称看起来像url,则没有任何内容可映射。/name./name../namehttp://js.cdn/name
<!-- app/views/messages/index.html.erb -->
<div id="chat"></div> <!-- output for broadcasted messages -->
<!-- since I have no rails ujs, for my purposes: bushcraft { remote: true } -->
<!-- v -->
<%= form_with model: Message.new, html: { onsubmit: "remote(event, this)" } do |f| %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
<script type="text/javascript">
// you can skip this, I assume you have `rails_ujs` installed or `turbo`.
// { remote: true } or { local: false } is all you need on the form.
function remote(e, form) {
e.preventDefault();
fetch(form.action, {method: form.method, body: new FormData(form)})
form["message[content]"].value = ""
}
</script>
Run Code Online (Sandbox Code Playgroud)
您不想在 js 文件中使用带有绝对路径的第二种形式,因为摘要哈希会在文件更新时发生更改以使浏览器缓存无效(这是由sprockets处理的)。
转换所有导入:
// app/javascript/channels/chat_channel.js
// update received() function
received(data) {
document.querySelector("#chat")
.insertAdjacentHTML("beforeend", `<p>${data}</p>`)
}
Run Code Online (Sandbox Code Playgroud)
匹配固定的名称:
# config/importmap.rb
# NOTE: luckily there is a command to help with bulk pins
pin_all_from "app/javascript/channels", under: "channels"
pin "application", preload: true
pin "@rails/actioncable", to: "https://ga.jspm.io/npm:@rails/actioncable@7.0.3-1/app/assets/javascripts/actioncable.esm.js"
# NOTE: the big reveal -> follow me ->------------------------------------------------------------------^^^^^^^^^^^^^^^^^^
# NOTE: this only works in rails 7+
# pin "@rails/actioncable", to: "actioncable.esm.js"
# `actioncable.esm.js` is in the asset pipeline so to speak and can be found here:
# https://github.com/rails/rails/tree/v7.0.3.1/actioncable/app/assets/javascripts
Run Code Online (Sandbox Code Playgroud)
jruby上的设置相同。我刚刚安装了它并更新了我的Gemfile:
$ bin/importmap json
{
"imports": {
"application": "/assets/application-3ac17ae8a9bbfcdc9571d7ffac88746f5a76b18c149fdaf02fa7ed721b3e7c49.js",
"@rails/actioncable": "https://ga.jspm.io/npm:@rails/actioncable@7.0.3-1/app/assets/javascripts/actioncable.esm.js",
"channels": "/assets/channels/index-78e712d4a980790be34a2e859a2bd9a1121f9f3b508bd3f7de89889ff75828a0.js",
"channels/chat_channel": "/assets/channels/chat_channel-0a2f983da2629a4d7edef5b7f05a494670df3f99ec6a22a2e2fee91a5d1c1d05.js",
"channels/consumer": "/assets/channels/consumer-b0ce945e7ae055dba9cceb062a47080dd9c7794a600762c19d38dbde3ba8ff0d.js"
}# ^ ^
} # | |
# names you use urls browser uses
# | to import ^ to actually get it
# | |
# `---> importmaped to ----'
Run Code Online (Sandbox Code Playgroud)
启动服务器时出现第一个错误:
import "channels/chat_channel"
// stays unchanged and is now the same as
import "/assets/channels/chat_channel-0a2f983da2629a4d7edef5b7f05a494670df3f99ec6a22a2e2fee91a5d1c1d05.js"
// because we have an importmap for "channels/chat_channel"
Run Code Online (Sandbox Code Playgroud)
importmap=方法在这里定义: https:
//github.com/rails/importmap-rails/blob/v0.7.6/lib/importmap/engine.rb#L4
Rails::Application.send(:attr_accessor, :importmap)
Run Code Online (Sandbox Code Playgroud)
在jruby中,它以这种方式定义私有方法:
import consumer from "./consumer"
import "./channels/chat_channel"
Run Code Online (Sandbox Code Playgroud)
修复方法是覆盖应用程序中的定义,或将这些方法公开:
import consumer from "channels/consumer"
import "channels/chat_channel"
// import "channels" // is mapped to `channels/index`
// TODO: want to auto import channels in index file?
// just get all the pins named *_channel and import them,
// like stumulus-loading does for controllers:
// https://github.com/hotwired/stimulus-rails/blob/v1.1.0/app/assets/javascripts/stimulus-loading.js#L8
Run Code Online (Sandbox Code Playgroud)
就是这样。没有其他问题。无论如何,您应该预料到会遇到一些挫折,因为您使用的是jruby,它远远落后于mri。Ruby 2.5 将于 2021 年 4 月 5 日停产。您不能指望最新的 gem 能够与旧的 Ruby 版本兼容。
| 归档时间: |
|
| 查看次数: |
1534 次 |
| 最近记录: |