# 애플리케이션 개발

Wails로 애플리케이션을 개발하기 위한 엄격한 규칙은 없으나 몇 가지의 기본 가이드가 있습니다.

## 애플리케이션 셋업

기본 템플릿에서 사용되는 패턴은 `main.go`가 애플리케이션 구성 및 실행에 사용되는 반면 `app.go`는 애플리케이션 로직 정의에 사용된다는 것입니다.

`app.go` 파일은 기본 애플리케이션에 hook 역할을 하는 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) {
}
```

- 시작 메서드는 Wails가 필요한 리소스를 할당하는 즉시 호출되며 리소스 생성, 이벤트 리스너 설정 및 시작 시 응용 프로그램에 필요한 모든 것을 설정하기에 좋은 위치입니다. 일반적으로 구조체 필드에 저장되는 `context.Context`가 제공됩니다. 이 컨텍스트는 [런타임](../reference/runtime/intro.mdx)을 호출하는 데 필요합니다. 이 메서드가 오류를 반환하면 응용 프로그램이 종료됩니다. 개발 모드에서는 오류가 콘솔에 출력됩니다.

- Shutdown 메소드는 shutdown 프로세스가 끝날 때 바로 Wails에 의해 호출됩니다. 이것은 메모리 할당을 해제하고 모든 shutodown 작업을 수행하기에 좋은 위치입니다.

`main.go` 파일은 일반적으로 애플리케이션 구성을 허용하는 `wails.Run()`에 대한 단일 호출로 구성됩니다. 템플릿에서 사용하는 패턴은 `wails.Run()`을 호출하기 전에 `app.go`에서 정의한 구조체의 인스턴스가 생성되어 변수에 저장된다는 것입니다. 이것은 `app`이라고 합니다. 이 configuration 은 콜백을 추가하는 위치입니다:

```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)
    }
}

```

애플리케이션 lifecycle hook에 대한 자세한 내용은 [여기](../howdoesitwork.mdx#application-lifecycle-callbacks)에서 확인할 수 있습니다.

## 바인딩 메소드

프론트엔드에서 Go 메서드를 호출할 가능성이 높습니다. 이는 일반적으로 `app.go`에서 이미 정의된 구조체에 public method를 추가하여 수행됩니다.

```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.Sprintf("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` 구조체의 모든 공개 메서드가 바인딩됩니다(시작 및 종료 메서드는 바인딩되지 않음).

### 여러 구조체를 바인딩할 때의 컨텍스트 처리

여러 구조체에 대한 메서드를 바인딩하고 싶지만 런타임을 사용할 수 있도록 각 구조체가 컨텍스트에 대한 참조를 유지하기를 원하는 경우, 함수에서 좋은 패턴은 `OnStartup` 메서드에서 구조체 인스턴스로 컨텍스트를 전달하는 것입니다.

```go
func main() {

    app := NewApp()
    otherStruct := NewOtherStruct()

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

Also you might want to use Enums in your structs and have models for them on frontend. In that case you should create array that will contain all possible enum values, instrument enum type and bind it to the app:

```go {16-18} title="app.go"
type Weekday string

const (
    Sunday    Weekday = "Sunday"
    Monday    Weekday = "Monday"
    Tuesday   Weekday = "Tuesday"
    Wednesday Weekday = "Wednesday"
    Thursday  Weekday = "Thursday"
    Friday    Weekday = "Friday"
    Saturday  Weekday = "Saturday"
)

var AllWeekdays = []struct {
    Value  Weekday
    TSName string
}{
    {Sunday, "SUNDAY"},
    {Monday, "MONDAY"},
    {Tuesday, "TUESDAY"},
    {Wednesday, "WEDNESDAY"},
    {Thursday, "THURSDAY"},
    {Friday, "FRIDAY"},
    {Saturday, "SATURDAY"},
}
```

In the main application configuration, the `EnumBind` key is where we can tell Wails what we want to bind enums as well:

```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,
    },
    EnumBind: []interface{}{
        AllWeekdays,
     },
    })
    if err != nil {
        log.Fatal(err)
    }
}

```

This will add missing enums to your `model.ts` file.

바인딩에 대한 더 많은 정보는 [여기](../howdoesitwork.mdx#method-binding)에서 확인할 수 있습니다.

## Application Menu

Wails는 당신의 애플리케이션에 메뉴 추가를 지원합니다. 이것은 [Menu](../reference/menus.mdx#menu) 구조체를 애플리케이션 구성에 전달하여 수행됩니다. Menu를 반환하는 메서드를 사용하는 것이 일반적이며 lifecycle hooks에 사용되는 `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)
    }
}

