Pusher constructor issue in production build with Vite, Laravel Echo, and Pusher-js

I’m working on a Laravel project that uses Vue 3 along with Vite, Laravel Echo, and Pusher-js. Everything functions correctly during development when I run npm run dev. However, after I build for production using npm run build, I encounter this error in the browser console:

Uncaught (in promise) TypeError: window.Pusher is not a constructor

My Setup

bootstrap.js:

if (typeof window !== 'undefined') {
    window.axios = axios;
    window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
}

import './echo.js';

echo.js:

import Pusher from 'pusher-js';

if (typeof window !== 'undefined') {
    console.log('Pusher', Pusher);
    window.Pusher = Pusher;

    window.Echo = new Echo({
        broadcaster: 'reverb',
        key: import.meta.env.VITE_REVERB_APP_KEY,
        wsHost: import.meta.env.VITE_REVERB_HOST,
        wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
        wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
        forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
        enabledTransports: ['ws', 'wss'],
    });
}

In development mode, everything works well. But when I build for production, the Pusher object becomes a plain object instead of a constructor class. When I log it in the console, it shows:

// outputs: Object { … } (not a constructor)

What I’ve Attempted

  • Enclosing everything within if (typeof window !== 'undefined').
  • Modifying the import to import('pusher-js').then(...).
  • Trying to utilize module.default from the dynamic import.

This issue persists only in the production build.

Utilizing Vue 3 (Composition API)

vite’s treeshakin might be messin up ur pusher import. try addin pusher-js to the optimizeDeps.include array in ur vite config or switch to import * as Pusher from 'pusher-js' instead of deffault import. that fixed it for me!

This happens because Vite bundles modules differently in production vs development. The pusher-js exports get mangled during build.

What fixed it for me was checking the module structure after import and handling both cases. Try this in your echo.js:

import PusherImport from 'pusher-js';

if (typeof window !== 'undefined') {
    // Handle both default export and named export cases
    const Pusher = PusherImport.default || PusherImport;
    window.Pusher = Pusher;
    
    window.Echo = new Echo({
        // your config here
    });
}

This covers how different bundlers might export the module. I got the exact same error and this fixed it without touching Vite config.

I encountered the same issue before. It stems from Vite’s handling of module imports during production builds. To resolve this, I recommend adjusting your vite.config.js. Specifically, include the following configuration to ensure Pusher is treated correctly:

build: {
  rollupOptions: {
    output: {
      globals: {
        'pusher-js': 'Pusher'
      }
    }
  }
}

Additionally, modify your import statement to use named imports like this:

import { default as Pusher } from 'pusher-js';

These changes should help the application recognize Pusher as a constructor in the production environment.