カテゴリー: BackEnd

Go 1.18のWorkspacesモードでマルチモジュール化

はじめに

Go 1.18から、マルチモジュールでの開発を便利にするためのWorkspacesモードが導入されました。今回は、Workspacesモードでどのように便利になるか紹介します。

マルチモジュール構成

比較のために、まずはWorkspacesモードではない場合のマルチモジュール構成の例を示します。

非Workspacesモードの場合

Workspacesモードではない場合の構成例は以下のとおりです。

% tree
.
├── items
│   ├── food.go
│   └── go.mod
├── main
│   ├── go.mod
│   └── main.go
└── stores
    ├── go.mod
    └── shop.go

それぞれ、ファイルの中身は以下のとおりです。

/items

module example.com/items

go 1.18
package items

const Name = "Food"

/stores

module example.com/stores

go 1.18
package stores

const Name = "Shop"

/main

module example.com/main

go 1.18

replace example.com/items => ../items

replace example.com/stores => ../stores

require example.com/items v0.0.0-00010101000000-000000000000

require example.com/stores v0.0.0-00010101000000-000000000000
package main

import (
 "fmt"
 "example.com/stores"
 "example.com/items"
)

func main() {
 fmt.Println(stores.Name)
 fmt.Println(items.Name)
}

マルチモジュール構成で開発している場合、ローカル上の他の依存モジュールを参照するためには、go.modファイルにてreplaceディレクティブを使って参照します。この際、ローカル上の複数のモジュールに依存していると、メンテナンスが必要なgo.modファイルが増えて、管理が大変になります。

Workspacesモードの場合

Workspacesモードの場合でも、ディレクトリ構成は非Workspacesモードの場合とほとんど変わりません。違いはgo.workファイルが有るか無いか。

% tree
.
├── go.work
├── items
│   ├── food.go
│   └── go.mod
├── main
│   ├── go.mod
│   └── main.go
└── stores
    ├── go.mod
    └── shop.go

また、go.workファイルが有る場合、go.modファイルにreplaceディレクティブは不要になります。

go 1.18

use (
 ./items // コメントを書いてもOK
 ./main
 ./stores
)
module example.com/main

go 1.18

require example.com/items v0.0.0-00010101000000-000000000000

require example.com/stores v0.0.0-00010101000000-000000000000

ちなみに、非Workspacesモードの場合は、mainディレクトリの親ディレクトリからmain/main.goを実行するとエラーになりますが、

% go run main/main.go 
main/main.go:6:2: no required module provides package example.com/items: go.mod file not found in current directory or any parent directory; see 'go help modules'
main/main.go:5:2: no required module provides package example.com/stores: go.mod file not found in current directory or any parent directory; see 'go help modules'

Workspacesモードの場合は、問題なく実行できます。

% go run main/main.go 
Shop
Food

go workコマンド

Workspacesモードに関するgo workコマンドでできることを紹介します。

init

go work init [ディレクトリ]は、go.workファイルを生成します。

% go work init stores items main
% cat go.work 
go 1.18

use (
 ./items
 ./main
 ./stores
)

edit

go work editコマンドはgo.workファイルを編集するために使います。

go work edit -use [ディレクトリ名]は、go.workファイルのuseディレクティブに追加します。この際、実際に存在しないディレクトリでも追加されてしまうので、追加の際には注意が必要です。

% go work edit -use hoge
% cat go.work           
go 1.18

use (
 ./hoge
 ./items // hoge
 ./main
 ./stores
)

go work edit -dropuse [ディレクトリ名]は、go.workファイルのuseディレクティブから削除します。

% go work edit -dropuse hoge
% cat go.work               
go 1.18

use (
 ./items // hoge
 ./main
 ./stores
)

go work edit -replace [モジュール名]=[パス]は、今までのreplaceディレクティブを作成できます。この際、main/go.modファイルではなく、go.workファイルに追加されます。

% go work edit -replace items=../items
% cat go.work                         
go 1.18

use (
 ./items // hoge
 ./main
 ./stores
)

replace items => ../items

-dropuseと同様に、go work edit -dropreplace [モジュール名]は、replaceディレクティブを削除します。

% go work edit -dropreplace items         
% cat go.work                             
go 1.18

use (
 ./items // hoge
 ./main
 ./stores
)

go work edit -fmtは、go.workファイルをフォーマットしてくれますが、使用していないmoduleパスを削除してくれるような事はありません。

go work edit -printは、go.workファイルを標準出力に表示します。

% go work edit -print
go 1.18

use (
 ./items // hoge
 ./main
 ./stores
)

go work edit -jsonは、go.workファイルをJSON形式で表示します。

% go work edit -json 
{
 "Go": "1.18",
 "Use": [
  {
   "DiskPath": "./items",
   "ModPath": "example.com/items"
  },
  {
   "DiskPath": "./main",
   "ModPath": "example.com/main"
  },
  {
   "DiskPath": "./stores",
   "ModPath": "example.com/stores"
  }
 ],
 "Replace": null
}

sync

go work syncは、ワークスペースのビルドリストにある依存関係を、ワークスペースの各モジュールに同期させるようです。

use

go work use [ディレクトリ]は、go.workファイルにuseディレクティブを追加します。この際、ディレクトリが存在する場合はuseディレクティブを追加し、存在しない場合はディレクトリを削除します。

また、-rフラグが立っている場合は、ディレクトリを再帰的に調べます。

さいごに

マルチモジュールでの開発を便利にするためのWorkspacesモードについて紹介しました。

おすすめ書籍

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: golangGo言語

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前