VSCodeでGolang✖︎Next.jsの開発環境を構築してみた

全般

はじめに

上野です!
最近、GraphQL(Golang)とNext.jsを使用して簡単なWebアプリを作ったりしています。今回はこのGraphQLとNext.jsの簡単 Webアプリを作る中で構築した開発環境をご紹介していきたいと思います。

今回はVSCodeのRemote Containersを使用して構築していきます。
Golang側に関しては、ホットリロード、デバックができるようにし、Next.js側に関してはPrettierなどを入れてより開発がしやすいようにしていきます。

では、早速構築していきます!

フォルダ構成

フォルダ構成は以下のように作成してください。

go-next
|_server
|       |_.devcontainer
|       |           |_devcontainer.json
|       |_.vscode
|       |           |_launch.json
|       |_Dockerfile  
|       |_.air.toml
|       |_main.go
|
|_client
|       |_.devcontainer
|       |           |_devcontainer.json
|       |_Dockerfile  
|
|_docker-compose.yml

docker-compose.ymlには以下のコードを書いてください。

version: '3.8'

services:
  server:
    build:
      context: ./server/
      dockerfile: Dockerfile
      target: dev
    ports:
      - 8888:8080
      - 2345:2345
    volumes:
      - ./server/:/app
  client:
    build:
      context: ./client/
      dockerfile: Dockerfile
      target: dev
    volumes:
      - ./client:/app
    ports:
      - 3434:3000

go-next/server/main.goには以下のコードを書いてください。

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/greeting", func(c *gin.Context) {
		greeting := "hello world"
		c.JSON(200, gin.H{
			"message": greeting,
		})
	})
	r.Run()
}

VSCodeの設定

まずはVSCodeでgo-nextフォルダを開き、Extensionsで「Remote – Containers」をインストールします。

Golang側のVSCodeの設定

go-next/server/.devcontainer/devcontainer.jsonには以下のコードを書いてください。

{
  "name": "Go devcontainer",
  "dockerComposeFile": [
    "../../docker-compose.yml"
  ],
  "service": "server",
  "workspaceFolder": "/app",
  "settings": {
    "go.toolsManagement.checkForUpdates": "off",
    "go.gopath": "/go",
    "go.gocodeAutoBuild": true,
    "go.formatTool": "gofmt",
    "go.useLanguageServer": true,
    "editor.tabSize": 2,
    "editor.formatOnPaste": true,
    "editor.formatOnSave": true,
    "editor.formatOnType": true,
    "editor.renderWhitespace": "all",
    "editor.bracketPairColorization.enabled": true,
    "editor.guides.bracketPairs":"active",
    "files.trimTrailingWhitespace": true,
    "files.trimFinalNewlines": true,
    "emeraldwalk.runonsave": {
    // デバック時、airによって.tmp/mainのプロセスが起動されるので、ファイル保存時に強制的に.tmp/mainのプロセスを削除する
      "commands": [
        {
          "match": ".*",
          "isAsync": false,
          "cmd": "ps aux | grep './tmp/main' | grep -v grep | awk '{ print $1 }' | xargs kill"
        },
      ]
    }
  },
  "extensions": [
    "golang.go",
    "editorconfig.editorconfig",
    "emeraldwalk.runonsave",
    // コードのスペルチェッカー
    "streetsidesoftware.code-spell-checker",
  ],
  "onCreateCommand": "",
  "updateContentCommand": "",
  "postCreateCommand": "",
  "shutdownAction": "none"
}

go-next/server/Dockerfileには以下のコードを書いてください。

FROM golang:1.17-alpine as dev

WORKDIR /app
RUN apk update && apk add git

RUN go install golang.org/x/tools/cmd/goimports@latest \
    && go install golang.org/x/tools/gopls@latest \
    && go install golang.org/x/tools/cmd/godoc@latest \
    && go install golang.org/x/lint/golint@latest \
    && go install github.com/rogpeppe/godef@latest \
    && go install github.com/nsf/gocode@latest \
    # hot relord
    && go install github.com/cosmtrek/air@latest \
    # debug
    && go install github.com/go-delve/delve/cmd/dlv@latest

CMD ["air", "-c", ".air.toml"]

go-next/server/.vscode/launch.jsonには以下のコードを書いてください。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Go",
      "type": "go",
      "request": "attach",
      "mode": "remote",
      "cwd": "${workspaceFolder}",
      "port": 2345,
      "host": "0.0.0.0",
      "showLog": true,
    }
  ]
}

go-next/server/.air.tomlには以下のコードを書いてください。
現在の.ari.tomlはデバック用になっています。デバック用ではなく、普通のホットリロードの状態にしたい場合はDebugとコメントがある下の部分のfull_binをコメントアウトし、Customize binaryとコメントがある下の部分のコメントアウトを解除すると普通のホットリロードの状態に戻ります。

root = "."
tmp_dir = "tmp"

