Skip to content

Commit 3f374e8

Browse files
authored
docs: Add upgrade guide for transitioning from Widget to Component in Serverpod 3.0 (#312)
1 parent 889d9d7 commit 3f374e8

2 files changed

Lines changed: 217 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ npm-debug.log*
1919
yarn-debug.log*
2020
yarn-error.log*
2121
settings.json
22+
.claude
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# Upgrade to 3.0
2+
3+
## Web Server: Widget to Component Rename
4+
5+
In Serverpod 3.0, all web server related "Widget" classes have been renamed to "Component" to better reflect their purpose and avoid confusion with Flutter widgets.
6+
7+
The following classes have been renamed:
8+
9+
| Old Name | New Name |
10+
| ---------------- | ------------------- |
11+
| `Widget` | `Component` |
12+
| `AbstractWidget` | `AbstractComponent` |
13+
| `WidgetRoute` | `ComponentRoute` |
14+
| `WidgetJson` | `JsonComponent` |
15+
| `WidgetRedirect` | `RedirectComponent` |
16+
| `WidgetList` | `ListComponent` |
17+
18+
### 1. Update Route Classes
19+
20+
Update all route classes that extend `WidgetRoute` to extend `ComponentRoute`, and rename them to follow the new naming convention:
21+
22+
**Before:**
23+
24+
```dart
25+
class RouteRoot extends WidgetRoute {
26+
@override
27+
Future<Widget> build(Session session, HttpRequest request) async {
28+
return MyPageWidget();
29+
}
30+
}
31+
```
32+
33+
**After:**
34+
35+
```dart
36+
class RootRoute extends ComponentRoute {
37+
@override
38+
Future<Component> build(Session session, HttpRequest request) async {
39+
return MyPageComponent();
40+
}
41+
}
42+
```
43+
44+
### 2. Update Component Classes
45+
46+
Update all classes that extend `Widget` to extend `Component`, and rename them from "Widget" to "Component":
47+
48+
**Before:**
49+
50+
```dart
51+
class MyPageWidget extends Widget {
52+
MyPageWidget({required String title}) : super(name: 'my_page') {
53+
values = {
54+
'title': title,
55+
};
56+
}
57+
}
58+
```
59+
60+
**After:**
61+
62+
```dart
63+
class MyPageComponent extends Component {
64+
MyPageComponent({required String title}) : super(name: 'my_page') {
65+
values = {
66+
'title': title,
67+
};
68+
}
69+
}
70+
```
71+
72+
### 3. Update Abstract Components
73+
74+
If you have custom abstract components, update them from `AbstractWidget` to `AbstractComponent` and rename accordingly:
75+
76+
**Before:**
77+
78+
```dart
79+
class CustomWidget extends AbstractWidget {
80+
@override
81+
String toString() {
82+
return '<html>...</html>';
83+
}
84+
}
85+
```
86+
87+
**After:**
88+
89+
```dart
90+
class CustomComponent extends AbstractComponent {
91+
@override
92+
String toString() {
93+
return '<html>...</html>';
94+
}
95+
}
96+
```
97+
98+
### 4. Update Special Component Types
99+
100+
Update references to special component types:
101+
102+
**Before:**
103+
104+
```dart
105+
// JSON responses
106+
return WidgetJson(object: {'status': 'success'});
107+
108+
// Redirects
109+
return WidgetRedirect(url: '/login');
110+
111+
// Component lists
112+
return WidgetList(widgets: [widget1, widget2]);
113+
```
114+
115+
**After:**
116+
117+
```dart
118+
// JSON responses
119+
return JsonComponent(object: {'status': 'success'});
120+
121+
// Redirects
122+
return RedirectComponent(url: '/login');
123+
124+
// Component lists
125+
return ListComponent(widgets: [widget1, widget2]);
126+
```
127+
128+
### 5. Update Route Registration
129+
130+
Update your route registration to use the renamed route classes:
131+
132+
**Before:**
133+
134+
```dart
135+
pod.webServer.addRoute(RouteRoot(), '/');
136+
pod.webServer.addRoute(RouteRoot(), '/index.html');
137+
```
138+
139+
**After:**
140+
141+
```dart
142+
pod.webServer.addRoute(RootRoute(), '/');
143+
pod.webServer.addRoute(RootRoute(), '/index.html');
144+
```
145+
146+
### Directory Structure
147+
148+
For consistency with the new naming convention, we recommend renaming your `widgets/` directories to `components/`. However, this is not strictly required - the directory structure can remain unchanged if needed.
149+
150+
### Class Names
151+
152+
For consistency and clarity, we recommend updating all class names from "Widget" to "Component" (e.g., `MyPageWidget``MyPageComponent`). While you can keep your existing class names and only update the inheritance, following the new naming convention will make your code more maintainable and consistent with Serverpod's conventions.
153+
154+
### Complete Example
155+
156+
Here's a complete example of migrating a simple web page:
157+
158+
**Before:**
159+
160+
```dart
161+
// lib/src/web/widgets/default_page_widget.dart
162+
import 'package:serverpod/serverpod.dart';
163+
164+
class DefaultPageWidget extends Widget {
165+
DefaultPageWidget() : super(name: 'default') {
166+
values = {
167+
'served': DateTime.now(),
168+
'runmode': Serverpod.instance.runMode,
169+
};
170+
}
171+
}
172+
173+
// lib/src/web/routes/root.dart
174+
import 'dart:io';
175+
import 'package:my_server/src/web/widgets/default_page_widget.dart';
176+
import 'package:serverpod/serverpod.dart';
177+
178+
class RouteRoot extends WidgetRoute {
179+
@override
180+
Future<Widget> build(Session session, HttpRequest request) async {
181+
return DefaultPageWidget();
182+
}
183+
}
184+
```
185+
186+
**After:**
187+
188+
```dart
189+
// lib/src/web/components/default_page_component.dart (renamed file and directory)
190+
import 'package:serverpod/serverpod.dart';
191+
192+
class DefaultPageComponent extends Component {
193+
DefaultPageComponent() : super(name: 'default') {
194+
values = {
195+
'served': DateTime.now(),
196+
'runmode': Serverpod.instance.runMode,
197+
};
198+
}
199+
}
200+
201+
// lib/src/web/routes/root.dart
202+
import 'dart:io';
203+
import 'package:my_server/src/web/components/default_page_component.dart';
204+
import 'package:serverpod/serverpod.dart';
205+
206+
class RootRoute extends ComponentRoute {
207+
@override
208+
Future<Component> build(Session session, HttpRequest request) async {
209+
return DefaultPageComponent();
210+
}
211+
}
212+
213+
// server.dart
214+
pod.webServer.addRoute(RootRoute(), '/');
215+
pod.webServer.addRoute(RootRoute(), '/index.html');
216+
```

0 commit comments

Comments
 (0)