Florian
Florian

Reputation: 93

Dynamic import with GatsbyJS

The problem is that the website-specific components are quite large and therefore bloat up the code of the individual websites which don't use those specific components. This results for example in a bad lighthouse score (unused code) and bad user experience (longer loading times).

Here is a strongly simplified example component that displays a website specific svg (loaded via gatsby-plugin-react-svg):

import React from "react";

import Site1 from "../../images/site1.svg";
import Site2 from "../../images/site2.svg";
import Default from "../../images/default.svg";

const Image = () => {
  let staticImage = <Default />;

  switch (process.env.GATSBY_SITE) {
    case "site1":
      staticImage = <Site1 />;
      break;
    case "site2":
      staticImage = <Site2 />;
      break;
    default:
  }

  return (
    <>{staticImage}</>
  );
};

export default Image;

I guess/understand this won't work because GatsbyJS/React/Webpack (?) simply does not know what happens in this component and when to show which image.

I tried to use loadable components to address this issue but had no success. This is the example code from above but with loadable components:

import React from "react";

import loadable from "@loadable/component";

const DynamicImage = loadable(async () => {
  switch (process.env.GATSBY_SITE) {
    case "site1":
      return import("../../images/site1.svg");
    case "site2":
      return import("../../images/site2.svg");
    default:
      return import("../../images/default.svg");
  }
});

const Image = () => {
  return <DynamicImage />;
};

export default Image;

With this code, all three images are still loaded although only one is shown. I would expect that only the used/required image (or component in other cases) is loaded.

Upvotes: 2

Views: 266

Answers (2)

1997daly
1997daly

Reputation: 31

this should work

import React, { lazy, Suspense } from "react";

const Site1 = lazy(() => import("../../images/site1.svg"));
const Site2 = lazy(() => import("../../images/site2.svg"));
const Default = lazy(() => import("../../images/default.svg"));

const Image = () => {
  let StaticImage = Default;

  switch (process.env.GATSBY_SITE) {
    case "site1":
      StaticImage = Site1;
      break;
    case "site2":
      StaticImage = Site2;
      break;
    default:
  }

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <StaticImage />
    </Suspense>
  );
};

export default Image;

Upvotes: 0

johannchopin
johannchopin

Reputation: 14844

Did you try with the React.lazy function?

const Github = React.lazy(async () => ({
  default: (await import("./github.svg")).ReactComponent,
}));
const Google = React.lazy(async () => ({
  default: (await import("./google.svg")).ReactComponent,
}));

const DynamicImage = () => {
    <React.Suspense fallback={<div>Loading...</div>}>
      {if(CONDITION) && <Github />}
      {if(OTHER_CONDITION) && <Google />}
    </React.Suspense>
};

See an example here:

Edit React lazy svg loading (forked)

Upvotes: 1

Related Questions