bon now

ありのままの現実を書き殴る吐き溜め。底辺ITエンジニアの備忘録。
Written by bon who just a foolish IT Engineer.

GoをVSCodeで快適に開発する:golangci-lint + gofumpt テンプレートの作り方

Created Date: 2023/04/10 02:23
Updated Date: 2026/03/04 23:14

Go言語開発をVSCodeで真面目にやり始めて数ヶ月が経った。Linterのセットアップ・ファイル保存時の自動フォーマット・golangci-lintの競合解消など様々なハマりポイントを乗り越えたので、プロジェクトテンプレートとして公開した。

https://github.com/bon10/go-develop-template

このテンプレートが解決すること

VSCodeでGoを書き始めると、以下の問題によくぶつかる。

  • 保存するたびにimport文の順序が変わる(golangci-lintとVSCodeのフォーマッタが競合)
  • linterが大量にあって何を有効にすべきか分からない
  • gofmt だと物足りないが gofumpt のセットアップ方法が分かりにくい
  • golangci-lintのバージョンとGoのバージョンの組み合わせで動かない

このテンプレートはこれらを全部解決済みの状態で使えるようにしてある。

前提環境

  • Go 1.20以上
  • VSCode + Go拡張機能
  • golangci-lint(後述のインストール手順で入れる)

セットアップ手順

1. golangci-lint のインストール

1
2
3
4
5
# macOS
brew install golangci-lint

# Linux / Windows (WSL)
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin

インストール後に golangci-lint --version でバージョンが表示されれば成功。

2. VSCode拡張機能の設定

.vscode/settings.json に以下を追加する。これが保存時自動フォーマットの核心部分。

1
2
3
4
5
6
7
8
9
10
11
{
  "go.lintTool": "golangci-lint",
  "go.lintFlags": ["--fast"],
  "go.formatTool": "gofumpt",
  "[go]": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": "explicit"
    }
  }
}

3. .golangci.yml の設定

linterの設定は .golangci.yml にまとめる。特に重要なのが gofumptmodule-path の指定。これを忘れるとgolangci-lintとVSCodeでフォーマットが競合してしまう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
linters-settings:
  gofumpt:
    lang-version: '1.20'
    module-path: your-module-name  # go.mod の module名を入れる

linters:
  enable:
    - gofumpt
    - golangci-lint
    - errcheck
    - gosimple
    - govet
    - ineffassign
    - staticcheck
    - typecheck
    - unused
  disable:
    # Go バージョンや他linterと競合するものをここでdisable
    - exhaustruct
    - gochecknoglobals

module-path にはプロジェクトの go.mod の先頭行 module xxxxxx を入れる。これがないとgolangci-lintとgoplsでimport文の認識が微妙にズレ、保存/commit のたびに順序が変わる地獄になる。(golangci-lintのドキュメントにちゃんと書いてあるが見落としやすい)

工夫したポイント詳説

Linterとして golangci-lint を採用した理由

golangci-lint は100以上のlinterを内蔵している統合linter。これ1つ入れるだけで errcheckstaticcheckgovet など主要なlinterがまとめて使えるので、個別にインストールする必要がない。

どのlinterが何をチェックするかは以下が網羅的でとても参考になった: golangci-lintを理解する - golangci-lint に搭載されている linter を学ぶ

全linterを有効にすると競合や誤検知が出るので、動かしながらdisableを積み上げていくのが現実的。

gofumpt を採用した理由

標準の gofmt はimportの並び順などを整理してくれるが、ルールが緩め。gofumptgofmt の上位互換で、より厳格なルールでフォーマットしてくれる。チーム開発での「フォーマットのブレ」がなくなる。

gofumpt を使うにはLanguage Serverの gopls を立ち上げる必要があり、golangci-lintとの連携にも .golangci.yml への明示的な設定が必要。これを知らないと「保存するたびにファイルが変わる」という謎バグに悩まされる。

よくあるエラーと対処

「import文がコミットのたびに変わる」.golangci.ymlgofumpt.module-path が設定されていない可能性が高い。go.mod のmodule名を確認して設定する。

「golangci-lintが動かない / タイムアウトする」go.lintFlags: ["--fast"] を追加するとlintチェックを軽量化できる。CIでは --fast なしで、ローカルでは --fast ありにするのがおすすめ。

「gofumptがインストールされていないと言われる」go install mvdan.cc/gofumpt@latest でインストール後、gopls を再起動する。

まとめ

GoのVSCode環境構築でハマりやすいポイントは「golangci-lintとgoplsのフォーマッタ競合」に集約される。.golangci.ymlmodule-path を明示するだけで大半の問題は解決するので、まずここを確認することをおすすめする。

テンプレートをforkして使ってもらえれば、ゼロから設定する手間が省けるはず。

local_offer
folder work

chat_bubble_outline コメントを残す