Skip to content

Commit

Permalink
Add Turbo support and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
excid3 committed Jan 3, 2021
1 parent 7787a88 commit 396fb1a
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 24 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
### Unreleased

### 2.2.0

* Add support for Turbo from Hotwire - @excid3
* Remove dependency on Vue - @excid3

### 2.1.0

* See git history
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# A Turbolinks Adapter for Vue components
# A Turbolinks & Hotwire Adapter for Vue components

![npm vue-turbolinks package version](https://img.shields.io/npm/v/vue-turbolinks.svg)

vue-turbolinks is a package to allow you to easily add Vue.js components
to your Turbolinks powered apps. We handle the Turbolinks events to
to your Turbolinks & Hotwire powered apps. We handle the events to
properly setup and teardown your Vue components on the page.

>:warning: If you're using [vue-router](https://github.com/vuejs/vue-router) or another
Javascript routing library, you don't need to use Turbolinks or this adapter.
Turbolinks is meant to level up the traditional request-render cycle
#### Supported Libraries

* Hotwire's Turbo.js
* Turbolinks

>:warning: If you're using [vue-router](https://github.com/vuejs/vue-router) or another
Javascript routing library, you don't need to use Turbolinks or this adapter.
Turbolinks is meant to level up the traditional request-render cycle
by loading the new page in the background and this adapter makes it possible
to use Vue components on pages rendered in this manner. If you've decided to
use a single-page app, you already have everything you need. :metal:
Expand All @@ -29,7 +34,7 @@ webpacker, you'll include it in your `hello_vue.js` file:
import TurbolinksAdapter from 'vue-turbolinks';
Vue.use(TurbolinksAdapter)

document.addEventListener('turbolinks:load', () => {
document.addEventListener('turbo:load', () => {
var vueapp = new Vue({
el: "#hello",
template: '<App/>',
Expand All @@ -43,7 +48,7 @@ document.addEventListener('turbolinks:load', () => {
``` javascript
import { turbolinksAdapterMixin } from 'vue-turbolinks';

document.addEventListener('turbolinks:load', () => {
document.addEventListener('turbo:load', () => {
var vueapp = new Vue({
el: "#hello",
template: '<App/>',
Expand All @@ -62,7 +67,7 @@ conditionally initialize it:
import TurbolinksAdapter from 'vue-turbolinks';
Vue.use(TurbolinksAdapter)

document.addEventListener('turbolinks:load', () => {
document.addEventListener('turbo:load', () => {
var element = document.getElementById("hello")
if (element != null) {
var vueapp = new Vue({
Expand All @@ -78,13 +83,13 @@ Or you can use a library like [Punchbox](https://github.com/kieraneglin/punchbox

### Options

You can pass in `turbolinksDestroyEvent` if you would like to customize which event Vue is torn down on. By default, this uses `turbolinks:before-cache`.
You can pass in `destroyEvent` if you would like to customize which event Vue is torn down on. By default, this uses `turbo:before-cache` or `turbolinks:before-cache`.

`Vue.use(TurbolinksAdapter, { turbolinksDestroyEvent: 'turbolinks:before-cache' })`
`Vue.use(TurbolinksAdapter, { destroyEvent: 'turbo:before-cache' })`

### A note on transitions

If a `$root` component's **root node** is a Vue `<transition>` then calling the `$destroy` method may fail, throwing `NoModificationAllowedError: Failed to set the 'outerHTML' property on 'Element'` errors on the next `turbolinks:visit` event. To prevent this, wrap the `transition` in a DOM element:
If a `$root` component's **root node** is a Vue `<transition>` then calling the `$destroy` method may fail, throwing `NoModificationAllowedError: Failed to set the 'outerHTML' property on 'Element'` errors on the next `turbo:visit` event. To prevent this, wrap the `transition` in a DOM element:

Instead of:
```
Expand Down
27 changes: 19 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
function handleVueDestruction(vue) {
var turbolinksEvent = vue.$options.turbolinksDestroyEvent || 'turbolinks:visit';
document.addEventListener(turbolinksEvent, function teardown() {
let event = vue.$options.destroyEvent || defaultEvent();

document.addEventListener(event, function teardown() {
vue.$destroy();
document.removeEventListener(turbolinksEvent, teardown);
document.removeEventListener(event, teardown);
});
}

var turbolinksAdapterMixin = {
let Mixin = {
beforeMount: function() {
// If this is the root component, we want to cache the original element contents to replace later
// We don't care about sub-components, just the root
if (this === this.$root && this.$el) {
handleVueDestruction(this);

// cache original element
this.$turbolinksCachedHTML = this.$el.outerHTML;
this.$cachedHTML = this.$el.outerHTML;

// register root hook to restore original element on destroy
this.$once('hook:destroyed', function() {
this.$el.outerHTML = this.$turbolinksCachedHTML
this.$el.outerHTML = this.$cachedHTML
});
}
}
};

function plugin(Vue, options) {
// Install a global mixin
Vue.mixin(turbolinksAdapterMixin)
Vue.mixin(Mixin)
}

function defaultEvent() {
if (typeof Turbo !== 'undefined') {
return "turbo:visit";
} else {
return "turbolinks:visit";
}
}

export { turbolinksAdapterMixin };
export { Mixin };
export default plugin;
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
"license": "MIT",
"keywords": [
"vue",
"turbolinks"
],
"dependencies": {
"vue": "^2.2.4"
}
"turbolinks",
"hotwire",
"turbo"
]
}

0 comments on commit 396fb1a

Please sign in to comment.