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

build-integration.mddocs/

0

# Build Tool Integration

1

2

React Loadable provides build tool plugins to automate server-side rendering setup and optimize the development experience. This includes a Babel plugin for automatic module resolution and a Webpack plugin for generating bundle manifests.

3

4

## Capabilities

5

6

### Babel Plugin

7

8

Automatically adds `webpack` and `modules` options to Loadable components, eliminating the need for manual configuration in SSR setups.

9

10

```javascript { .api }

11

/**

12

* Babel plugin that transforms Loadable calls to include webpack and modules options

13

* Plugin name: "react-loadable/babel"

14

*/

15

```

16

17

**Configuration:**

18

19

```json

20

{

21

"plugins": ["react-loadable/babel"]

22

}

23

```

24

25

**Transform Example:**

26

27

```javascript

28

// Input

29

import Loadable from 'react-loadable';

30

31

const LoadableComponent = Loadable({

32

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

33

loading: Loading,

34

});

35

36

const LoadableMap = Loadable.Map({

37

loader: {

38

One: () => import('./One'),

39

Two: () => import('./Two'),

40

},

41

loading: Loading,

42

render: (loaded, props) => <div>{/* ... */}</div>,

43

});

44

```

45

46

```javascript

47

// Output (automatically generated)

48

import Loadable from 'react-loadable';

49

import path from 'path';

50

51

const LoadableComponent = Loadable({

52

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

53

loading: Loading,

54

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

55

modules: [path.join(__dirname, './MyComponent')],

56

});

57

58

const LoadableMap = Loadable.Map({

59

loader: {

60

One: () => import('./One'),

61

Two: () => import('./Two'),

62

},

63

loading: Loading,

64

render: (loaded, props) => <div>{/* ... */}</div>,

65

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

66

modules: [path.join(__dirname, './One'), path.join(__dirname, './Two')],

67

});

68

```

69

70

### Webpack Plugin

71

72

Generates a manifest file mapping modules to webpack bundles, enabling server-side rendering to determine which bundles to include for rendered components.

73

74

```javascript { .api }

75

/**

76

* Webpack plugin for generating loadable component manifest

77

*/

78

class ReactLoadablePlugin {

79

/**

80

* @param options - Plugin configuration

81

* @param options.filename - Path where manifest JSON should be written

82

*/

83

constructor(options: { filename: string });

84

}

85

```

86

87

**Configuration:**

88

89

```javascript

90

// webpack.config.js

91

const { ReactLoadablePlugin } = require('react-loadable/webpack');

92

93

module.exports = {

94

plugins: [

95

new ReactLoadablePlugin({

96

filename: './dist/react-loadable.json',

97

}),

98

],

99

};

100

```

101

102

**Generated Manifest Structure:**

103

104

```json

105

{

106

"./src/components/Header": [

107

{

108

"id": 0,

109

"name": "./src/components/Header",

110

"file": "0.js",

111

"publicPath": "/dist/0.js"

112

}

113

],

114

"./src/components/Footer": [

115

{

116

"id": 1,

117

"name": "./src/components/Footer",

118

"file": "1.js",

119

"publicPath": "/dist/1.js"

120

}

121

]

122

}

123

```

124

125

### Bundle Resolution

126

127

Convert module names to bundle information for including the correct script tags in server-rendered HTML.

128

129

```javascript { .api }

130

/**

131

* Converts module IDs to bundle information using webpack manifest

132

* @param stats - Webpack stats object or manifest from ReactLoadablePlugin

133

* @param modules - Array of module names reported by Loadable.Capture

134

* @returns Array of bundle objects containing file paths and metadata

135

*/

136

function getBundles(stats: WebpackStats, modules: string[]): Bundle[];

137

138

interface Bundle {

139

/** Webpack module ID */

140

id: number | string;

141

/** Module name or path */

142

name: string;

143

/** Bundle filename */

144

file: string;

145

/** Full public path to bundle */

146

publicPath: string;

147

}

148

149

interface WebpackStats {

150

[moduleName: string]: Bundle[];

151

}

152

```

153

154

**Usage Examples:**

155

156

```javascript

157

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

158

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

159

160

// Server-side rendering

161

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

162

const modules = [];

163

164

const html = ReactDOMServer.renderToString(

165

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

166

<App />

167

</Loadable.Capture>

168

);

169

170

// Convert modules to bundles

171

const bundles = getBundles(stats, modules);

172

173

// Generate script tags

174

const scripts = bundles.map(bundle =>

175

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

176

).join('\n');

177

178

res.send(`

179

<!DOCTYPE html>

180

<html>

181

<body>

182

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

183

${scripts}

184

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

185

</body>

186

</html>

187

`);

188

});

189

```

190

191

## Complete Build Setup

192

193

### Webpack Configuration

194

195

```javascript

196

// webpack.config.js

197

const path = require('path');

198

const { ReactLoadablePlugin } = require('react-loadable/webpack');

199

200

module.exports = {

201

entry: './src/index.js',

202

output: {

203

path: path.resolve(__dirname, 'dist'),

204

filename: '[name].[chunkhash].js',

205

publicPath: '/dist/',

206

},

207

plugins: [

208

// Generate manifest for server-side rendering

209

new ReactLoadablePlugin({

210

filename: path.resolve(__dirname, 'dist/react-loadable.json'),

211

}),

212

213

// Extract webpack manifest (required for proper chunk loading)

214

new webpack.optimize.CommonsChunkPlugin({

215

name: 'manifest',

216

minChunks: Infinity,

217

}),

218

],

219

optimization: {

220

splitChunks: {

221

chunks: 'all',

222

},

223

},

224

};

225

```

