Troubleshooting Guide

View Source

This guide helps you diagnose and fix common issues when working with LiveVue.

Quick Start

New to LiveVue? Start with Getting Started for a working example, then check Basic Usage for common patterns.

Component Issues

Component Not Rendering

Symptoms:

  • Empty div where component should be
  • No errors in console
  • Component works in isolation

Possible Causes & Solutions:

  1. Missing v-socket attribute

    # ❌ Missing v-socket
    <.vue v-component="Counter" count={@count} />
    
    # ✅ Correct
    <.vue v-component="Counter" count={@count} v-socket={@socket} />
  2. Component name mismatch

    # ❌ File: Counter.vue, but using wrong name
    <.vue v-component="counter" v-socket={@socket} />
    
    # ✅ Correct - case sensitive
    <.vue v-component="Counter" v-socket={@socket} />

    Check browser console for errors.

  3. Component not found in resolution

    // Check your component resolution in assets/vue/index.js
    const components = {
      ...import.meta.glob("./**/*.vue", { eager: true }),
    }
    
    // Debug: log available components
    console.log("Available components:", Object.keys(components))

Component Renders But Doesn't Update

Symptoms:

  • Component shows initial state
  • Props don't update when server state changes
  • No reactivity

Solutions:

  1. Check prop names match

    # Server side
    <.vue user_name={@user.name} v-component="Profile" v-socket={@socket} />
    <!-- Client side - prop names must match exactly -->
    <script setup>
    const props = defineProps<{
      user_name: string  // Must match server prop name
    }>()
    </script>
  2. Verify assigns are updating

    # Add debug logging
    def handle_event("update", _params, socket) do
      IO.inspect(socket.assigns, label: "Before update")
      socket = assign(socket, :count, socket.assigns.count + 1)
      IO.inspect(socket.assigns, label: "After update")
      {:noreply, socket}
    end
  3. Use Vue.js devtools to inspect the component

    Open Vue.js devtools in browser and inspect the component. Check if the component is receiving the correct props. Check if the component is re-rendering when the props change.

LiveVue.Encoder Protocol Issues

Symptoms:

  • Protocol.UndefinedError when passing structs as props
  • Component doesn't render with custom struct props
  • Error mentions "LiveVue.Encoder protocol must always be explicitly implemented"

Solutions:

  1. Implement the encoder protocol for your structs

    defmodule User do
      @derive LiveVue.Encoder
      defstruct [:name, :email, :age]
    end
  2. For third-party structs, use Protocol.derive/3

    # In your application.ex or relevant module
    Protocol.derive(LiveVue.Encoder, SomeLibrary.User, only: [:id, :name])
  3. Debug encoder issues

    # Test your encoder implementation
    iex> user = %User{name: "John", email: "john@example.com"}
    iex> LiveVue.Encoder.encode(user)
    %{name: "John", email: "john@example.com"}

For complete implementation details including field selection and custom implementations, see Component Reference.

Common Causes:

  • Passing structs without implementing the encoder protocol
  • Nested structs where some don't have the protocol implemented
  • Third-party library structs that need protocol derivation

TypeScript Errors

Common Error: Cannot find module 'live_vue'

// Add to your env.d.ts or types.d.ts
declare module 'live_vue' {
  export function useLiveVue(): any
  export function createLiveVue(config: any): any
  export function findComponent(components: any, name: string): any
  export function getHooks(app: any): any
}

Error: Property 'xxx' does not exist on type

// Define proper interfaces
interface Props {
  count: number
  user: {
    id: number
    name: string
  }
}

const props = defineProps<Props>()

Event Handling Issues

Events Not Firing

Symptoms:

  • Clicking buttons does nothing
  • No events reach LiveView
  • Console shows no errors

Solutions:

  1. Check event handler syntax

    # ❌ Wrong syntax
    <.vue v-on-click={JS.push("increment")} />
    
    # ✅ Correct syntax
    <.vue v-on:click={JS.push("increment")} />
  2. Verify event names match

    <!-- Vue component -->
    <button @click="$emit('increment', {amount: 1})">+1</button>
    <!-- LiveView template -->
    <.vue v-on:increment={JS.push("inc")} />
    
    def handle_event("inc", %{"amount" => amount}, socket) do
      # Handle event
    end
  3. Check payload structure

    # Debug event payload
    def handle_event("save", params, socket) do
      IO.inspect(params, label: "Event params")
      {:noreply, socket}
    end

Events Fire But Handler Not Called

Check handler function exists:

# Make sure you have the handler defined
def handle_event("my_event", _params, socket) do
  {:noreply, socket}
end

Verify event name spelling:

