DEV Community

chama-chomo
chama-chomo

Posted on

Setting up neovim for web development in Golang

Since I primarily use Neovim for all my development, configuring my environment for comfortable development of my new web project wasn't a quick task. I've decided to share my experience in hopes that it helps others get started as quickly as possible.

The main topics I want to cover are:

  1. Neovim LSP and Treesitter updates
  2. Templ formatting configuration
  3. TailwindCSS configuration
  4. Enabling HTMX in the project
  5. Setting up file watchers

As for the structure of my project, I simply follow conventions.

Image description

Neovim LSP and Treesitter updates

To make the LSP aware of Templ files, I had to introduce a few changes to the "lspconfig." However, before doing that, I needed to ensure that all the necessary components would be installed automatically. For this, we use Mason:

    ensure_installed = {
        "templ",
        "html",
        "htmx",
        "tailwindcss",
        "html",
        "cssls",
        "efm",
        "gopls",
    },
Enter fullscreen mode Exit fullscreen mode

Now, we are ready to update the 'lspconfig' configuration:

    -- templ
    lspconfig.templ.setup({
        capabilities = capabilities,
        on_attach = on_attach,
    })

    -- html
    lspconfig.html.setup({
        on_attach = on_attach,
        capabilities = capabilities,
        filetypes = { "html", "templ" },
    })

    -- htmx
    lspconfig.htmx.setup({
        on_attach = on_attach,
        capabilities = capabilities,
        filetypes = { "html", "templ" },
    })

    -- tailwindcss
    lspconfig.tailwindcss.setup({
        on_attach = on_attach,
        capabilities = capabilities,
        filetypes = { "templ", "astro", "javascript", "typescript", "react" },
        init_options = { userLanguages = { templ = "html" } },
        settings = {
            tailwindCSS = {
                includeLanguages = {
                    templ = "html",
                },
            },
        },

Enter fullscreen mode Exit fullscreen mode

For proper semantic highlighting provided by Treesitter, I installed the following TS plugins:

ensure_installed = {
            "javascript",
            "go",
            "html",
            "templ",
            "css",
        },
Enter fullscreen mode Exit fullscreen mode

Templ formatting

This was possibly the most complicated part to automate. Through EFM, I was unable to get the LSP to trigger formatting specifically for Templ files (format on save). I suspect this might be because multiple LSP servers are running for Templ files, which may confuse the LSP.

After some struggle, I decided to offload this operation to another plugin called 'conform.'

I installed the 'conform' plugin in my editor.

Below is my 'conform' configuration:

return {
    "stevearc/conform.nvim",
    opts = {
        formatters_by_ft = {
            templ = { "templ" },
        },
    },
    config = function()
        require("conform").setup({
            format_on_save = {
                timeout_ms = 500,
                lsp_format = "fallback",
            },
        })
    end,
}
Enter fullscreen mode Exit fullscreen mode

Once set up, it's time to make 'format on save' for Templ files semi-automatic using 'autocmd.'

Insert the following snippet somewhere in your Lua config:

-- conform format
vim.api.nvim_create_autocmd("BufWritePre", {
    pattern = "*.templ",
    callback = function(args)
        require("conform").format({ bufnr = args.buf })
    end,
})
Enter fullscreen mode Exit fullscreen mode

Originally the pattern part looked like this:
pattern = "*."
However, I experienced some formatting issues in my Go files, so I tried to be more specific. While I'm not convinced that these problems were solely caused by this change, I no longer experience such issues (perhaps it was just a coincidence).

TailwindCSS configuration

As for TailwindCSS, the setup has been quite straightforward. I simply followed the installation manual. Just make sure that 'lspconfig' is aware of 'tailwindcss,' as described in the LSP setup section.

Enabling htmx inside the project

This part is also quite straightforward. To enable HTMX in your project, import the HTMX library from a CDN. In my case, I included it in my base.templ file:

<head>
  <title>MyProject</title>
  <link rel="icon" type="image/x-icon" href="/public/favicon.ico" />
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="/public/styles.css" />
  <script src="https://unpkg.com/htmx.org@1.9.9" defer></script>
</head>
Enter fullscreen mode Exit fullscreen mode

Setting up file watchers

Here’s a refined version of that section:

An important part of the workflow is ensuring that all my edited files are being watched for changes, so that my web project gets updated 'on-the-fly.'

We need to watch for:

  • TailwindCSS changes
  • Go file changes
  • Templ changes

Optionally, you can include all file-watching commands in your Makefile.

.PHONY: build
build: tailwind-build templ-gen
    @go build -o bin/app .

.PHONY: tailwind-watch
tailwind-watch:
    npx tailwindcss -i views/css/app.css -o public/styles.css --watch

.PHONY: tailwind-build
tailwind-build:
    npx tailwindcss -i views/css/app.css -o public/styles.min.css --minify

.PHONY: templ-watch
templ-watch:
    templ generate --watch

.PHONY: templ-gen
templ-gen:
    templ generate
Enter fullscreen mode Exit fullscreen mode

For each part, there is a specific way to set up the watcher.

tailwind watcher

npx tailwindcss -i views/css/app.css -o public/styles.css --watch

For production you might want to run with --minify flag, not --watch

Image description

Go watcher

To detect changes in standard Go files, we can use the 'AIR' tool. Follow the fairly simple AIR manual. Essentially, all I had to do was execute air init inside the project to create the config file, and I updated it if needed. Finally, executing the air command should suffice.

Image description

My configuration for reference:

root = "."
tmp_dir = "tmp"

[build]
  bin = "./tmp/main"
  cmd = "go build -tags dev -o ./tmp/main ."

  delay = 20
  exclude_dir = ["assets", "tmp", "vendor"]
  exclude_file = []
  exclude_regex = [".*_templ.go"]
  exclude_unchanged = false
  follow_symlink = false
  full_bin = ""
  include_dir = []
  include_ext = ["go", "tpl", "tmpl", "templ", "html"]
  kill_delay = "0s"
  log = "build-errors.log"
  send_interrupt = false
  stop_on_error = true

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

[log]
  time = false

[misc]
  clean_on_exit = false
Enter fullscreen mode Exit fullscreen mode

Templ changes

'Templ' tooling provides a convenient way for .templ files monitoring inside your project
templ generate --watch

Image description

For production, you may want to run just templ generate without the --watch flag; otherwise, after running your binary, you might encounter some errors about missing files.

Conclusion

Thank you for reading! If you come across any inaccuracies or if you would like to delve deeper into any topic, please feel free to contact me. I welcome your feedback and insights.

Let me know if you'd like any adjustments!

Top comments (0)