Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
settings.json
.claude
216 changes: 216 additions & 0 deletions docs/08-upgrading/06-upgrade-to-three.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Upgrade to 3.0

## Web Server: Widget to Component Rename

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.

The following classes have been renamed:

| Old Name | New Name |
| ---------------- | ------------------- |
| `Widget` | `Component` |
| `AbstractWidget` | `AbstractComponent` |
| `WidgetRoute` | `ComponentRoute` |
| `WidgetJson` | `JsonComponent` |
| `WidgetRedirect` | `RedirectComponent` |
| `WidgetList` | `ListComponent` |

### 1. Update Route Classes

Update all route classes that extend `WidgetRoute` to extend `ComponentRoute`, and rename them to follow the new naming convention:

**Before:**

```dart
class RouteRoot extends WidgetRoute {
@override
Future<Widget> build(Session session, HttpRequest request) async {
return MyPageWidget();
}
}
```

**After:**

```dart
class RootRoute extends ComponentRoute {
@override
Future<Component> build(Session session, HttpRequest request) async {
return MyPageComponent();
}
}
```

### 2. Update Component Classes

Update all classes that extend `Widget` to extend `Component`, and rename them from "Widget" to "Component":

**Before:**

```dart
class MyPageWidget extends Widget {
MyPageWidget({required String title}) : super(name: 'my_page') {
values = {
'title': title,
};
}
}
```

**After:**

```dart
class MyPageComponent extends Component {
MyPageComponent({required String title}) : super(name: 'my_page') {
values = {
'title': title,
};
}
}
```

### 3. Update Abstract Components

If you have custom abstract components, update them from `AbstractWidget` to `AbstractComponent` and rename accordingly:

**Before:**

```dart
class CustomWidget extends AbstractWidget {
@override
String toString() {
return '<html>...</html>';
}
}
```

**After:**

```dart
class CustomComponent extends AbstractComponent {
@override
String toString() {
return '<html>...</html>';
}
}
```

### 4. Update Special Component Types

Update references to special component types:

**Before:**

```dart
// JSON responses
return WidgetJson(object: {'status': 'success'});

// Redirects
return WidgetRedirect(url: '/login');

// Component lists
return WidgetList(widgets: [widget1, widget2]);
```

**After:**

```dart
// JSON responses
return JsonComponent(object: {'status': 'success'});

// Redirects
return RedirectComponent(url: '/login');

// Component lists
return ListComponent(widgets: [widget1, widget2]);
```

### 5. Update Route Registration

Update your route registration to use the renamed route classes:

**Before:**

```dart
pod.webServer.addRoute(RouteRoot(), '/');
pod.webServer.addRoute(RouteRoot(), '/index.html');
```

**After:**

```dart
pod.webServer.addRoute(RootRoute(), '/');
pod.webServer.addRoute(RootRoute(), '/index.html');
```

### Directory Structure

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.

### Class Names

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.

### Complete Example

Here's a complete example of migrating a simple web page:

**Before:**

```dart
// lib/src/web/widgets/default_page_widget.dart
import 'package:serverpod/serverpod.dart';

class DefaultPageWidget extends Widget {
DefaultPageWidget() : super(name: 'default') {
values = {
'served': DateTime.now(),
'runmode': Serverpod.instance.runMode,
};
}
}

// lib/src/web/routes/root.dart
import 'dart:io';
import 'package:my_server/src/web/widgets/default_page_widget.dart';
import 'package:serverpod/serverpod.dart';

class RouteRoot extends WidgetRoute {
@override
Future<Widget> build(Session session, HttpRequest request) async {
return DefaultPageWidget();
}
}
```

**After:**

```dart
// lib/src/web/components/default_page_component.dart (renamed file and directory)
import 'package:serverpod/serverpod.dart';

class DefaultPageComponent extends Component {
DefaultPageComponent() : super(name: 'default') {
values = {
'served': DateTime.now(),
'runmode': Serverpod.instance.runMode,
};
}
}

// lib/src/web/routes/root.dart
import 'dart:io';
import 'package:my_server/src/web/components/default_page_component.dart';
import 'package:serverpod/serverpod.dart';

class RootRoute extends ComponentRoute {
@override
Future<Component> build(Session session, HttpRequest request) async {
return DefaultPageComponent();
}
}

// server.dart
pod.webServer.addRoute(RootRoute(), '/');
pod.webServer.addRoute(RootRoute(), '/index.html');
```