Gamote / lottie-react

A lightweight React library for rendering complex After Effects animations in real time using Lottie.
https://lottiereact.com
Other
794 stars 58 forks source link

ReferenceError: document is not defined at createTag... #101

Open Beruguru opened 1 year ago

Beruguru commented 1 year ago

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:

case1.

case2.

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.

xgg94 commented 1 year ago

Got the same error

dharmatriyasa commented 1 year ago

Got the same error, but everything works fine

bytemtek commented 1 year ago

Same error.

ZhariffAdam commented 1 year ago

use nvm 18.18.2 for temporary

xereda commented 11 months ago

same error with node 21

hewelt commented 11 months ago

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.

Beruguru commented 11 months ago

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.^_^

xereda commented 11 months ago

@ZhariffAdam

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

Thank you for now

AlonMiz commented 10 months ago

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

andregoncalvesdev commented 10 months ago

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

+1

Beruguru commented 10 months ago

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

AlonMiz commented 10 months ago

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/react-lottie@1.2.4
  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}
    />
  );
};
dragoshuniq commented 10 months ago

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 });
alan-nousot commented 6 months ago

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.

sxxov commented 6 months ago

@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 },
);
nixjs commented 4 months ago

Use node 18.17.0 to resolve

csori99 commented 2 months ago

When is Lottie team planning to fix it? have been months

beardsleym commented 2 months ago

I was using Node v22, using v20 sorted it out.

MartinGerritsen commented 1 month ago

Same issue here, had to downgrade node

yfrommelt commented 2 weeks ago

You can add NODE_OPTIONS="--no-experimental-global-navigator" before you dev /build script to disable the Navigator API in Node v21