Skip to content

Commit

Permalink
Merge branch 'v3-alpha' into v3-alpha-bugfix/4012-dynamic-context-menu
Browse files Browse the repository at this point in the history
  • Loading branch information
leaanthony authored Jan 17, 2025
2 parents 260336e + f01b4b9 commit 144329a
Show file tree
Hide file tree
Showing 550 changed files with 9,443 additions and 6,088 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test-v3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
go-version: [1.22]
go-version: [1.23]

steps:
- name: Checkout code
Expand Down
11 changes: 11 additions & 0 deletions docs/src/content/docs/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Breaking Changes

- Renamed Service methods: `Name` -> `ServiceName`, `OnStartup` -> `ServiceStartup`, `OnShutdown` -> `ServiceShutdown` by [@leaanthony](https://github.com/leaanthony)

### Added

- Support aarch64 AppImage builds by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981)
- Add diagnostics section to `wails doctor` by [@leaanthony](https://github.com/leaanthony)
- Add window to context when calling a service method by [@leaanthony](https://github.com/leaanthony)
- Add `window-call` example to demonstrate how to know which window is calling a service by [@leaanthony](https://github.com/leaanthony)
- New Menu guide by [@leaanthony](https://github.com/leaanthony)
- Better panic handling by [@leaanthony](https://github.com/leaanthony)

### Fixed

- Fixed Windows+Linux Edit Menu issues by [@leaanthony](https://github.com/leaanthony) in [#3f78a3a](https://github.com/wailsapp/wails/commit/3f78a3a8ce7837e8b32242c8edbbed431c68c062)
- Updated the minimum system version in macOS .plist files from 10.13.0 to 10.15.0 by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981)
- Window ID skip issue by [@leaanthony](https://github.com/leaanthony)
- Fix nil menu issue when calling RegisterContextMenu by [@leaanthony](https://github.com/leaanthony)
- Fixed dependency cycles in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001)
- Fixed use-before-define errors in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001)

### Changed

- Removed `application.WindowIDKey` and `application.WindowNameKey` (replaced by `application.WindowKey`) by [@leaanthony](https://github.com/leaanthony)
- ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony)
- In JS/TS bindings, class fields of fixed-length array types are now initialized with their expected length instead of being empty by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001)

## v3.0.0-alpha.9 - 2025-01-13

Expand Down
111 changes: 111 additions & 0 deletions docs/src/content/docs/guides/panic-handling.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: Handling Panics
description: How to handle panics in your Wails application
---

In Go applications, panics can occur during runtime when something unexpected happens. This guide explains how to handle panics both in general Go code and specifically in your Wails application.

## Understanding Panics in Go

Before diving into Wails-specific panic handling, it's essential to understand how panics work in Go:

1. Panics are for unrecoverable errors that shouldn't happen during normal operation
2. When a panic occurs in a goroutine, only that goroutine is affected
3. Panics can be recovered using `defer` and `recover()`

Here's a basic example of panic handling in Go:

```go
func doSomething() {
// Deferred functions run even when a panic occurs
defer func() {
if r := recover(); r != nil {
fmt.Printf("Recovered from panic: %v\n", r)
}
}()

// Your code that might panic
panic("something went wrong")
}
```

For more detailed information about panic and recover in Go, see the [Go Blog: Defer, Panic, and Recover](https://go.dev/blog/defer-panic-and-recover).

## Panic Handling in Wails

Wails automatically handles panics that occur in your Service methods when they are called from the frontend. This means you don't need to add panic recovery to these methods - Wails will catch the panic and process it through your configured panic handler.

The panic handler is specifically designed to catch:
- Panics in bound service methods called from the frontend
- Internal panics from the Wails runtime

For other scenarios, such as background goroutines or standalone Go code, you should handle panics yourself using Go's standard panic recovery mechanisms.

## The PanicDetails Struct

When a panic occurs, Wails captures important information about the panic in a `PanicDetails` struct:

```go
type PanicDetails struct {
StackTrace string // The stack trace of where the panic occurred. Potentially trimmed to provide more context
Error error // The error that caused the panic
Time time.Time // The time when the panic occurred
FullStackTrace string // The complete stack trace including runtime frames
}
```

This structure provides comprehensive information about the panic:
- `StackTrace`: A formatted string showing the call stack that led to the panic
- `Error`: The actual error or panic message
- `Time`: The exact time when the panic occurred
- `FullStackTrace`: The complete stack trace including runtime frames

:::note[Panics in Service Code]

When panics are caught in your Service code after being called from the frontend, the stack trace is trimmed to focus on exactly where in your code the panic occurred.
If you want to see the full stack trace, you can use the `FullStackTrace` field.

:::

## Default Panic Handler

If you don't specify a custom panic handler, Wails will use its default handler which outputs error information in a formatted log message. For example:

```
Jan 16 21:18:05.649 ERR panic error: oh no! something went wrong deep in my service! :(
main.(*WindowService).call2
at E:/wails/v3/examples/panic-handling/main.go:24
main.(*WindowService).call1
at E:/wails/v3/examples/panic-handling/main.go:20
main.(*WindowService).GeneratePanic
at E:/wails/v3/examples/panic-handling/main.go:16
```

## Custom Panic Handler

You can implement your own panic handler by setting the `PanicHandler` option when creating your application. Here's an example:

```go
app := application.New(application.Options{
Name: "My App",
PanicHandler: func(panicDetails *application.PanicDetails) {
fmt.Printf("*** Custom Panic Handler ***\n")
fmt.Printf("Time: %s\n", panicDetails.Time)
fmt.Printf("Error: %s\n", panicDetails.Error)
fmt.Printf("Stacktrace: %s\n", panicDetails.StackTrace)
fmt.Printf("Full Stacktrace: %s\n", panicDetails.FullStackTrace)

// You could also:
// - Log to a file
// - Send to a crash reporting service
// - Show a user-friendly error dialog
// - Attempt to recover or restart the application
},
})
```

For a complete working example of panic handling in a Wails application, see the panic-handling example in `v3/examples/panic-handling`.

## Final Notes

Remember that the Wails panic handler is specifically for managing panics in bound methods and internal runtime errors. For other parts of your application, you should use Go's standard error handling patterns and panic recovery mechanisms where appropriate. As with all Go applications, it's better to prevent panics through proper error handling where possible.
22 changes: 11 additions & 11 deletions docs/src/content/docs/learn/services.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,34 +57,34 @@ app := application.New(application.Options{
Services can implement optional methods to hook into the application lifecycle.

:::note
The `OnStartup`, `OnShutdown`, and `ServeHTTP` methods are not included in the
The `ServiceStartup`, `ServiceShutdown`, `ServiceName` and `ServeHTTP` methods are not included in the
bindings generated for a service, so they are not exposed to your frontend.
:::

### Name
### ServiceName

```go
func (s *Service) Name() string
func (s *Service) ServiceName() string
```

This method returns the name of the service. It is used for logging purposes
only.

### OnStartup
### ServiceStartup

```go
func (s *Service) OnStartup(ctx context.Context, options application.ServiceOptions) error
func (s *Service) ServiceStartup(ctx context.Context, options application.ServiceOptions) error
```

This method is called when the application is starting up. You can use it to
initialize resources, set up connections, or perform any necessary setup tasks.
The context is the application context, and the `options` parameter provides
additional information about the service.

### OnShutdown
### ServiceShutdown

```go
func (s *Service) OnShutdown() error
func (s *Service) ServiceShutdown() error
```

This method is called when the application is shutting down. Use it to clean up
Expand Down Expand Up @@ -125,11 +125,11 @@ func New(config *Config) *Service {
}
}

func (s *Service) Name() string {
func (s *Service) ServiceName() string {
return "github.com/wailsapp/wails/v3/services/fileserver"
}

func (s *Service) OnStartup(ctx context.Context, options application.ServiceOptions) error {
func (s *Service) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
// Any initialization code here
return nil
}
Expand Down Expand Up @@ -159,11 +159,11 @@ All requests to `/files` will be handled by the `fileserver` service.

1. During application initialization, services are registered with the
application.
2. When the application starts (`app.Run()`), the `OnStartup` method of each
2. When the application starts (`app.Run()`), the `ServiceStartup` method of each
service is called with the application context and service options.
3. Throughout the application's lifetime, services can perform their specific
tasks.
4. If a service implements `ServeHTTP`, it can handle HTTP requests at the
specified path.
5. When the application is shutting down, the `OnShutdown` method of each
5. When the application is shutting down, the `ServiceShutdown` method of each
service is called as well as the context being cancelled.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import {Create as $Create} from "/wails/runtime.js";

/**
* Person holds someone's most important attributes
*/
export class Person {
/**
* Creates a new Person instance.
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
*/
constructor($$source = {}) {
if (!("name" in $$source)) {
/**
* Name is the person's name
* @member
* @type {string}
*/
this["name"] = "";
}
if (!("counts" in $$source)) {
/**
* Counts tracks the number of time the person
* has been greeted in various ways
* @member
* @type {number[]}
*/
this["counts"] = [];
}

Object.assign(this, $$source);
}

/**
* Creates a new Person instance from a string or object.
* @param {any} [$$source = {}]
* @returns {Person}
*/
static createFrom($$source = {}) {
const $$createField1_0 = $$createType0;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("counts" in $$parsedSource) {
$$parsedSource["counts"] = $$createField1_0($$parsedSource["counts"]);
}
return new Person(/** @type {Partial<Person>} */($$parsedSource));
}
}

// Private type creation functions
const $$createType0 = $Create.Array($Create.Any);
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,6 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import {Create as $Create} from "/wails/runtime.js";

/**
* Person holds someone's most important attributes
*/
export class Person {
/**
* Creates a new Person instance.
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
*/
constructor($$source = {}) {
if (!("name" in $$source)) {
/**
* Name is the person's name
* @member
* @type {string}
*/
this["name"] = "";
}
if (!("counts" in $$source)) {
/**
* Counts tracks the number of time the person
* has been greeted in various ways
* @member
* @type {number[]}
*/
this["counts"] = [];
}

Object.assign(this, $$source);
}

/**
* Creates a new Person instance from a string or object.
* @param {any} [$$source = {}]
* @returns {Person}
*/
static createFrom($$source = {}) {
const $$createField1_0 = $$createType0;
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
if ("counts" in $$parsedSource) {
$$parsedSource["counts"] = $$createField1_0($$parsedSource["counts"]);
}
return new Person(/** @type {Partial<Person>} */($$parsedSource));
}
}

// Private type creation functions
const $$createType0 = $Create.Array($Create.Any);
export {
Person
} from "./internal.js";
11 changes: 11 additions & 0 deletions v3/examples/panic-handling/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Panic Handling Example

This example is a demonstration of how to handle panics in your application.

## Running the example

To run the example, simply run the following command:

```bash
go run .
```
27 changes: 27 additions & 0 deletions v3/examples/panic-handling/assets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Window Call Demo</title>
<style>
body {
color: white;
}
</style>
<script src="/wails/runtime.js" type="module"></script>
<script>
async function callBinding(name, ...params) {
return wails.Call.ByName(name, ...params)
}
</script>
</head>
<body>
<button onclick="panic()">Create a panic</button>
<script>
async function panic() {
await callBinding('main.WindowService.GeneratePanic')
}
</script>
</body>
</html>
Loading

0 comments on commit 144329a

Please sign in to comment.