Dynamic Imports (`arcway/dynamic`)
arcway/dynamic is a first-class helper for component-level lazy loading. It wraps React.lazy with a local Suspense boundary and adds an SSR escape hatch for components that can't or shouldn't render o
arcway/dynamic is a first-class helper for component-level lazy loading. It wraps React.lazy with a local Suspense boundary and adds an SSR escape hatch for components that can't or shouldn't render on the server.
Import
import dynamic from 'arcway/dynamic';Signature
dynamic(loader, opts?) → React.Component| Parameter | Type | Description |
|---|---|---|
loader | () => Promise<{ default: Component }> | Dynamic import that resolves to a React component |
opts.ssr | boolean (default: true) | Whether to render the component during SSR |
opts.loading | React.Component (optional) | Shown as the Suspense fallback while the chunk loads |
Returns a React component. You use it exactly like any other component in JSX.
Basic Usage
import dynamic from 'arcway/dynamic';
const HeavyChart = dynamic(() => import('./HeavyChart'), {
loading: () => <p>Loading chart...</p>,
});
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<HeavyChart data={...} />
</div>
);
}The HeavyChart chunk is excluded from the initial page load. It is fetched on first render, and the loading component is shown in the meantime.
Disabling SSR (ssr: false)
Use ssr: false for components that depend on browser APIs (canvas, WebGL, third-party editors) or that are too expensive to hydrate on the server.
const CodeEditor = dynamic(() => import('./CodeEditor'), {
ssr: false,
loading: () => <div className="editor-skeleton" />,
});Server behaviour — the loader is never called. The loading component (or null if none) is rendered instead. The chunk does not appear in the SSR payload.
Client behaviour — React.lazy + a local Suspense boundary. The chunk is fetched on first mount; the loading fallback is shown while it loads.
Default SSR behaviour (ssr: true)
When ssr is true (the default), the component uses React.lazy under streaming SSR (renderToPipeableStream). The Suspense fallback is streamed first; the resolved chunk streams in when the loader promise settles. This works without modification — no changes needed to your page or layout components.
// Both server and client load this chunk.
// Works with streaming SSR out of the box.
const MarkdownPreview = dynamic(() => import('./MarkdownPreview'));Error Handling
Loader errors bubble as React render errors. Wrap the component in an error boundary to handle them gracefully:
import { ErrorBoundary } from 'react-error-boundary';
<ErrorBoundary fallback={<p>Failed to load editor.</p>}>
<CodeEditor value={code} onChange={setCode} />
</ErrorBoundary>Summary
ssr | Server | Client |
|---|---|---|
true (default) | React.lazy + Suspense (streaming-friendly) | React.lazy + Suspense |
false | Renders loading or null — loader never called | React.lazy + Suspense |
Coming in v2
arcway/dynamic v1 does not emit <link rel="modulepreload"> for dynamically-imported chunks during SSR. A preload manifest that injects these hints is tracked as a follow-up task and will ship as a minor update once the waterfall cost is measured.