twilio-client package isn't working with next.js
Hi, I'm trying to build an app that involves app to app calling using the Twilio API. My project is built using Next.js, and the twilio-client
package isn't running properly.
Whenever I import the package, I get one of two errors:
TypeError: Cannot redefine property: instance
or
ReferenceError: window is not defined
To reproduce this issue,
- Create a new Next.js application using
npx create-next-app
- Install twilio-client using
npm install twilio-client --save
- Create a page and import
twilio-client
, using either the CommonJS or ES6 syntax. - Visit the page.
Does anyone have any experience with this? Can somebody help me out?
Best Answer
-
I was able to get that walkie-talkie tutorial working in next.js with the following component:
import { useEffect,useState } from 'react';
export default function VoiceRoom(){
const [device, setDevice] = useState(null)
const [identity, setIdentity] = useState("")
const [status, setStatus] = useState(null)
const [ready, setReady] = useState(false)const setup = async (event) => { event.preventDefault(); try { const response = await fetch(`https://YOUR-WALKIE-TALKIE-URL-dev.twil.io/token?identity=${identity}`) const data = await response.json(); device.setup(data.accessToken); device.audio.incoming(false); device.audio.incoming(false); device.audio.outgoing(false); device.audio.disconnect(false); setDevice(device) } catch (err) { console.log(err) } } const connect = () => { const recipient = identity === 'friend1' ? 'friend2' : 'friend1'; device.connect({recipient}) } const disconnect = () => { device.disconnectAll(); } useEffect(()=>{ async function createDevice(){ const Device = (await import('twilio-client')).Device const device = new Device(); device.on('incoming', connection => { //Whatever logic you need connection.accept() setStatus(connection.status()) }); device.on('ready', () => { setStatus("device ready"); setReady(true); }) device.on('connect', connection => { setStatus(connection.status()) }) device.on('disconnect', connection => { setStatus(connection.status()) }) setDevice(device); } createDevice() }, []) return( <div> <p>Hello</p> { ready ? <button onMouseDown={connect} onMouseUp={disconnect} >Press to Talk</button> : <div> <p>Enter your name to begin.</p> <form onSubmit={(e) => setup(e)}> <input value={identity} onChange={(e) => setIdentity(e.target.value)} type="text" placeholder="What's your name?"></input> <input type="submit" value="Begin Session"></input> </form> </div> } <p>{status}</p> </div> )
}
I'm not super well-versed with hooks (yet), so apologies if it's not the most beautiful Next app
(I'm not totally sure when I should call
setDevice
to update the device in state, but this is the best I could do in the time I have.)In the code snippet above, it looked like
createDevice()
was called outside theuseEffect
hook. Also, I used the useState hook to keep track of the device object within the component.
Answers
-
Hi Hari.
The window being undefined made me think it's an issue with the code executing on the server side, rather than client-side only.
There seems to be a variety of workarounds to this, and I was able to load a page without errors using this option:
if (typeof window !== 'undefined') { const Device = require('twilio-client') }
and this option:
import dynamic from 'next/dynamic'; const Device = dynamic(import('twilio-client'), { ssr: false });
Hopefully that helps. If not, just post here and we can try something else!
-
Hi, thank you for the quick response! Both of your solutions are allowing me to load the page, but I can't seem to initialize the
device
object properly.I've been following this tutorial, https://twilio.com/blog/build-a-browser-based-walkie-talkie-react-twilio-programmable-voice-functions, but using Next.js instead of create-react-app, and using functional components instead of class components.
After importing twilio-client, I tried initializing it inside the useEffect hook, like so:
import { useEffect } from 'react'; import dynamic from 'next/dynamic'; const Device = dynamic(import('twilio-client'), { ssr: false }); export default function VoiceRoom(){ //useEffect doesn't run on the server-side useEffect(()=>{ const device = new Device(); }, []) return( <div> <p>Hello</p> </div> ) }
The webpage shows the error
TypeError: Device is not a constructor
console.log(typeof(Device))
shows that it's apparently an object. Am I doing something wrong? -
Hm, it looks like I should have put this in the examples above:
const { Device } = dynamic(import('twilio-client'), { ssr: false });
to pull out just the Device property from the twilio-client package using ES6 destructuring.
Hopefully that works!
-
Any solutions available for this issue ?
I tries @bdelvalle suggestions, but no luck.
Any other suggestions or workaround ?
Thanks in advance
-
I haven't had time to fully finish and test out what I was working on, but for now the following code doesn't produce issues.
import { useEffect } from 'react'; export default function VoiceRoom(){ //useEffect doesn't run on the server-side useEffect(()=>{ //for await to work inside useEffect, wrap it in an async function async function createDevice(){ const Device = (await import('twilio-client')).Device const device = new Device(); //For some reason returning the device and then using it doesn't work //So keep all the "device.on()" stuff inside the async function device.on('incoming', connection => { //Whatever logic you need }); }, []) createDevice() return( <div> <p>Hello</p> </div> ) }
Note that I haven't been able to test it out yet, but I don't get any errors when visiting the webpage.
-
@Hari thanks for the workaround, this seems working, although there is some other issue which is not related to this, I guess.
-
Thank you so much for your help!
Categories
- 83 All Categories
- 19 SIGNAL 2021
- 376 Product Discussions
- 7 Community - Announcements
- 2 Changelog
- 4 Forum UI Updates
- 8 Welcome Guide
- 6 Community - Events
- 2 Twilio Relay Developer Conference 2021 Mega Thread
- 1 External Community Events
- 25 Inspiration
- 17 Community - Other Discussions
- 1 Community- Twilio Startups