{"id":26512082,"url":"https://github.com/mclintprojects/actioncable-vue","last_synced_at":"2025-05-15T13:07:54.411Z","repository":{"id":33958526,"uuid":"164097303","full_name":"mclintprojects/actioncable-vue","owner":"mclintprojects","description":"A Vue plugin that makes integrating Rails Action Cable dead-easy.","archived":false,"fork":false,"pushed_at":"2024-12-14T17:22:57.000Z","size":940,"stargazers_count":184,"open_issues_count":1,"forks_count":37,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T22:35:27.090Z","etag":null,"topics":["actioncable","javascript","rails","real-time","vue","vuejs2","websocket"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mclintprojects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-04T11:06:52.000Z","updated_at":"2025-02-17T20:04:20.000Z","dependencies_parsed_at":"2024-06-18T17:08:15.819Z","dependency_job_id":"41c2342b-6659-466d-a73b-51b267c6bf84","html_url":"https://github.com/mclintprojects/actioncable-vue","commit_stats":{"total_commits":202,"total_committers":11,"mean_commits":"18.363636363636363","dds":"0.19306930693069302","last_synced_commit":"ac1c863adcbad71ade12cd6521778c8cc4ccf804"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mclintprojects%2Factioncable-vue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mclintprojects%2Factioncable-vue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mclintprojects%2Factioncable-vue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mclintprojects%2Factioncable-vue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mclintprojects","download_url":"https://codeload.github.com/mclintprojects/actioncable-vue/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253645495,"owners_count":21941316,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actioncable","javascript","rails","real-time","vue","vuejs2","websocket"],"created_at":"2025-03-21T03:18:53.954Z","updated_at":"2025-05-15T13:07:49.400Z","avatar_url":"https://github.com/mclintprojects.png","language":"JavaScript","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/mclintprojects/actioncable-vue/\"\u003e\u003cimg src=\"https://github.com/mclintprojects/actioncable-vue/actions/workflows/test.yml/badge.svg\" /\u003e\u003c/a\u003e\n  \u003cimg alt=\"Last Commit\" src=\"https://badgen.net/github/last-commit/mclintprojects/actioncable-vue\" /\u003e\n  \u003cimg alt=\"All Contributors Count\" src=\"https://img.shields.io/github/contributors/mclintprojects/actioncable-vue\"/\u003e\n  \u003ca href=\"https://www.npmjs.com/package/actioncable-vue\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/actioncable-vue.svg\"/\u003e\u003c/a\u003e\n  \u003cimg alt=\"Bundle Size\" src=\"https://badgen.net/bundlephobia/minzip/actioncable-vue\"/\u003e\n  \u003cimg alt=\"Downloads\" src=\"https://img.shields.io/npm/dt/actioncable-vue.svg\"/\u003e\n  \u003ca href=\"https://github.com/mclintprojects/actioncable-vue/\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/mclintprojects/actioncable-vue.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/mclintprojects/actioncable-vue/\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/actioncable-vue.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://vuejs.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/vue-3.x-purple.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://vuejs.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/vue-2.x-purple.svg\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003eActionCableVue is an easy-to-use Action Cable integration for VueJS.\u003cp\u003e\n\n#### 🚀 Installation\n\n```bash\nnpm install actioncable-vue --save\n```\n\n```javascript\n// Vue 3.x\nimport { createApp } from \"vue\";\nimport App from \"./App.vue\";\nimport ActionCableVue from \"actioncable-vue\";\n\nconst actionCableVueOptions = {\n  debug: true,\n  debugLevel: \"error\",\n  connectionUrl: \"ws://localhost:5000/api/cable\", // If you don\"t provide a connectionUrl, ActionCable will use the default behavior\n  connectImmediately: true,\n  unsubscribeOnUnmount: true,\n};\n\ncreateApp(App)\n  .use(store)\n  .use(router)\n  .use(ActionCableVue, actionCableVueOptions)\n  .mount(\"#app\");\n```\n\n```javascript\n// Vue 2.x\nimport Vue from \"vue\";\nimport ActionCableVue from \"actioncable-vue\";\nimport App from \"./App.vue\";\n\nVue.use(ActionCableVue, {\n  debug: true,\n  debugLevel: \"error\",\n  connectionUrl: \"ws://localhost:5000/api/cable\", // or function which returns a string with your JWT appended to your server URL as a query parameter\n  connectImmediately: true,\n});\n\nnew Vue({\n  router,\n  store,\n  render: (h) =\u003e h(App),\n}).$mount(\"#app\");\n```\n\n| **Parameters**       | **Type**        | **Default** | **Required** | **Description**                                                                                                                                  |\n| -------------------- | --------------- | ----------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |\n| debug                | Boolean         | `false`     | Optional     | Enable logging for debug                                                                                                                         |\n| debugLevel           | String          | `error`     | Optional     | Debug level required for logging. Either `info`, `error`, or `all`                                                                               |\n| connectionUrl        | String/Function | `null`      | Optional     | ActionCable websocket server url. Omit it for the [default behavior](https://guides.rubyonrails.org/action_cable_overview.html#connect-consumer) |\n| connectImmediately   | Boolean         | `true`      | Optional     | ActionCable connects to your server immediately. If false, ActionCable connects on the first subscription.                                       |\n| unsubscribeOnUnmount | Boolean         | `true`      | Optional     | Unsubscribe from channels when component is unmounted.                                                                                           |\n| store                | Object          | null        | Optional     | Vuex store                                                                                                                                       |\n\n#### Table of content\n\n- [Component Level Usage](https://github.com/mclintprojects/actioncable-vue#-component-level-usage)\n- [Subscriptions](https://github.com/mclintprojects/actioncable-vue#-subscriptions)\n- [Unsubscriptions](https://github.com/mclintprojects/actioncable-vue#-unsubscriptions)\n- [Manually connect to the server](https://github.com/mclintprojects/actioncable-vue#-manually-connect-to-the-server)\n- [Disconnecting from the server](https://github.com/mclintprojects/actioncable-vue#-disconnecting-from-the-server)\n- [Performing an action on your Action Cable server](https://github.com/mclintprojects/actioncable-vue#-performing-an-action-on-your-action-cable-server)\n- [Usage with Vuex](https://github.com/mclintprojects/actioncable-vue#-usage-with-vuex)\n- [Usage with Nuxt.JS](https://github.com/mclintprojects/actioncable-vue#-usage-with-nuxtjs)\n\n#### Wall of Appreciation\n\n- Many thanks to [@x88BitRain](https://github.com/x8BitRain) for adding Vue 3 compatibility\n\n#### 🌈 Component Level Usage\n\nIf you want to listen to channel events from your Vue component:\n\n1. If you're using **Vue 3** `setup` script define a `channels` object in the `setup` function.\n2. If you're using **Vue 3** `defineComponent` define a `channels` property.\n3. You need to either add a `channels` object in the Vue component **(Vue 2 only)**\n4. If you're using `vue-class-component` define a `channels` property. **(Vue 2 only)**\n\nEach defined object in `channels` will start to receive events provided you subscribe correctly.\n\n##### 1. Vue 3 `setup` script\n\n```typescript\n\u003cscript setup\u003e\nimport { onMounted, onUnmounted } from \"vue\";\n\nconst channels = {\n  ChatChannel: {\n    connected() {\n      console.log(\"connected\");\n    },\n  },\n};\n\nonMounted(() =\u003e {\n  this.$cable.registerChannels(channels);\n  this.$cable.subscribe({\n    channel: \"ChatChannel\",\n  });\n});\n\nonUnmounted(() =\u003e {\n  this.$cable.unregisterChannels(channels);\n  this.$cable.unsubscribe(\"ChatChannel\");\n});\n\u003c/script\u003e\n```\n\n##### 2. Vue 3 `defineComponent`\n\n```typescript\nimport { onMounted } from \"vue\";\n\nexport default defineComponent({\n  channels: {\n    ChatChannel: {\n      connected() {\n        console.log(\"connected\");\n      },\n      rejected() {\n        console.log(\"rejected\");\n      },\n      received(data) {},\n      disconnected() {},\n    },\n  },\n  setup() {\n    onMounted(() =\u003e {\n      this.$cable.subscribe({\n        channel: \"ChatChannel\",\n      });\n    });\n  },\n});\n```\n\n##### 3. Vue 2.x.\n\n```javascript\nnew Vue({\n  data() {\n    return {\n      message: \"Hello world\",\n    };\n  },\n  channels: {\n    ChatChannel: {\n      connected() {},\n      rejected() {},\n      received(data) {},\n      disconnected() {},\n    },\n  },\n  methods: {\n    sendMessage: function () {\n      this.$cable.perform({\n        channel: \"ChatChannel\",\n        action: \"send_message\",\n        data: {\n          content: this.message,\n        },\n      });\n    },\n  },\n  mounted() {\n    this.$cable.subscribe({\n      channel: \"ChatChannel\",\n      room: \"public\",\n    });\n  },\n});\n```\n\n##### 4. Vue 2.x `vue-class-component`\n\n```typescript\n@Component\nexport default class ChatComponent extends Vue {\n  @Prop({ required: true }) private id!: string;\n\n  get channels() {\n    return {\n      ChatChannel: {\n        connected() {\n          console.log(\"connected\");\n        },\n        rejected() {},\n        received(data) {},\n        disconnected() {},\n      },\n    };\n  }\n\n  sendMessage() {\n    this.$cable.perform({\n      channel: \"ChatChannel\",\n      action: \"send_message\",\n      data: {\n        content: this.message,\n      },\n    });\n  }\n\n  async mounted() {\n    this.$cable.subscribe({\n      channel: \"ChatChannel\",\n      room: \"public\",\n    });\n  }\n}\n```\n\n#### 👂🏾 Subscriptions\n\n###### 1. Subscribing to a channel\n\nDefine a `channels` object in your component matching the action cable server channel name you passed for the subscription.\n\n```typescript\n\u003cscript setup\u003e\nimport { onMounted } from \"vue\";\n\nconst channels = {\n  ChatChannel: {\n    connected() {\n      console.log(\"connected\");\n    },\n  },\n};\n\nonMounted(() =\u003e {\n  this.$cable.registerChannels(channels);\n  this.$cable.subscribe({\n    channel: \"ChatChannel\",\n  });\n});\n\u003c/script\u003e\n```\n\n### Important ⚠️\n\n\u003e ActionCableVue **automatically** uses your ActionCable server channel name if you do not pass in a specific channel name to use in your `channels`. It will also **override** clashing channel names.\n\n###### 2. Subscribing to the same channel but different rooms\n\n```typescript\n\u003cscript setup\u003e\nimport { onMounted } from \"vue\";\n\nconst channels = {\n  chat_channel_public: {\n    connected() {\n      console.log(\"I am connected to the public chat channel.\");\n    },\n  },\n  chat_channel_private: {\n    connected() {\n      console.log(\"I am connected to the private chat channel.\");\n    },\n  },\n};\n\nonMounted(() =\u003e {\n  this.$cable.registerChannels(channels);\n\n  this.$cable.subscribe(\n    {\n      channel: \"ChatChannel\",\n      room: \"public\"\n    },\n    \"chat_channel_public\"\n  );\n\n  this.$cable.subscribe(\n    {\n      channel: \"ChatChannel\",\n      room: \"private\"\n    },\n    \"chat_channel_private\"\n  );\n});\n\u003c/script\u003e\n```\n\n###### 3. Subscribing to a channel with a computed name\n\n```typescript\n// Conversations.vue\n\n\u003cscript setup\u003e\nimport { onMounted } from \"vue\";\nconst router = useRouter();\n\nconst openConversation = (conversationId) =\u003e {\n  router.push({name: \"conversation\", params: {id: conversationId});\n}\n\u003c/script\u003e\n```\n\n```typescript\n// Chat.vue\n\n\u003cscript setup\u003e\nimport { onMounted } from \"vue\";\nconst route = useRoute();\n\nconst channels = {\n  computed: [\n    {\n      channelName() {\n        return `chat-convo-${route.params.conversationId}`;\n      },\n      connected() {\n        console.log(\"I am connected to a channel with a computed name.\");\n      },\n      rejected() {},\n      received(data) {},\n      disconnected() {},\n    },\n  ],\n}\n\nonMounted(() =\u003e {\n  this.$cable.registerChannels(channels);\n  this.$cable.subscribe({\n    channel: `chat-convo-${route.params.conversationId}`,\n  });\n});\n\u003c/script\u003e\n```\n\n#### 🔇 Unsubscriptions\n\n\u003e For Vue 2.x and when using Vue 3.x `defineComponent`, when your component is **destroyed** ActionCableVue **automatically unsubscribes** from any channel **that component** was subscribed to.\n\n###### 1. Unsubscribing from a channel (Vue 3.x setup script)\n\n```typescript\n\u003cscript setup\u003e\nimport {onUnmounted } from \"vue\";\nonUnmounted(() =\u003e {\n  this.$cable.unsubscribe(\"ChatChannel\");\n});\n\u003c/script\u003e\n```\n\n###### 2. Unsubscribing from a channel Vue 2.x\n\n```javascript\nnew Vue({\n  methods: {\n    unsubscribe() {\n      this.$cable.unsubscribe(\"ChatChannel\");\n    },\n  },\n});\n```\n\n#### 🔌 Manually connect to the server\n\nActionCableVue automatically connects to your Action Cable server if `connectImmediately` is not set to `false` during setup. If you do set `connectImmediately` to `false` you can manually trigger a connection to your ActionCable server with `this.$cable.connection.connect`.\n\n```typescript\n\u003cscript setup\u003e\nconst connectWithRefreshedToken = (token) =\u003e {\n  this.$cable.connection.connect(`ws://localhost:5000/api/cable?token=${token}`);\n}\n\u003c/script\u003e\n```\n\n#### ✂️ Disconnecting from the server\n\n```typescript\n\u003cscript setup\u003e\nconst disconnect = () =\u003e {\n  this.$cable.connection.disconnect();\n}\n\u003c/script\u003e\n```\n\n#### 💎 Performing an action on your Action Cable server\n\nRequires that you have a method defined in your Rails Action Cable channel whose name matches the action property passed in.\n\n```typescript\n\u003cscript setup\u003e\nimport { onMounted } from \"vue\";\n\nconst sendMessage = () =\u003e {\n  this.$cable.perform({\n    channel: \"ChatChannel\",\n    action: \"send_message\",\n    data: {\n      content: \"Hi\",\n    },\n  });\n};\n\nconst channels = {\n  ChatChannel: {\n    connected() {\n      console.log(\"Connected to the chat channel\");\n    },\n    received(data) {\n      console.log(\"Message received\");\n    },\n  },\n};\n\nonMounted(() =\u003e {\n  this.$cable.registerChannels(channels);\n  this.$cable.subscribe({\n    channel: \"ChatChannel\",\n  });\n});\n\u003c/script\u003e\n```\n\n#### 🐬 Usage with Vuex (Vue 2.x)\n\nActionCableVue has support for Vuex. All you have to do is setup your store correctly and pass it in during the ActionCableVue plugin setup.\n\n```javascript\n// store.js\n\nimport Vue from \"vue\";\nimport Vuex from \"vuex\";\n\nVue.use(Vuex);\n\nexport default new Vuex.Store({\n  state: {},\n  mutations: {\n    sendMessage(state, content) {\n      this.$cable.perform({\n        action: \"send_message\",\n        data: {\n          content,\n        },\n      });\n    },\n  },\n  actions: {\n    sendMessage({ commit }, content) {\n      commit(\"sendMessage\", content);\n    },\n  },\n});\n```\n\n```javascript\nimport store from \"./store\";\nimport Vue from \"vue\";\nimport ActionCableVue from \"actioncable-vue\";\n\nVue.use(ActionCableVue, {\n  debug: true,\n  debugLevel: \"all\",\n  connectionUrl: process.env.WEBSOCKET_HOST,\n  connectImmediately: true,\n  store,\n});\n```\n\n#### 💪 Usage with Nuxt\n\nActionCableVue works just fine with Nuxt 2 or 3. All you need to do is set it up as a client side plugin.\n\n##### Nuxt 3\n\n```javascript\n// /plugins/actioncablevue.client.js\nimport ActionCableVue from \"actioncable-vue\";\n\nexport default defineNuxtPlugin(({ vueApp }) =\u003e {\n  const config = useRuntimeConfig();\n\n  vueApp.use(ActionCableVue, {\n    debug: true,\n    debugLevel: \"all\",\n    connectionUrl: config.public.WEBSOCKET_HOST,\n    connectImmediately: true,\n  });\n});\n\n\n// /pages/chat.vue\n\u003cscript setup\u003e\nconst { vueApp } = useNuxtApp();\n\nlet $cable;\nconst channels = {\n  ChatChannel: {\n    connected() {\n      console.log(\"connected\");\n    },\n  }\n};\n\nonMounted(() =\u003e {\n  $cable = vueApp.config.globalProperties.$cable;\n\n  $cable.registerChannels(channels, vueApp);\n  $cable.subscribe({\n    channel: \"ChatChannel\",\n  });\n});\n\nonUnmounted(() =\u003e {\n  $cable.unregisterChannels(channels, vueApp);\n  $cable.unsubscribe(\"ChatChannel\");\n});\n\u003c/script\u003e\n```\n\n##### Nuxt 2\n\n```javascript\n// /plugins/actioncable-vue.js\n\nimport Vue from \"vue\";\nimport ActionCableVue from \"actioncable-vue\";\n\nif (process.client) {\n  Vue.use(ActionCableVue, {\n    debug: true,\n    debugLevel: \"all\",\n    connectionUrl: process.env.WEBSOCKET_HOST,\n    connectImmediately: true,\n  });\n}\n\n// nuxt.config.js\nplugins: [{ src: \"@/plugins/actioncable-vue\", ssr: false }];\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmclintprojects%2Factioncable-vue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmclintprojects%2Factioncable-vue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmclintprojects%2Factioncable-vue/lists"}