gomponents icon indicating copy to clipboard operation
gomponents copied to clipboard

Convert HTML to Gomponents

Open amrojjeh opened this issue 1 year ago • 3 comments

This is my attempt to solve #167. I didn't use x/net/html because... well I forgot to look into it. The XML parser in the standard library seems to work fine though once configured to parse HTML.

The way I decided to format the output was as such:

  • Attributes are on the same line
  • g.Text and other elements take up a new line
  • Whitespace is ignored
  • Tabs are used instead of spaces (as per Go's standard)
  • It's standard to have one "page" per file, so this code outputs an entire new file with the imports and the package (default "ui") rather than outputting a single function

Here's an example:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<p>How are you doing?</p>
	<unknown required data-crazy="lol">wow</unknown>
	<a aria-hidden="true" data-wow="some field" unrecognized="crazy" anotherunrecognized></a>
	<form action="/test" method="get">
		<input type="text" required>
	</form>
</body>
</html>
package ui

import (
	g "github.com/maragudk/gomponents"
	. "github.com/maragudk/gomponents/html"
)

func Page() g.Node {
	return Doctype(
		HTML(Lang("en"),
			Head(
				Meta(Charset("UTF-8")),
				Meta(Name("viewport"), Content("width=device-width, initial-scale=1.0")),
				TitleEl(
					g.Text("Document"),
				),
			),
			Body(
				P(
					g.Text("How are you doing?"),
				),
				g.El("unknown", Required(), Data("crazy", "lol"),
					g.Text("wow"),
				),
				A(Aria("hidden", "true"), Data("wow", "some field"), g.Attr("unrecognized", "crazy"), g.Attr("anotherunrecognized", "anotherunrecognized")),
				Form(Action("/test"), Method("get"),
					Input(Type("text"), Required()),
				),
			),
		),
	)
}

(Note: the output contains trailing commas, not seen here, but these are easily removed by running go fmt, which is integrated into most editors)

Usage: go run . (-p PACKAGE NAME) [html file]

There is still lots of work left, such as integrating SVG and HTMX, running automated tests, supporting globbing, but I think this lays a good foundation.

Apologize for the older commits as well. I had an older fork of this repo and I didn't know how to squash them excerpt by deleting my fork and starting a new one, and at that point I had already started working on it.

Feel free to move this off of main.

amrojjeh avatar Jun 23 '24 05:06 amrojjeh

Tests are failing because I accidentally used go 1.20 features :skull: (strings.CutPrefix). I'll let you decide if you want to upgrade or if we should stick to go1.18

amrojjeh avatar Jun 23 '24 06:06 amrojjeh

Hey @amrojjeh, thanks for having a go at this! I'll see if I can get around to having a look at it before the start of my summer holidays at the end of this week. 😊

markuswustenberg avatar Jun 25 '24 11:06 markuswustenberg

Note to self: Go code can be formatted with https://pkg.go.dev/go/format

amrojjeh avatar Jun 26 '24 19:06 amrojjeh

Hi @amrojjeh . Thanks again for having a go at this!

Since then, @PiotrKowalski made an online version at https://htg.piotrkowalski.me, with source available at https://github.com/PiotrKowalski/html-to-gomponents . I think I'm going with pointing to that for now, since it's the least amount of work for me and looks like it's working fine. If I'm adding anything to the core library, I'd have to make sure to understand it and be responsible for maintaining it, and unfortunately I don't want to take that on right now.

But perhaps it would make sense for you to publish this as an independent CLI tool?

markuswustenberg avatar Sep 05 '24 08:09 markuswustenberg