[build]
  bin = "./tmp/main -e=develop"
  cmd = "go build -o ./tmp/main ."
  # It's not necessary to trigger build each time file changes if it's too frequent.
  delay = 1000 # ms
  # Ignore these filename extensions or directories.
  exclude_dir = ["assets", "tmp", "vendor"]
  # Exclude files.
  exclude_file = []
  exclude_regex = []
  exclude_unchanged = false
  follow_symlink = false
  # Customize binary.
  # full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
  # Debug
  full_bin = "APP_ENV=dev APP_USER=air /go/bin/dlv exec ./tmp/main --headless=true --listen=:2345 --api-version=2 --accept-multiclient"
  # Watch these directories if you specified.
  include_dir = []
  # Watch these filename extensions.
  include_ext = ["go", "tpl", "tmpl", "html"]
  # Delay after sending Interrupt signal
  kill_delay = 500 # ms
  # This log file places in your tmp_dir.
  log = "air.log"
  # Send Interrupt signal before killing process (windows does not support this feature)
  send_interrupt = false
  # Stop running old binary when build errors occur.
  stop_on_error = true

[color]
  main = "magenta"
  watcher = "cyan"
  build = "yellow"
  runner = "green"

[log]
  time = false

[misc]
# Delete tmp directory on exit
clean_on_exit = true

Next.js側のVSCodeの設定

client/.devcontainer/devcontainer.jsonには以下のコードを書いてください。

{
  "name": "Next devcontainer",
  "dockerComposeFile": [
    "../../docker-compose.yml"
  ],
  "service": "client",
  "workspaceFolder": "/app",
  "settings": {
    "editor.tabSize": 2,
    "editor.formatOnPaste": true,
    "editor.formatOnSave": true,
    "editor.formatOnType": true,
    "editor.renderWhitespace": "all",
    "editor.bracketPairColorization.enabled": true,
    "editor.guides.bracketPairs":"active",
    "files.trimTrailingWhitespace": true,
    "files.trimFinalNewlines": true,
  },
  "extensions": [
    "xabikos.javascriptsnippets",
    "formulahendry.auto-rename-tag",
    "formulahendry.auto-close-tag",
    "coenraads.bracket-pair-colorizer-2",
    "shardulm94.trailing-spaces",
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint",
    "visualstudioexptteam.vscodeintellicode",
    "foxundermoon.next-js",
    // コードのスペルチェッカー
    "streetsidesoftware.code-spell-checker",
  ],
  "shutdownAction": "none"
}

Next.jsのアプリを作成

docker-compose.ymlファイルが存在するディレクトリ上で以下コマンドを実行しNext.jsのアプリを作成していきます。

docker-compose run --rm client yarn create next-app --typescript

途中で「? What is your project named?」と聞かれるので「app」と入力します。

go-next/clientフォルダ直下に「yarn create next-app」で作成したappフォルダが作成されるので、このappフォルダの中身を./clientフォルダに移動していきます。

mv ./client/app/* ./client/app/.* ./client
rm -r ./client/app

以上でNext.jsの用意が完了しました。

Golang、Next.jsのコンテナにアクセスしてみる

docker-compose.ymlファイルが存在するディレクトリ上で以下コマンドを実行しコンテナを立ち上げます。

docker-compose up -d

では、Golangのコンテナにアクセスしていきます。

GolangのRemote Containerに接続するにはVSCodeの左下のボタンをクリックし「Open Folder in Container」をクリックしgo-next/serverフォルダを選択します。
serverフォルダを選択すると自動でserverのRemote Containerに接続できます。

コンテナ内に入ってgoファイルを作成し、実際にコーディングをしてみてください。開発がしやすくなっているはずです。

Next.js用のコンテナへのアクセスも先程と同様(Golang側)でVSCodeの左下のボタンをクリックし「Open Folder in Container」をクリックしgo-next/clientフォルダを選択することでNext.jsのコンテナにアクセスすることができます。

Next.js側のコンテナも同様にファイル保存時に自動でフォーマットされたりなど開発がしやすくなっているのが分かります。

Golang側のDebugに関しては、Golang側のRemote Containerに接続しVSCodeのサイドメニューから「Run on Debug」をクリックし「Go」と記載してある隣の再生ボタンをクリックするとデバックが開始します。
デバックを開始する際は、.air.tomlファイル内のDebugとコメントアウトがされている下のfull_binという箇所のコメントアウトを解除し、Customize binaryとコメントアウトされている下のfull_binをコメントアウトするようにしてください。

以上でNext.jsとGolangの開発環境の構築は完了です。

まとめ

今回はGolang✖︎Next.jsの開発環境をご紹介しました。今回紹介したRemote Containersを使用しての開発環境ですが、個人ごとにVSCodeの設定をせずに済み、またローカル環境も汚さずに済むのでかなりお勧めです。他にもお勧めの設定方法などがあれば紹介していきます!

今回は以上となります。ありがとうございました!

コメント