|
| 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