0
# @loadable/babel-plugin
1
2
@loadable/babel-plugin is a Babel plugin that transforms loadable component function calls to enable server-side rendering (SSR) support in React applications. The plugin analyzes dynamic import() statements within loadable() calls and injects additional properties required for SSR, including chunk names, synchronous loading methods, and module resolution functions.
3
4
## Package Information
5
6
- **Package Name**: @loadable/babel-plugin
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install --save-dev @loadable/babel-plugin`
10
11
## Core Imports
12
13
```javascript
14
// Babel plugin configuration (in babel.config.js or .babelrc)
15
module.exports = {
16
plugins: ['@loadable/babel-plugin']
17
};
18
```
19
20
For custom import signatures:
21
22
```javascript
23
module.exports = {
24
plugins: [
25
['@loadable/babel-plugin', {
26
signatures: [
27
{ name: 'default', from: '@loadable/component' },
28
{ name: 'loadable', from: 'my-custom-loadable' }
29
]
30
}]
31
]
32
};
33
```
34
35
## Basic Usage
36
37
The plugin transforms loadable component calls automatically during build time:
38
39
```javascript
40
// Input code
41
import loadable from '@loadable/component';
42
43
const AsyncComponent = loadable(() => import('./MyComponent'));
44
45
// Plugin transforms this to include SSR properties
46
const AsyncComponent = loadable({
47
chunkName(props) { return 'MyComponent'; },
48
isReady(props) { /* ... */ },
49
importAsync: () => import('./MyComponent'),
50
requireAsync(props) { /* ... */ },
51
requireSync(props) { /* ... */ },
52
resolve(props) { /* ... */ },
53
resolved: {}
54
});
55
```
56
57
## Architecture
58
59
The plugin operates during Babel's AST transformation phase and consists of:
60
61
- **Main Plugin**: Entry point that configures visitor patterns and transformation logic
62
- **Property Generators**: Modules that create the injected SSR-support methods
63
- **Signature Detection**: Logic to identify loadable function calls based on import patterns
64
- **AST Transformation**: Code that replaces loadable function calls with enhanced objects
65
66
## Capabilities
67
68
### Plugin Configuration
69
70
Configure which import patterns the plugin should transform.
71
72
```javascript { .api }
73
/**
74
* Main Babel plugin export - configured in Babel configuration
75
* @param api - Babel API object containing types and other utilities
76
* @param options - Plugin configuration options
77
* @returns Babel plugin object with visitor methods
78
*/
79
function loadablePlugin(api: object, options: LoadablePluginOptions): BabelPlugin;
80
81
interface LoadablePluginOptions {
82
/** Array of import signature patterns to transform */
83
signatures?: ImportSignature[];
84
}
85
86
interface ImportSignature {
87
/** Import specifier name ('default' for default imports, or named import) */
88
name: string;
89
/** Package name to match for transformation */
90
from: string;
91
}
92
93
interface BabelPlugin {
94
/** Inherits syntax-dynamic-import plugin for import() support */
95
inherits: object;
96
/** AST visitor configuration */
97
visitor: {
98
Program: {
99
enter(programPath: object): void;
100
};
101
};
102
}
103
```
104
105
**Default Configuration:**
106
107
```javascript
108
// Default signatures - transforms @loadable/component imports
109
const DEFAULT_SIGNATURE = [{ name: 'default', from: '@loadable/component' }];
110
```
111
112
### Transformation Targets
113
114
The plugin identifies and transforms these patterns:
115
116
```javascript { .api }
117
// 1. loadable() function calls (based on import signatures)
118
loadable(() => import('./Component'))
119
120
// 2. lazy() function calls (when imported from @loadable/component)
121
import { lazy } from '@loadable/component';
122
lazy(() => import('./Component'))
123
124
// 3. loadable.lib() method calls
125
loadable.lib(() => import('./library'))
126
127
// 4. Functions with #__LOADABLE__ comment - supports multiple function types:
128
/* #__LOADABLE__ */ () => import('./Component') // Arrow function
129
/* #__LOADABLE__ */ function() { return import('./Component') } // Function expression
130
const obj = { /* #__LOADABLE__ */ load() { return import('./Component') } } // Object method
131
```
132
133
### Generated Runtime Methods
134
135
When the plugin transforms a loadable call, it injects these SSR-support methods:
136
137
```javascript { .api }
138
interface LoadableComponentObject {
139
/**
140
* Generates webpack chunk name for the dynamic import
141
* Handles webpack comments and template literals
142
*/
143
chunkName(props: any): string;
144
145
/**
146
* Checks if the module is ready (loaded) for synchronous rendering
147
* Returns true if module is available in webpack module cache
148
*/
149
isReady(props: any): boolean;
150
151
/**
152
* Original async import function - preserves the dynamic import()
153
*/
154
importAsync: () => Promise<any>;
155
156
/**
157
* Async module loading with resolution tracking
158
* Updates resolved state when promise completes
159
*/
160
requireAsync(props: any): Promise<any>;
161
162
/**
163
* Synchronous module loading for SSR
164
* Uses __webpack_require__ or Node.js require based on environment
165
*/
166
requireSync(props: any): any;
167
168
/**
169
* Resolves module ID for the dynamic import
170
* Uses require.resolveWeak or require.resolve based on availability
171
*/
172
resolve(props: any): string;
173
174
/**
175
* Object tracking resolved module states
176
* Maps module IDs to boolean resolution status
177
*/
178
resolved: Record<string, boolean>;
179
}
180
```
181
182
### Webpack Integration
183
184
The plugin handles webpack-specific features for chunk naming and module resolution:
185
186
```javascript { .api }
187
// Webpack comment processing for chunk names
188
import(
189
/* webpackChunkName: "my-chunk" */
190
'./Component'
191
);
192
193
// Template literal support for dynamic chunk names
194
const componentName = 'MyComponent';
195
import(`./components/${componentName}`);
196
```
197
198
**Chunk Name Generation Rules:**
199
200
- Static imports: Uses file path converted to chunk-safe format
201
- Template literals: Preserves dynamic expressions with sanitization
202
- Webpack comments: Respects existing webpackChunkName comments
203
- Path normalization: Removes file extensions and converts special characters to hyphens
204
205
### Error Handling
206
207
The plugin validates usage patterns and throws errors for unsupported configurations:
208
209
```javascript { .api }
210
// Error: Multiple import calls not supported
211
loadable(() => {
212
import('./ComponentA');
213
import('./ComponentB'); // Throws error
214
});
215
```
216
217
**Common Error Messages:**
218
219
- `"loadable: multiple import calls inside loadable() function are not supported"`
220
- Webpack comment parsing errors with compilation context
221
- Template literal processing errors for invalid expressions
222
223
### Environment Detection
224
225
The plugin generates environment-aware code that works in different contexts:
226
227
```javascript { .api }
228
// Browser environment (webpack)
229
if (typeof __webpack_require__ !== 'undefined') {
230
return __webpack_require__(id);
231
}
232
233
// Node.js environment
234
return eval('module.require')(id);
235
236
// Webpack modules check
237
if (typeof __webpack_modules__ !== 'undefined') {
238
return !!(__webpack_modules__[key]);
239
}
240
```
241
242
## Types
243
244
```javascript { .api }
245
// Plugin accepts these configuration options
246
interface LoadablePluginOptions {
247
signatures?: ImportSignature[];
248
}
249
250
interface ImportSignature {
251
name: string; // 'default' | string (named import)
252
from: string; // Package name like '@loadable/component'
253
}
254
255
// Internal transformation context
256
interface TransformContext {
257
path: object; // Babel AST path to the loadable call
258
callPath: object; // Babel AST path to the import() call
259
funcPath: object; // Babel AST path to the function expression
260
}
261
262
// Generated object structure
263
interface GeneratedLoadableObject {
264
chunkName(props: any): string;
265
isReady(props: any): boolean;
266
importAsync: () => Promise<any>;
267
requireAsync(props: any): Promise<any>;
268
requireSync(props: any): any;
269
resolve(props: any): string | number;
270
resolved: Record<string, boolean>;
271
}
272
```