or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-integration.mddynamic-loading.mdindex.mdmulti-resource-loading.mdserver-side-rendering.md

server-side-rendering.mddocs/

0

# Server-Side Rendering

1

2

Comprehensive server-side rendering (SSR) support for React Loadable, enabling seamless hydration between server-rendered content and client-side lazy loading. This includes module tracking, preloading utilities, and bundle mapping.

3

4

## Capabilities

5

6

### Module Capture

7

8

Track which loadable components are rendered during server-side rendering to ensure the correct bundles are sent to the client.

9

10

```javascript { .api }

11

/**

12

* Component for capturing rendered modules during SSR

13

*/

14

class Capture extends React.Component {

15

static propTypes: {

16

/** Function called for each rendered module */

17

report: (moduleName: string) => void;

18

/** Child components to render */

19

children: React.ReactNode;

20

};

21

22

static childContextTypes: {

23

loadable: {

24

report: (moduleName: string) => void;

25

};

26

};

27

}

28

```

29

30

**Usage Examples:**

31

32

```javascript

33

import React from 'react';

34

import ReactDOMServer from 'react-dom/server';

35

import Loadable from 'react-loadable';

36

import App from './App';

37

38

// Server-side rendering with module capture

39

app.get('/', (req, res) => {

40

const modules = [];

41

42

const html = ReactDOMServer.renderToString(

43

<Loadable.Capture report={moduleName => modules.push(moduleName)}>

44

<App />

45

</Loadable.Capture>

46

);

47

48

console.log('Rendered modules:', modules);

49

50

// Use modules to determine which bundles to include

51

const bundles = getBundles(stats, modules);

52

53

res.send(createHTML(html, bundles));

54

});

55

56

function createHTML(content, bundles) {

57

return `

58

<!DOCTYPE html>

59

<html>

60

<head><title>My App</title></head>

61

<body>

62

<div id="app">${content}</div>

63

${bundles.map(bundle =>

64

`<script src="${bundle.publicPath}"></script>`

65

).join('\n')}

66

<script src="/main.js"></script>

67

</body>

68

</html>

69

`;

70

}

71

```

72

73

### Server Preloading

74

75

Preload all loadable components on the server before rendering to ensure all components are available during SSR.

76

77

```javascript { .api }

78

/**

79

* Preloads all registered loadable components

80

* @returns Promise that resolves when all components are loaded

81

*/

82

function preloadAll(): Promise<void>;

83

```

84

85

**Usage Examples:**

86

87

```javascript

88

import express from 'express';

89

import Loadable from 'react-loadable';

90

import { renderApp } from './render';

91

92

const app = express();

93

94

// Preload all components before starting the server

95

Loadable.preloadAll().then(() => {

96

app.get('/', renderApp);

97

98

app.listen(3000, () => {

99

console.log('Server started on http://localhost:3000');

100

});

101

}).catch(err => {

102

console.error('Failed to preload components:', err);

103

process.exit(1);

104

});

105

106

// Alternative: preload on each request (not recommended for production)

107

app.get('/slow', async (req, res) => {

108

try {

109

await Loadable.preloadAll();

110

const html = renderToString(<App />);

111

res.send(html);

112

} catch (error) {

113

res.status(500).send('Server error');

114

}

115

});

116

```

117

118

### Client Hydration

119

120

Preload components that were server-rendered before hydrating the client application.

121

122

```javascript { .api }

123

/**

124

* Preloads components that are ready (webpack modules already available)

125

* Typically used on the client before hydration

126

* @returns Promise that resolves when ready components are loaded

127

*/

128

function preloadReady(): Promise<void>;

129

```

130

131

**Usage Examples:**

132

133

```javascript

134

// Client entry point

135

import React from 'react';

136

import ReactDOM from 'react-dom';

137

import Loadable from 'react-loadable';

138

import App from './App';

139

140

// Wait for loadable components before hydrating

141

Loadable.preloadReady().then(() => {

142

ReactDOM.hydrate(<App />, document.getElementById('app'));

143

});

144

145

// Alternative with error handling

146

Loadable.preloadReady()

147

.then(() => {

148

ReactDOM.hydrate(<App />, document.getElementById('app'));

149

})

150

.catch(err => {

151

console.error('Failed to preload components:', err);

152

// Fallback to client-side rendering

153

ReactDOM.render(<App />, document.getElementById('app'));

154

});

155

```

156

157

## Module and Bundle Mapping

158

159

### Module Declaration

160

161

Loadable components need to declare which modules they load for SSR support. This is typically automated by the Babel plugin.

162

163

```javascript { .api }

164

/**

165

* Manual module declaration (usually automated by Babel plugin)

166

*/

167

interface LoadableSSROptions {

168

/** Function returning webpack module IDs */

169

webpack?: () => number[];

170

/** Array of module paths */

171

modules?: string[];

172

}

173

```

174

175

**Usage Examples:**

176

177

