# 应用开发

使用 Wails 开发应用程序没有硬性规定，但有一些基本准则。

## 应用程序设置

默认模板使用 `main.go` 配置和运行应用程序, 同时`app.go`用于定义应用程序逻辑.

该`app.go`文件将定义一个结构体，该结构体有 2 个方法作为主应用程序的回调：

```go title="app.go"
type App struct {
	ctx context.Context
}

func NewApp() *App {
	return &App{}
}

func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
}

func (a *App) shutdown(ctx context.Context) {
}
```

- `startup`方法会在 Wails 分配它需要的资源后立即调用，这是创建资源、设置事件侦听器以及应用程序在启动时需要的任何其他内容的好地方。它提供了一个`context.Context`，
  通常保存在结构字段中。调用[运行时](/docs/reference/runtime/intro)需要此`context.Context`。如果此方法返回错误，则应用程序将终止。在开发模式下，错误会输出到控制台。
- `shutdown`方法会在应用程序关闭进程时调用，这是释放内存和执行任何关闭任务的好地方。

`main.go`文件通常由对`wails.Run()`的单个调用组成，它接受应用程序配置。模板使用的模式是，在调用`wails.Run()`之前，
我们创建并保存一个在`app.go`中定义的结构体的实例在名`app`的变量中。这个配置是我们添加回调的地方：

```go {3,9,10} title="main.go"
func main() {

	app := NewApp()

	err := wails.Run(&options.App{
		Title:             "My App",
		Width:             800,
		Height:            600,
		OnStartup:  app.startup,
		OnShutdown: app.shutdown,
	})
	if err != nil {
		log.Fatal(err)
	}
}

```

可以在[此处](/docs/howdoesitwork#应用程序生命周期回调)找到有关应用程序生命周期回调的更多信息。

## 绑定方法

您可能希望从前端调用 Go 方法。这通常是通过向`app.go`中已经定义的结构体中添加公共方法来实现的：

```go {16-18} title="app.go"
type App struct {
	ctx context.Context
}

func NewApp() *App {
	return &App{}
}

func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
}

func (a *App) shutdown(ctx context.Context) {
}

func (a *App) Greet(name string) string {
    return fmt.Printf("Hello %s!", name)
}
```

在主应用程序中，`Bind`字段告诉我们 Wails 想要绑定什么：

```go {11-13} title="main.go"
func main() {

	app := NewApp()

	err := wails.Run(&options.App{
		Title:             "My App",
		Width:             800,
		Height:            600,
		OnStartup:  app.startup,
		OnShutdown: app.shutdown,
        Bind: []interface{}{
            app,
        },
	})
	if err != nil {
		log.Fatal(err)
	}
}

```

这将绑定`App`结构中的所有公共方法(它永远不会绑定 startup 和 shutdown 方法)。

可以在[此处](/docs/howdoesitwork#方法绑定)找到有关绑定的更多信息。

## 应用程序菜单

Wails 支持向您的应用程序添加菜单。 这是通过将 [菜单](/docs/reference/menus#菜单) 结构体传递给应用程序配置来完成的。
常见做法是使用一个返回菜单的方法，更常见的是用作生命周期回调的 `App` 结构体上的方法。

```go {11} title="main.go"
func main() {

	app := NewApp()

	err := wails.Run(&options.App{
		Title:             "My App",
		Width:             800,
		Height:            600,
		OnStartup:  app.startup,
		OnShutdown: app.shutdown,
		Menu:       app.menu(),
        Bind: []interface{}{
            app,
        },
	})
	if err != nil {
		log.Fatal(err)
	}
}

```

## 资源

Wails v2 处理资源的方式的伟大之处在于它没有！您唯一需要给 Wails 的是一个 `embed.FS`， 如何做到这一点完全取决于您。您可以像 vanilla 模板一样使用 vanilla html/css/js 文件。您可能有一些复杂的构建系统，但这并不影响。

当运行`wails build`时，它会检查项目根目录的`wails.json`文件。文件中有 2 个字段会被读取：

- "frontend:install"
- "frontend:build"

第一个，如果有给定，将在`frontend`目录中执行以安装 node 模块。第二个，如果有给定，将在`frontend`目录中执行以构建前端项目。

如果没有给出这两个字段，那么 Wails 不会对前端做任何操作。它仅仅被用作`embed.FS`。

## 内置开发服务器

运行`wails dev`将启动内置的开发服务器，它将在您的项目目录中启动一个文件监听器。
默认情况下，如果有任何文件更改，wails 会检查它是否是应用程序文件（默认：.go，可使用`-e`标志配置）。如果是，那么它将重新构建您的应用程序并重新启动它。如果更改的文件在`assetdir`目录中，它会在很短的时间后重新加载。

开发服务器使用一种称为“防抖”的技术，这意味着它不会立即重新加载，因为可能会在短时间内更改多个文件。当触发发生时，它会在发出重新加载之前等待一定的时间。
如果发生另一个触发，它会再次重置为等待时间。默认情况下，此值为 100ms。如果此值不适用于您的项目，则可以使用`-debounce`标志进行配置。如果使用，此值将保存到您的项目配置中并成为默认值。

## 外部开发服务器

一些框架带有自己的实时重新加载服务器，但是它们将无法利用 Wails Go 绑定。在这种情况下，最好运行一个监听脚本，将项目重新构建到构建目录中，Wails 将监视该目录。
有关示例，请参阅使用[rollup](https://rollupjs.org/guide/en/)的默认 svelte 模板。对于[create-react-app](https://create-react-app.dev/)，可以使用[此脚本](https://gist.github.com/int128/e0cdec598c5b3db728ff35758abdbafd)来实现类似的结果。

## Go 模块

默认的 Wails 模板会生成一个包含模块名称“changeme”的`go.mod`文件。您应该在项目生成后将其更改为更合适的内容。