226

227

### Babel Configuration

228

229

```json

230

{

231

"presets": ["@babel/preset-react", "@babel/preset-env"],

232

"plugins": [

233

"react-loadable/babel",

234

"@babel/plugin-syntax-dynamic-import"

235

]

236

}

237

```

238

239

### Package.json Scripts

240

241

```json

242

{

243

"scripts": {

244

"build": "webpack --mode=production",

245

"build:dev": "webpack --mode=development",

246

"start": "node server.js",

247

"dev": "webpack-dev-server --mode=development"

248

}

249

}

250

```

251

252

## Advanced Build Configurations

253

254

### Custom Webpack Public Path

255

256

Handle dynamic public paths for CDN deployment:

257

258

```javascript

259

// webpack.config.js

260

module.exports = {

261

output: {

262

publicPath: process.env.CDN_URL || '/dist/',

263

},

264

plugins: [

265

new ReactLoadablePlugin({

266

filename: './dist/react-loadable.json',

267

}),

268

],

269

};

270

271

// Server usage

272

const bundles = getBundles(stats, modules);

273

const scripts = bundles.map(bundle => {

274

// Use bundle.publicPath which includes the configured publicPath

275

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

276

}).join('\n');

277

```

278

279

### Development vs Production

280

281

```javascript

282

// webpack.config.js

283

const isProduction = process.env.NODE_ENV === 'production';

284

285

module.exports = {

286

plugins: [

287

new ReactLoadablePlugin({

288

filename: isProduction

289

? './dist/react-loadable.json'

290

: './dev/react-loadable.json',

291

}),

292

].filter(Boolean),

293

294

optimization: isProduction ? {

295

splitChunks: {

296

chunks: 'all',

297

cacheGroups: {

298

vendor: {

299

test: /[\\/]node_modules[\\/]/,

300

name: 'vendors',

301

chunks: 'all',

302

},

303

},

304

},

305

} : {},

306

};

307

```

308

309

### Multiple Entry Points

310

311

Handle applications with multiple entry points:

312

313

```javascript

314

// webpack.config.js

315

module.exports = {

316

entry: {

317

main: './src/main.js',

318

admin: './src/admin.js',

319

},

320

plugins: [

321

new ReactLoadablePlugin({

322

filename: './dist/react-loadable.json',

323

}),

324

],

325

};

326

327

// Server usage - filter bundles by entry point

328

function getBundlesForEntry(stats, modules, entryName) {

329

const bundles = getBundles(stats, modules);

330

return bundles.filter(bundle =>

331

bundle.file.includes(entryName) ||

332

!bundle.file.match(/^(main|admin)\./)

333

);

334

}

335

```

336

337

### TypeScript Integration

338

339

```json

340

// tsconfig.json

341

{

342

"compilerOptions": {

343

"target": "es5",

344

"module": "esnext",

345

"moduleResolution": "node",

346

"jsx": "react",

347

"allowSyntheticDefaultImports": true

348

}

349

}

350

```

351

352

```javascript

353

// webpack.config.js

354

module.exports = {

355

resolve: {

356

extensions: ['.js', '.jsx', '.ts', '.tsx'],

357

},

358

module: {

359

rules: [

360

{

361

test: /\.(js|jsx|ts|tsx)$/,

362

exclude: /node_modules/,

363

use: {

364

loader: 'babel-loader',

365

},

366

},

367

],

368

},

369

};

370

```

371

372

## Build Optimization

373

374

### Bundle Analysis

375

376

Analyze which components are being code-split:

377

378

```javascript

379

// Build script to analyze loadable components

380

const fs = require('fs');

381

const stats = require('./dist/react-loadable.json');

382

383

console.log('Loadable components:');

384

Object.keys(stats).forEach(module => {

385

const bundles = stats[module];

386

console.log(`${module}:`);

387

bundles.forEach(bundle => {

388

console.log(` - ${bundle.file} (${bundle.id})`);

389

});

390

});

391

```

392

393

### Bundle Size Optimization

394

395

```javascript

396

// webpack.config.js - Optimize chunk sizes

397

module.exports = {

398

optimization: {

399

splitChunks: {

400

chunks: 'all',

401

minSize: 20000,

402

maxSize: 200000,

403

cacheGroups: {

404

default: {

405

minChunks: 2,

406

priority: -20,

407

reuseExistingChunk: true,

408

},

409

vendor: {

410

test: /[\\/]node_modules[\\/]/,

411

priority: -10,

412

reuseExistingChunk: true,

413

},

414

},

415

},

416

},

417

};

418

```

419

420

### Preload Optimization

421

422

Generate preload hints for critical bundles:

423

424

```javascript

425

// Server-side bundle preloading

426

function generatePreloadLinks(bundles) {

427

return bundles

428

.filter(bundle => bundle.file.endsWith('.js'))

429

.map(bundle =>

430

`<link rel="preload" href="${bundle.publicPath}" as="script">`

431

)

432

.join('\n');

433

}

434

435

// Usage in server

436

const bundles = getBundles(stats, modules);

437

const preloadLinks = generatePreloadLinks(bundles);

438

439

res.send(`

440

<!DOCTYPE html>

441

<html>

442

<head>

443

${preloadLinks}

444

</head>

445

<body>

446

<!-- ... -->

447

</body>

448

</html>

449

`);

450

```