Documentation Index
Fetch the complete documentation index at: https://mintlify.com/amark/gun/llms.txt
Use this file to discover all available pages before exploring further.
Vue Integration
GUN integrates naturally with Vue.js’s reactive data system, providing real-time synchronization across clients.
Installation
Install GUN
Add GUN to your Vue project:npm install gun
# or
yarn add gun
Include GUN in your Vue app
Import GUN in your main.js or component: Initialize GUN
Create a GUN instance and connect to peers:const gun = Gun(['http://localhost:8765/gun'])
Basic Usage
Here’s a complete example of a Todo app using GUN with Vue:
<!doctype html>
<html>
<head>
<title>Todo App: Gun + Vue</title>
<script src="https://unpkg.com/vue" type="text/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
</head>
<body>
<div id="app">
<div class="todo-wrapper">
<h1>Todos App</h1>
<input
class="add-todo"
type="text"
placeholder="Add new todo"
v-model="newTodo"
@keyup.enter="addTodo"
>
<h3>Active</h3>
<div v-for="active in activeTodos">
<label>
<input
type="checkbox"
@click.prevent="completeTodo(active.key)"
>
{{ active.todo.description }}
</label>
</div>
<h5 v-show="completedTodos.length > 0" class="completed-header">
Completed
</h5>
<div v-for="completed in completedTodos" @click="reopenTodo(completed.key)">
<span class="completed">{{ completed.todo.description }}</span>
<span class="completed-time">
(completed at {{ (new Date(completed.todo.completed)).toUTCString() }})
</span>
</div>
</div>
</div>
<script>
var gun = new Gun();
var todos = gun.get('todos');
new Vue({
data: {
todos: [],
newTodo: ""
},
computed: {
activeTodos: function() {
return this.todos.filter(function(todo) {
return todo.todo.completed === '';
});
},
completedTodos: function() {
return this.todos.filter(function(todo) {
return todo.todo.completed !== '';
});
}
},
methods: {
todoUpdated: function(todo, nodeKey) {
if (/\D/.test(nodeKey)) {
return;
}
var existingTodoIndex = this.todos.findIndex(function(todo) {
return todo.key === nodeKey
});
var todoToStore = {
todo: todo,
key: nodeKey
};
if (existingTodoIndex === -1) {
this.todos.push(todoToStore);
} else {
this.todos.splice(existingTodoIndex, 1, todoToStore);
}
},
addTodo: function() {
var newTodo = todos.get(Date.now().toString());
newTodo.put({
description: this.newTodo,
completed: ''
});
todos.set(newTodo);
this.newTodo = "";
},
completeTodo: function(key) {
todos.get(key).put({
completed: Date.now()
});
},
reopenTodo: function(key) {
todos.get(key).put({
completed: ''
});
}
},
mounted: function() {
// Subscribe to updates on the todos set
todos.map().on(this.todoUpdated.bind(this));
}
}).$mount('#app');
</script>
</body>
</html>
Vue 3 Composition API
For Vue 3 applications using the Composition API:
import { ref, onMounted, computed } from 'vue'
import Gun from 'gun'
export default {
setup() {
const gun = Gun()
const todos = gun.get('todos')
const todoList = ref([])
const newTodo = ref('')
onMounted(() => {
todos.map().on((todo, key) => {
if (key !== '_') {
const index = todoList.value.findIndex(t => t.key === key)
if (index === -1) {
todoList.value.push({ key, ...todo })
} else {
todoList.value[index] = { key, ...todo }
}
}
})
})
const addTodo = () => {
if (newTodo.value.trim()) {
todos.get(Date.now().toString()).put({
text: newTodo.value,
completed: false
})
newTodo.value = ''
}
}
const deleteTodo = (key) => {
todos.get(key).put(null)
}
return {
todoList,
newTodo,
addTodo,
deleteTodo
}
}
}
Creating a GUN Plugin for Vue
You can create a Vue plugin to make GUN available throughout your app:
// gun-plugin.js
import Gun from 'gun'
export default {
install: (app, options) => {
const gun = Gun(options.peers || [])
// Make gun available via this.$gun
app.config.globalProperties.$gun = gun
// Make gun available via inject
app.provide('gun', gun)
}
}
Usage in main.js:
import { createApp } from 'vue'
import App from './App.vue'
import GunPlugin from './gun-plugin'
const app = createApp(App)
app.use(GunPlugin, {
peers: ['http://localhost:8765/gun']
})
app.mount('#app')
Using in components:
export default {
inject: ['gun'],
mounted() {
this.gun.get('myData').on(data => {
console.log(data)
})
}
}
Vuex Integration
Integrate GUN with Vuex for centralized state management:
import Gun from 'gun'
const gun = Gun()
const store = {
state: {
todos: []
},
mutations: {
SET_TODOS(state, todos) {
state.todos = todos
},
ADD_TODO(state, todo) {
state.todos.push(todo)
},
UPDATE_TODO(state, { key, todo }) {
const index = state.todos.findIndex(t => t.key === key)
if (index !== -1) {
state.todos[index] = { key, ...todo }
}
}
},
actions: {
initTodos({ commit }) {
gun.get('todos').map().on((todo, key) => {
if (key !== '_') {
commit('UPDATE_TODO', { key, todo })
}
})
},
addTodo({ commit }, text) {
const key = Date.now().toString()
gun.get('todos').get(key).put({ text, completed: false })
},
toggleTodo({ commit }, key) {
gun.get('todos').get(key).once(todo => {
gun.get('todos').get(key).put({ completed: !todo.completed })
})
}
}
}
Check out these community-maintained Vue + GUN packages:
Best Practices
- Use computed properties: Filter GUN data in Vue computed properties for reactive updates
- Clean up listeners: Remove GUN listeners when components are destroyed
- Avoid direct mutations: Use GUN’s
.put() method to update data, not Vue’s reactive assignments
- Filter metadata: GUN uses
_ keys for metadata - filter these in your display logic
Reactive Patterns
Two-way Data Binding
data() {
return {
username: ''
}
},
watch: {
username(newVal) {
this.$gun.get('user').get('name').put(newVal)
}
},
mounted() {
this.$gun.get('user').get('name').on(name => {
this.username = name
})
}
Next Steps