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

ReferenceError: document is not defined at createTag...

Open Beruguru opened this issue 2 years ago • 24 comments
trafficstars

Hello everyone,

I had some issues with ReferenceError (with SSR). And yes I know, it could be solved by dynamic import, lazy or maybe some other ways.

But the situation is like below:

  • There is a main(index) page with Lottie (lottie-react)
  • I've even use useEffect with isMount state to render the Lottie after the mount

case1.

  • No errors and works fine in Node 18 (v.18.18.0)

case2.

  • ReferenceError: document is not defined at createTag... occurs in higher version of Node (20, 21)

So, we (I and my co-worker) decided to fix Node version to 18 and it works fine.

But we are just curious about it. Try to figure it out but all we can find is that the node version effects build in somehow.

If anyone knows what has been changed between 18 and higher, it would be nice to know of it.

Thank you so much.

Beruguru avatar Nov 01 '23 07:11 Beruguru

Got the same error

xgg94 avatar Nov 02 '23 19:11 xgg94

Got the same error, but everything works fine

dharmatriyasa avatar Nov 04 '23 14:11 dharmatriyasa

Same error.

bytemtek avatar Nov 09 '23 17:11 bytemtek

use nvm 18.18.2 for temporary

ZhariffAdam avatar Nov 16 '23 08:11 ZhariffAdam

same error with node 21

xereda avatar Dec 01 '23 14:12 xereda

Hey folks, this error happens because lottie-web, dependency of lottie-react depends on the condition of typeof navigator !== "undefined" to determine if it runs in browser or server environment:

if (typeof navigator !== "undefined") {
  // client-side code
  } else {
  // server-side code
}

This is not valid anymore though, because Node v21 introduces a new navigator API, previously present only in client-side code. So document is now reached when being run in Node. One solution would be for lottie-web to just change that condition to one that clearly distinguishes between client and server.

hewelt avatar Dec 05 '23 10:12 hewelt

Hey folks, this error happens because lottie-web, dependency of lottie-react depends on the condition of typeof navigator !== "undefined" to determine if it runs in browser or server environment:

if (typeof navigator !== "undefined") {
  // client-side code
  } else {
  // server-side code
}

This is not valid anymore though, because Node v21 introduces a new navigator API, previously present only in client-side code. So document is now reached when being run in Node. One solution would be for lottie-web to just change that condition to one that clearly distinguishes between client and server.

Thank you so much! I was so wondering why this happenend and thanks for the sharing.^_^

Beruguru avatar Dec 05 '23 11:12 Beruguru

@ZhariffAdam

Why was this issue closed? Was solved? Is there a plan for support for node 21?

Thank you for now

xereda avatar Dec 08 '23 13:12 xereda

this issue should remain open. not fixed for node >= 20

AlonMiz avatar Jan 10 '24 18:01 AlonMiz

this issue should remain open. not fixed for node >= 20

+1

andregoncalvesdev avatar Jan 10 '24 18:01 andregoncalvesdev

Oh I am sorry. I didn't know it has to be open until the fix. I will reopen it~

Beruguru avatar Jan 11 '24 00:01 Beruguru

thanks @Beruguru 🙏 i worked on a workaround with some additional benefits Lazyloading the lottie module as loading lazily the animation json

  1. less bundle from package - which is pretty large (81.9 kB MINIFIED + GZIPPED) - https://bundlephobia.com/package/[email protected]
  2. less bundle for loading the json - will be load lazily as well - as they can get quite large as well

EDIT: I had a chance to write a small article

https://medium.com/@alonmiz1234/lazy-load-lottie-animation-in-react-e58e67e2aa74

this example uses Skeleton from mantine but it can be replace with a simple loading animation you already have

LazyLottie (Optimized for SSR)

import { Skeleton } from '@mantine/core';
import { useQuery } from '@tanstack/react-query';
import { type LottieComponentProps } from 'lottie-react';
import { Suspense, lazy, useEffect, useRef, useState } from 'react';

const LazyLottieComponent = lazy(() => import('lottie-react'));

interface LottieProps<T extends Record<string, unknown>> {
  getJson: () => Promise<T>;
  id: string;
}

export function LazyLottie<T extends Record<string, unknown>>({
  getJson,
  id,
  ref,
  ...props
}: LottieProps<T> & Omit<LottieComponentProps, 'animationData'>) {
  const { data } = useQuery({
    queryKey: [id],
    queryFn: getJson,
    enabled: typeof window !== 'undefined',
  });

  if (!data) return <Skeleton height={props.height} width={props.width} />;

  return (
    <Suspense fallback={<Skeleton height={props.height} width={props.width} />}>
      <LazyLottieComponent animationData={data} {...props} />
    </Suspense>
  );
}

Usage


export const EmptyState: React.FC = () => {
  return (
    <LazyLottie
      getJson={() => import('../../../assets/lottie/empty-box.json')}
      loop
      id="empty-box"
      width={120}
      height={120}
    />
  );
};

AlonMiz avatar Jan 11 '24 05:01 AlonMiz

Next.js. Lottie-web uses the window object, which is not available during SSR. To fix this use the following code: Ref here

import dynamic from 'next/dynamic';
const Lottie = dynamic(() => import('react-lottie'), { ssr: false });

dragoshuniq avatar Jan 16 '24 09:01 dragoshuniq

Running into this issue consistently from using lottie-react in a component library that doesn't use next with nodejs 20.12.2. Lazy importing react-lottie or the component itself doesn't work either.

alan-nousot avatar May 07 '24 16:05 alan-nousot

@alan-nousot If you're importing a named export that uses lottie-react, you can try the following:

const Component = dynamic(
	async () =>
		import('library').then(({ Component }) => ({
			default: Component, // note the alias to `default`!
		})),
	{ ssr: false },
);

sxxov avatar May 20 '24 03:05 sxxov

Use node 18.17.0 to resolve

nixjs avatar Jun 28 '24 09:06 nixjs