```javascript

178

// Manual configuration (not recommended - use Babel plugin instead)

179

const LoadableComponent = Loadable({

180

loader: () => import('./MyComponent'),

181

loading: Loading,

182

webpack: () => [require.resolveWeak('./MyComponent')],

183

modules: ['./MyComponent'],

184

});

185

186

// With Babel plugin, this is automatically added:

187

const LoadableComponent = Loadable({

188

loader: () => import('./MyComponent'),

189

loading: Loading,

190

// webpack and modules options added automatically

191

});

192

```

193

194

### Bundle Information

195

196

Structure of bundle objects returned by `getBundles` function.

197

198

```javascript { .api }

199

/**

200

* Bundle information for including scripts in HTML

201

*/

202

interface Bundle {

203

/** Module ID or name */

204

id: number | string;

205

/** Module name from webpack */

206

name: string;

207

/** Filename of the bundle */

208

file: string;

209

/** Full public path to the bundle */

210

publicPath: string;

211

}

212

```

213

214

## Complete SSR Setup

215

216

### Server Setup

217

218

```javascript

219

import express from 'express';

220

import React from 'react';

221

import ReactDOMServer from 'react-dom/server';

222

import Loadable from 'react-loadable';

223

import { getBundles } from 'react-loadable/webpack';

224

import stats from './dist/react-loadable.json';

225

import App from './App';

226

227

const server = express();

228

229

// Serve static files

230

server.use('/dist', express.static('./dist'));

231

232

// SSR route

233

server.get('*', (req, res) => {

234

const modules = [];

235

236

const html = ReactDOMServer.renderToString(

237

<Loadable.Capture report={moduleName => modules.push(moduleName)}>

238

<App url={req.url} />

239

</Loadable.Capture>

240

);

241

242

const bundles = getBundles(stats, modules);

243

244

res.send(`

245

<!DOCTYPE html>

246

<html>

247

<head>

248

<title>My App</title>

249

<meta charset="utf-8">

250

</head>

251

<body>

252

<div id="app">${html}</div>

253

<script src="/dist/manifest.js"></script>

254

${bundles.map(bundle =>

255

`<script src="/dist/${bundle.file}"></script>`

256

).join('\n')}

257

<script src="/dist/main.js"></script>

258

</body>

259

</html>

260

`);

261

});

262

263

// Start server after preloading

264

Loadable.preloadAll().then(() => {

265

server.listen(3000, () => {

266

console.log('Running on http://localhost:3000/');

267

});

268

});

269

```

270

271

### Client Setup

272

273

```javascript

274

// Client entry point (src/index.js)

275

import React from 'react';

276

import ReactDOM from 'react-dom';

277

import Loadable from 'react-loadable';

278

import App from './App';

279

280

// Preload components that were server-rendered

281

Loadable.preloadReady().then(() => {

282

ReactDOM.hydrate(<App />, document.getElementById('app'));

283

});

284

```

285

286

### Development vs Production

287

288

```javascript

289

// Development setup

290

if (process.env.NODE_ENV === 'development') {

291

// Skip preloading in development for faster startup

292

const app = express();

293

app.get('*', renderRoute);

294

app.listen(3000);

295

} else {

296

// Production setup with preloading

297

Loadable.preloadAll().then(() => {

298

const app = express();

299

app.get('*', renderRoute);

300

app.listen(3000);

301

});

302

}

303

```

304

305

## SSR Best Practices

306

307

### Component Definition

308

309

```javascript

310

// Good: Define loadable components at module level

311

const LoadableComponent = Loadable({

312

loader: () => import('./Component'),

313

loading: Loading,

314

});

315

316

export default function MyPage() {

317

return <LoadableComponent />;

318

}

319

320

// Bad: Define loadable components inside render methods

321

export default function MyPage() {

322

const LoadableComponent = Loadable({ // This won't work with preloadAll

323

loader: () => import('./Component'),

324

loading: Loading,

325

});

326

327

return <LoadableComponent />;

328

}

329

```

330

331

### Error Handling

332

333

```javascript

334

// Server error handling

335

Loadable.preloadAll()

336

.then(() => {

337

startServer();

338

})

339

.catch(err => {

340

console.error('Failed to preload components:', err);

341

process.exit(1);

342

});

343

344

// Client error handling

345

Loadable.preloadReady()

346

.then(() => {

347

ReactDOM.hydrate(<App />, document.getElementById('app'));

348

})

349

.catch(err => {

350

console.warn('Preload failed, falling back to render:', err);

351

ReactDOM.render(<App />, document.getElementById('app'));

352

});

353

```

354

355

### Multiple React Loadable Instances

356

357

Ensure only one instance of react-loadable is used in your application to avoid issues with `preloadAll()`.

358

359

```javascript

360

// package.json - ensure single version

361

{

362

"dependencies": {

363

"react-loadable": "5.5.0"

364

},

365

"resolutions": {

366

"react-loadable": "5.5.0"

367

}

368

}

369

```