Dynamic imports #2936
Replies: 10 comments 7 replies
-
Sometimes its perf reason (loading when its needed), sometimes its just a must. |
Beta Was this translation helpful? Give feedback.
-
You can currently do Client Only dynamic component imports with the following pattern: import { Suspense, lazy, useEffect, useState } from "react";
import type { ReactNode } from "react";
let LazyImported = lazy(() => import("./lazy-comp"));
export function ClientOnly({ children }: { children: ReactNode }) {
let [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return mounted ? <>{children}</> : null;
}
export default RouteComponent() {
return (
<h1>YAY!</h1>
<ClientOnly>
<Suspense fallback="">
<LazyImported />
</Suspense>
</ClientOnly>
);
} |
Beta Was this translation helpful? Give feedback.
-
Thanks @jacob-ebey , it work indeed, but its a hacky way. I assume it will be gone when React 18 and SSR suspense is shipped. What is worth to mention IMO is
Regarding initial issue by Ryan, my opinion is to use native React way (lazy and suspense) without re-exporting it, but ensure internal build system is configured well to support it |
Beta Was this translation helpful? Give feedback.
-
Dynamic imports seem to work just fine with "module": "es6" in tsconfig even though TS complains about the availability. Older browsers probably break entirely but that's to be expected with ES6. Changing module to something else is bound to break newish browsers, like Safari from last "good' MacOS version, so that isn't really an option? Would be nice if there was some sort of official guidance on the subject. I was able to implement a lazy loading admin overlay, but I'm a bit afraid for it's longevity. |
Beta Was this translation helpful? Give feedback.
-
tsconfig isn't really used and there's nothing you configure there that will break how remix complies your code currently. Don't worry about changing it, especially when it's to include a config for language settings you are trying to use such as dynamic import. Anything you can do today such as putting suspense behind a client only won't break in the future as react is only adding the ability for the server to use this, not removing anything. Don't worry about "longevity" in terms of things breaking around the pattern I've outlined above. And I wouldn't call it hacky, it's literally how you delay execution for client only using state in React. Nothing strange about it. As for a "dynamic" component, React.lazy will essentially become this when 18 drops, but I'm skeptical about implementing it today as every version of it will be a combo of the compiler turning async imports into sync imports for the server, and "hacks" for the client around delaying hydration until these chunks have loaded to avoid hydration issues. This means we'd have to expose some sort of "waitTillDynamicHasLoaded()" you have to call in your entry.client, or hide this away very hacky under the hood. I don't think this is worth it currently. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the clarification! I can get rid of |
Beta Was this translation helpful? Give feedback.
-
Looks like using React lazy according to what Ryan explained above is working in React 18 with server-side suspense. |
Beta Was this translation helpful? Give feedback.
-
@ryanflorence Dynamic Imports appear not to work. Here's my investigation. Remix 1.9.3 This commit: dwjohnston/remix-app-1-dynamic-imports@cbd1079 Is a [email protected] app scaffolded with create-remix. We try to do a dynamic import like this: export const loader = async (loaderInput: LoaderArgs) => {
const pathname = loaderInput.params["*"];
const result = await import(`../app/json/${pathname}.json`);
return result;
}
export default function () {
return <div>Whatever</div>
} And get a server error:
I can add that import assertion: dwjohnston/remix-app-1-dynamic-imports@7490068 But now we get:
I investigated how we configure babel plugins, but I get to this issue: #2278 telling us that Remix uses esbuild and not babel, and it's not possible to configure esbuild. Remix 2.3.0 Same problem with Remix@2. Without import type assertion: dwjohnston/remix-2-dynamic-imports@d99c5ab With import type assertion: dwjohnston/remix-2-dynamic-imports@e7d7674 |
Beta Was this translation helpful? Give feedback.
-
Yes. Was this never implemented? Kind of a big deal if you want to create a page builder from a CMS. |
Beta Was this translation helpful? Give feedback.
-
This works like so for me (on Remix v^2.9.1): // Import for styles:
import 'react-quill/dist/quill.snow.css';
// In my component, before the return for the rendering
const ReactQuill = useMemo(
() => React.lazy(() => import('react-quill')),
[]
);
// In the return itself:
<ReactQuill
style={{ width: 612, height: 792 }}
value={
html
}
onChange={(value) => {
// This is one of my props
onChangeDocument(value);
}}
/> |
Beta Was this translation helpful? Give feedback.
-
Do they work?
Maybe I don't want Firebase imported until they actually click the button.
Do we want our own React.lazy that code splits and server renders?
Beta Was this translation helpful? Give feedback.
All reactions