lottie-web icon indicating copy to clipboard operation
lottie-web copied to clipboard

document is not defined for server side rendering SSR at createTag

Open joshunger opened this issue 2 years ago • 13 comments

I'm seeing document is not defined for server side rendering (SSR).

function createTag(type) {
  // return {appendChild:function(){},setAttribute:function(){},style:{}}
  return document.createElement(type);
}

export default createTag;

https://github.com/airbnb/lottie-web/blob/master/player/js/utils/helpers/html_elements.js#L3

@bodymovin would it be possible to check for document so it doesn't break SSR when this JavaScript is included in the SSR bundle?

Thanks.

joshunger avatar Mar 09 '22 15:03 joshunger

@bodymovin any response? Thanks!

sebinievas avatar Jul 26 '22 15:07 sebinievas

I hope this helps others. This is what we ended up doing to workaround the issue -

const ChevronDownBouncing = lazy(() => import('./ChevronDownBouncing'));

Then -

<NoSsr>
  <Suspense fallback={<img alt="" src={chevronDownBouncing} />}>
    <ChevronDownBouncing />
  </Suspense>
</NoSsr>

Then -

import { useEffect, useRef } from 'react';
import lottieWeb from 'lottie-web';
import ChevronDownBouncingIcon from './ChevronDownBouncingIcon.json';
import * as styles from './ChevronDownBouncing.module.scss';

export default function ChevronDownBouncing() {
  const ref = useRef();

  useEffect(() => {
    lottieWeb.loadAnimation({
      container: ref.current,
      renderer: 'svg',
      loop: true,
      autoplay: true,
      animationData: ChevronDownBouncingIcon
    });
  }, []);

  return <div ref={ref} className={styles.chevron} />;
}

And chevronDownBouncing is the last frame. We saved the last frame to an svg by doing something this and grabbing the svg content in Google Chrome.

function SaveLastFrame() {
  const ref = useRef();
  useEffect(() => {
    const animation = lottie.loadAnimation({
      container: ref.current, // the dom element that will contain the animation
      renderer: 'svg',
      loop: true,
      autoplay: true,
      animationData: json // the path to the animation json
    });

    // open json and find op value
    animation.goToAndStop(120, true);
  }, []);

  return <div style={{ width: '100px' }} ref={ref}></div>;
}

joshunger avatar Jul 26 '22 15:07 joshunger

Same error,have you ever solved it ? I'm using loadable-component with loadable(() => import(a.jsx)). Got the same error.

Without dynamic import , it goes all right. So, what's wrong with dynamic import?

horrylala avatar Nov 12 '22 14:11 horrylala

This happened to me yesterday on Shopify/Oxygen and @joshunger's solution fixed it for me.

aas395 avatar Apr 19 '23 13:04 aas395

Maybe this will help someone looking for this similar issue. I accidentally upgraded to node version to the newest version 21.5.0 which caused this error to appear. Downgrading to version 20.10.0 (LTS) and reinstalling all the packages resolved this issue for me.

djrcawley avatar Jan 03 '24 17:01 djrcawley

Thanks very very much @djrcawley your comment is very helpful 100% work , how I fix: after reinstalling 20.10.0 (LTS) , I delete node_modules , yarn.lock , package-lock.json , .next and after reinstalling these, need to close the vs code and open again it will work

HyatMyat4 avatar Jan 09 '24 06:01 HyatMyat4

@djrcawley I want you to know that I've been suffering with this issue in my daily job for months now, I've been in this thread multiple times trying different things to resolve it, but your comment is new as of last week and your fix totally worked for me. THANK YOU. The nightmare of refreshing my NextJS app 3-4 times until the 'document is not defined' error stopped popping up is now just a bad memory.

ChaseObserves avatar Jan 09 '24 20:01 ChaseObserves

Hi!

Another solution specific to Next.js is to wrap the player component using dynamic to prevent SSR. This removes the issue without needing to downgrade node:

'use client';

import dynamic from "next/dynamic";

export const MyComponentWithLottie = () => {
  return (<>
    {/* ... other components ... */}

    <PlayerWithNoSSR
      autoplay
      keepLastFrame
      loop
      src={'https://static3.lottiefiles.com/lotties/01_ramen_character.json'}
    />

    {/* ... other components ... */}
  </>);
};

const PlayerWithNoSSR = dynamic(
  () => import('@lottiefiles/react-lottie-player').then(module => module.Player),
  {ssr: false},
);

nadeemc avatar Jan 15 '24 08:01 nadeemc

Hi!

Another solution specific to Next.js is to wrap the player component using dynamic to prevent SSR. This removes the issue without needing to downgrade node:

'use client';

import dynamic from "next/dynamic";

export const MyComponentWithLottie = () => {
  return (<>
    {/* ... other components ... */}

    <PlayerWithNoSSR
      autoplay
      keepLastFrame
      loop
      src={'https://static3.lottiefiles.com/lotties/01_ramen_character.json'}
    />

    {/* ... other components ... */}
  </>);
};

const PlayerWithNoSSR = dynamic(
  () => import('@lottiefiles/react-lottie-player').then(module => module.Player),
  {ssr: false},
);

i love you

juan-alencar avatar Feb 21 '24 02:02 juan-alencar

Dynamic imports Svelte/SvelteKit:

<script lang="ts">
	const imports = {
		lottieAnimation: () => import('./LottieAnimation.svelte')
	};

	export let options = {
		path: '94729-not-found',
		loop: true
	};
</script>

{#await imports['lottieAnimation']() then module}
	<svelte:component this={module.default} {options} />
{/await}

makowey avatar Feb 23 '24 10:02 makowey

Maybe this will help someone looking for this similar issue. I accidentally upgraded to node version to the newest version 21.5.0 which caused this error to appear. Downgrading to version 20.10.0 (LTS) and reinstalling all the packages resolved this issue for me.

This saved me... I wonder what the underlying issue is

jangir-ritik avatar Feb 27 '24 08:02 jangir-ritik

Hi!

Another solution specific to Next.js is to wrap the player component using dynamic to prevent SSR. This removes the issue without needing to downgrade node:

'use client';

import dynamic from "next/dynamic";

export const MyComponentWithLottie = () => {
  return (<>
    {/* ... other components ... */}

    <PlayerWithNoSSR
      autoplay
      keepLastFrame
      loop
      src={'https://static3.lottiefiles.com/lotties/01_ramen_character.json'}
    />

    {/* ... other components ... */}
  </>);
};

const PlayerWithNoSSR = dynamic(
  () => import('@lottiefiles/react-lottie-player').then(module => module.Player),
  {ssr: false},
);

thank youu

RonaldoAlencar avatar Mar 20 '24 22:03 RonaldoAlencar