# Event names are case-sensitive
<.vue v-on:save-user={JS.push("save_user")} />  # save-user → save_user

Build and Development Issues

Vite Server Not Starting

Error: EADDRINUSE: address already in use

# Kill process using port 5173
lsof -ti:5173 | xargs kill -9

# Or use different port
npm run dev -- --port 5174

Error: Module not found

# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install

Build Failures

TypeScript compilation errors:

# Check TypeScript version compatibility
npm install typescript@5.5.4 vue-tsc@2.10.0

Vite build errors:

# Clear Vite cache
rm -rf node_modules/.vite
npm run build

Hot Reload Not Working

  1. Check Vite configuration:

    // vite.config.js
    export default defineConfig({
      server: {
        host: '0.0.0.0',  // Allow external connections
        port: 5173,
        hmr: true
      }
    })
  2. Verify watcher configuration:

    # config/dev.exs
    config :my_app, MyAppWeb.Endpoint,
      watchers: [
        npm: ["--silent", "run", "dev", cd: Path.expand("../assets", __DIR__)]
      ]

SSR Issues

SSR Not Working

Check SSR configuration:

# config/dev.exs
config :live_vue,
  ssr_module: LiveVue.SSR.ViteJS,
  vite_host: "http://localhost:5173",
  ssr: true

For complete SSR configuration options, see Configuration.

Verify Node.js version:

node --version  # Should be 19+

SSR Errors in Production

Check NodeJS supervisor:

# application.ex
children = [
  {NodeJS.Supervisor, [path: LiveVue.SSR.NodeJS.server_path(), pool_size: 4]},
  # ... other children
]

Verify server bundle exists:

ls priv/vue/server.js  # Should exist after build

For production SSR setup details, see Configuration.

Performance Issues

Slow Initial Load

  1. Enable lazy loading:

    // assets/vue/index.js
    const components = {
      Counter: () => import('./Counter.vue'),
      Modal: () => import('./Modal.vue')
    }
  2. Optimize bundle size:

    # Analyze bundle
    npm run build -- --analyze
    

Memory Leaks

Clean up event listeners:

<script setup>
import { onUnmounted } from 'vue'
import { useLiveVue } from 'live_vue'

const live = useLiveVue()

const cleanup = live.handleEvent('data_update', handleUpdate)

onUnmounted(() => {
  cleanup()  // Important: clean up listeners
})
</script>

Clear timers and intervals:

<script setup>
import { onUnmounted } from 'vue'

const interval = setInterval(() => {
  // Do something
}, 1000)

onUnmounted(() => {
  clearInterval(interval)
})
</script>

Debugging Techniques

Enable Debug Mode

// In browser console or app.js
window.liveVueDebug = true

Component Inspection

  1. Use Vue DevTools browser extension
  2. Add debug logging:
    <script setup>
    import { watch } from 'vue'
    
    const props = defineProps<{count: number}>()
    
    watch(() => props.count, (newVal, oldVal) => {
      console.log('Count changed:', oldVal, '→', newVal)
    })
    </script>

Network Debugging

  1. Monitor WebSocket traffic in browser DevTools
  2. Log LiveView events:
    def handle_event(event, params, socket) do
      IO.inspect({event, params}, label: "LiveView Event")
      # ... handle event
    end

Common Error Messages

Cannot read property 'mount' of undefined

Cause: Component resolution failed

Solution: Check component name and file path

// Debug component resolution
// find component does it by default, you might need to do it if you override it
console.log("Resolving component:", componentName)
console.log("Available components:", Object.keys(components))

ReferenceError: process is not defined

Cause: Node.js globals in browser code

Solution: Add to Vite config:

// vite.config.js
export default defineConfig({
  define: {
    global: 'globalThis',
    'process.env': {}
  }
})

Module "live_vue" has been externalized

Cause: SSR configuration issue

Solution: Check Vite SSR config:

// vite.config.js
export default defineConfig({
  ssr: {
    noExternal: ['live_vue']
  }
})

Getting Help

Before Asking for Help

  1. Check browser console for errors
  2. Verify all configuration steps (see Configuration)
  3. Test with minimal reproduction case
  4. Check if issue exists in example project

Where to Get Help

  1. GitHub Issues: For bugs and feature requests
  2. GitHub Discussions: For questions and community help
  3. Elixir Forum: For general Phoenix/Elixir questions
  4. Vue.js Discord: For Vue-specific questions

Creating Bug Reports

Include:

  1. LiveVue version
  2. Phoenix/LiveView versions
  3. Node.js version
  4. Minimal reproduction case
  5. Error messages and stack traces
  6. Browser and OS information

Next Steps