```

## Assets

Wails v2가 assets을 처리하는 방식의 장점은 그렇지 않다는 것입니다! Wails에 제공해야 하는 유일한 것은 `embed.FS`입니다. 당신이 어떻게 얻어내는가는 전적으로 당신에게 달렸습니다. 바닐라 템플릿과 같은 바닐라 html/css/js를 사용할 수 있습니다. 복잡한 빌드 시스템을 가질 수 있으나, 중요하지 않습니다.

`wails build`가 실행되면 프로젝트 최상위에서 `wails.json` 프로젝트 파일을 확인합니다. 프로젝트 파일에는 2개의 키가 있습니다.

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

첫 번째는 노드 모듈을 설치하기 위해 `frontend` 디렉토리에서 실행됩니다. 두 번째는 프런트엔드 프로젝트를 빌드하기 위해 `frontend` 디렉토리에서 실행됩니다.

이 2개의 키가 주어지지 않으면 Wails는 프런트엔드에서 아무 작업도 수행하지 않습니다. 그것은 `embed.FS`에서만 기대합니다.

### AssetsHandler

Wails v2 앱은 선택적으로 `options.App`에서 `http.Handler`를 정의할 수 있습니다. 즉석에서 파일을 생성하거나 POST/PUT 요청을 처리합니다. GET 요청은 항상 `assets` FS에서 먼저 처리됩니다. FS가 요청된 파일을 찾지 못하면 요청은 제공을 위해 `http.Handler`로 전달됩니다. GET 이외의 모든 요청은 지정된 경우 `AssetsHandler`에서 직접 처리됩니다. `Assets` 옵션으로 `nil`을 지정하여 `AssetsHandler`만 사용할 수도 있습니다.

## Built in Dev Server

`wails dev`를 실행하면 내장된 dev 서버가 시작되어 프로젝트 디렉토리에서 file watcher를 시작합니다. 기본적으로 파일이 변경되면 wails는 응용 프로그램 파일인지 확인합니다(기본값: `.go`, `-e` 플래그로 구성 가능). 그렇다면 응용 프로그램을 다시 빌드하고 다시 시작합니다. 변경된 파일이 assets에 있는 경우 짧은 시간 후에 다시 로드를 발행합니다.

개발 서버는 "debouncing"이라는 기술을 사용합니다. 즉, 짧은 시간에 여러 파일이 변경될 수 있으므로 바로 다시 로드되지 않습니다. 트리거가 발생하면 다시 로드하기 전에 설정된 시간 동안 기다립니다. 다른 트리거가 발생하면 다시 대기 시간으로 재설정됩니다. 기본 값은 `100ms` 입니다. 이 값이 프로젝트에서 작동하지 않는 경우 `-debounce` 플래그를 사용하여 구성할 수 있습니다. 사용하는 경우 이 값은 프로젝트 구성에 저장되고 기본값이 됩니다.

## External Dev Server

일부 프레임워크는 자체 라이브 리로딩 서버와 함께 제공되지만 Wails Go 바인딩을 활용할 수 없습니다. 이 시나리오에서는 Wails가 감시할 빌드 디렉토리에 프로젝트를 다시 빌드하는 watcher script를 실행하는 것이 가장 좋습니다. 예를 보려면 [rollup](https://rollupjs.org/guide/en/)을 사용하는 기본 svelte 템플릿을 참조하세요.

### Create React App

The process for a Create-React-App project is slightly more complicated. In order to support live frontend reloading the following configuration needs to be added to your `wails.json`:

```json
  "frontend:dev:watcher": "yarn start",
  "frontend:dev:serverUrl": "http://localhost:3000",
```

The `frontend:dev:watcher` command will start the Create-React-App development server (hosted on port `3000` typically). The `frontend:dev:serverUrl` command then instructs Wails to serve assets from the development server when loading the frontend rather than from the build folder. In addition to the above, the `index.html` needs to be updated with the following:

```html
    <head>
        <meta name="wails-options" content="noautoinject" />
        <script src="/wails/ipc.js"></script>
        <script src="/wails/runtime.js"></script>
    </head>
```

This is required as the watcher command that rebuilds the frontend prevents Wails from injecting the required scripts. This circumvents that issue by ensuring the scripts are always injected. With this configuration, `wails dev` can be run which will appropriately build the frontend and backend with hot-reloading enabled. Additionally, when accessing the application from a browser the React developer tools can now be used on a non-minified version of the application for straightforward debugging. Finally, for faster builds, `wails dev -s` can be run to skip the default building of the frontend by Wails as this is an unnecessary step.

## Go Module

기본 Wails 템플릿은 "changeme"라는 모듈 이름이 포함된 `go.mod` 파일을 생성합니다. 프로젝트 생성 후에 이 파일의 이름을 변경해야 합니다.
