Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document is not defined for server side rendering SSR at createTag #2739

Closed
joshunger opened this issue Mar 9, 2022 · 14 comments · Fixed by #3096 · May be fixed by #3129
Closed

document is not defined for server side rendering SSR at createTag #2739

joshunger opened this issue Mar 9, 2022 · 14 comments · Fixed by #3096 · May be fixed by #3129

Comments

@joshunger
Copy link

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.

@sebinievas
Copy link

@bodymovin any response? Thanks!

@joshunger
Copy link
Author

joshunger commented Jul 26, 2022

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>;
}

@horrylala
Copy link

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?

@aas395
Copy link

aas395 commented Apr 19, 2023

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

@djrcawley
Copy link

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.

@HyatMyat4
Copy link

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

@ChaseObserves
Copy link

@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.

@nadeemc
Copy link

nadeemc commented Jan 15, 2024

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},
);

@juan-alencar
Copy link

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

@makowey
Copy link

makowey commented Feb 23, 2024

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}

@jangir-ritik
Copy link

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

@hewelt
Copy link

hewelt commented Mar 18, 2024

@RonaldoAlencar
Copy link

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

@neelp03
Copy link

neelp03 commented Jun 2, 2024

Hello, if you are using lottie-web in next.js then you can dynamically load it inside useEffect() and the error will go away

'use client';

import React, { useEffect, useRef } from 'react';
import { signatureData } from '../constants/index';

const Signature = () => {
  const animationContainerRef = useRef<HTMLDivElement>(null);
  const titleTextRef = useRef<HTMLDivElement>(null);
  const signatureContainerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const loadLottie = async () => {
      if (!animationContainerRef.current || !titleTextRef.current || !signatureContainerRef.current) return;
      
      const lottie = await import('lottie-web');
      const animation = lottie.default.loadAnimation({
        container: animationContainerRef.current,
        renderer: 'svg',
        loop: false,
        autoplay: true,
        animationData: signatureData,
      });

      const titleTextElement = titleTextRef.current as HTMLElement;
      const signatureContainerElement = signatureContainerRef.current as HTMLElement;
      const navElement = document.querySelector('#navbar') as HTMLElement;
      // ......
      return () => {
        animation.destroy();
      };
    };

    loadLottie();
  }, []);

  return (
    <div className="..." ref={signatureContainerRef}>
      <div id="animation" ref={animationContainerRef}></div>
      <div className="..." ref={titleTextRef}>xyz</div>
    </div>
  );
};

export default Signature;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet