Giter Site home page Giter Site logo

a-h / templ Goto Github PK

View Code? Open in Web Editor NEW
6.5K 33.0 210.0 3.86 MB

A language for writing HTML user interfaces in Go.

Home Page: https://templ.guide/

License: MIT License

Go 98.32% Shell 0.13% JavaScript 0.16% HTML 0.98% Nix 0.38% Dockerfile 0.03%
templating-languages ide-support lsp language-server html-elements go hacktoberfest htmx server-side-rendering

templ's Introduction

templ

A HTML templating language for Go that has great developer tooling.

templ

Documentation

See user documentation at https://templ.guide

Go Reference xc compatible Go Coverage Go Report Card

Tasks

build

Build a local version.

go run ./get-version > .version
cd cmd/templ
go build

nix-update-gomod2nix

gomod2nix

install-snapshot

Build and install current version.

# Remove templ from the non-standard ~/bin/templ path
# that this command previously used.
rm -f ~/bin/templ
# Clear LSP logs.
rm -f cmd/templ/lspcmd/*.txt
# Update version.
go run ./get-version > .version
# Install to $GOPATH/bin or $HOME/go/bin
cd cmd/templ && go install

build-snapshot

Use goreleaser to build the command line binary using goreleaser.

goreleaser build --snapshot --clean

generate

Run templ generate using local version.

go run ./cmd/templ generate -include-version=false

test

Run Go tests.

go run ./get-version > .version
go run ./cmd/templ generate -include-version=false
go test ./...

test-cover

Run Go tests.

# Create test profile directories.
mkdir -p coverage/fmt
mkdir -p coverage/generate
mkdir -p coverage/version
mkdir -p coverage/unit
# Build the test binary.
go build -cover -o ./coverage/templ-cover ./cmd/templ
# Run the covered generate command.
GOCOVERDIR=coverage/fmt ./coverage/templ-cover fmt .
GOCOVERDIR=coverage/generate ./coverage/templ-cover generate -include-version=false
GOCOVERDIR=coverage/version ./coverage/templ-cover version
# Run the unit tests.
go test -cover ./... -coverpkg ./... -args -test.gocoverdir="$PWD/coverage/unit"
# Display the combined percentage.
go tool covdata percent -i=./coverage/fmt,./coverage/generate,./coverage/version,./coverage/unit
# Generate a text coverage profile for tooling to use.
go tool covdata textfmt -i=./coverage/fmt,./coverage/generate,./coverage/version,./coverage/unit -o coverage.out
# Print total
go tool cover -func coverage.out | grep total

benchmark

Run benchmarks.

go run ./cmd/templ generate -include-version=false && go test ./... -bench=. -benchmem

fmt

Format all Go and templ code.

gofmt -s -w .
go run ./cmd/templ fmt .

lint

golangci-lint run --verbose

push-release-tag

Push a semantic version number to Github to trigger the release process.

./push-tag.sh

docs-run

Run the development server.

Directory: docs

npm run start

docs-build

Build production docs site.

Directory: docs

npm run build

templ's People

Contributors

a-h avatar a-mesin avatar acaloiaro avatar af-md avatar alehechka avatar alyxpink avatar angaz avatar aranw avatar atifcppprogrammer avatar danderson avatar dougbarrett avatar dvorakluk avatar evan-mai avatar gungun974 avatar headblockhead avatar heyajulia avatar jackielii avatar jamestiberiuskirk avatar joerdav avatar jonnyloughlin avatar kasonbraley avatar mattn avatar michaelbyrne avatar phenpessoa avatar stephenafamo avatar tekagg avatar vo1dwoken avatar vrischmann avatar wdscxsj avatar websymphony avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

templ's Issues

proposal: cumbersome css class API.

I've been using templ to build some web pages, and am using bulma.io for styling. Most css frameworks like this work using thin css classes, so it's not strange to have around 5 classes on an element in some cases.

Currently the templ classes API makes it tough to do this kind of thing dynamically.

If the classes are all static then the following works:

templ Template() {
    <span class="c1 c2 c3 c4"></span>
}

As soon as you want to include a templ css class you need to use templ.Classes:

css customClass() {
    background-color: black;
}

templ Template() {
    <span class={templ.Classes(templ.Class("c1"), templ.Class("c2"), templ.Class("c3"), templ.Class("c4"), customClass())}></span>
}

Proposal 1 - Support 2 class attributes.

Allow strictly one static class attribute and one dynamic (this doesn't work at the moment):

css customClass() {
    background-color: black;
}

templ Template() {
    <span class="c1 c2 c3 c4" class={templ.Classes(customClass())}></span>
}

Proposal 2 - Support spaces in a templ.Class

Allow spaces in a templ.Class this goes against the type as it isn't plural (this doesn't work at the moment):

css customClass() {
    background-color: black;
}

templ Template() {
    <span class={templ.Classes(templ.Class("c1 c2 c3 c4"), customClass())}></span>
}

Proposal 3 - Create an alternative to templ.Classes that takes a string as first parameter.

A new function that supports static classes as a string then variadic templ.Class.

css customClass() {
    background-color: black;
}

templ Template() {
    <span class={templ.SplitClasses("c1 c2 c3 c4", customClass())}></span>
}

Feedback, Inputs & Proposals

I really like templ. I hope it have a great future.
I have made some notes and thoughts while using it which I want to share now - I write it compact, but let's discuss about some points if you want.

1. Pointer Receiver Templates

I commonly use structs as ViewModels. Instead wire up all of those with it's render function manually this could help a lot:

{% templ (x ViewModel) MyTempl() %}

I used this pattern very much in quicktemplate to make all kind of structures "renderable". Currently in templ I have to create a struct method manually and invoke the render function, for every piece of template.

2. Autocompletion

{%! $ %} // cursor

In this scenario a Component is expected. All functions in the current package, which return a Component are possible candidates.

3. Implicit Package selection

This line of code is most time redundant because the package name can be derrived by the directory name.
When using templ on daily basis I forget this line sometimes.
Also, it is not adjusted by the IDE if the name of the package name changes (i.e. the directory name).

{% package my_pkg %}

4. Comments

Comment out quickly some code like {% comment %} in quicktemplate.
What about HTML comment? Or {{/* a comment */}}

5. Alternative START/END-Tag

This point is mabye a matter of taste. On swiss german keyboard, and maybe a lot others, this {% and %} is arduous to write. And you do it a lot when writing templates.
Maybe the {{ and }} which are used in regular go templates is not bad at all.

6. Required Space after START-Tag and before END-Tag

The space after the {% or before the %} took some getting used to. Strict on the one hand, prone to error on the other.
Perhaps the parser could point out this error more clearly - or even autofix it (like go fmt for templ).

7. The Context

A really happy that a context I passed arround the Component Render methods.
This way I can access global data or a localizer helper.
But this is undocumented feature and somehow not so nice.

{% if getUser(ctx) != nil %}
   Username: {% getUser(ctx).Username %}
   Age: {% getLocalizer(ctx).FormatNumber(getUser(ctx).Height) %}
{% endif %}

I have no concrete implementation-idea currently. I make some thoughts...
But in the abstract a shortcut to access a global "struct" variable would do the job.

{% if .user != nil %}
   Username: {% .user.Username %}
   Age: {% .i18n.FormatNumber(.user.Height) %}
{% endif %}

An easier implementation would be:
A pointer to a struct could be passed via context value, while templ make it visible in a variable x.

{% if x.user != nil %}
   Username: {% x.user.Username %}
   Age: {% x.i18n.FormatNumber(x.user.Height) %}
{% endif %}

In both cases the qualified-id must be specified somewhere (for generation and LSP)

Don't get me wrong, I'm not a make it all global type of guy. But it reduces all this argument passtroughts of really important things (i18n, basic user info etc.).
It's just a third source of (typed) data beside receiver variable + argument variables.

8. The Writer

If I'm not mistaken, virtual calls are 5 times slower than direct method calls. And a template calls it thousands of times including the error check.
A benchmark might help.
Maybe it would be interesting to have a look at the implementation of Quicktemplate, where among other things an acquirable byte buffer comes into play.
Another idea would be to be able to define a writer type via CLI argument.
If I manually implement templ components in go, the io.Writer interface is a bit tedious to work with directly.

9. Switch case improvement

Instead:

{% switch p.Type %}
	{% case "test" %}
		<span>{%= "Test user" %}</span>
	{% endcase %}
	{% case "admin" %}
		<span>{%= "Admin user" %}</span>
	{% endcase %}
	{% default %}
		<span>{%= "Unknown user" %}</span>
	{% enddefault %}
{% endswitch %}

What about:

{% switch p.Type %}
	{% case "test" %}
		<span>{%= "Test user" %}</span>
	{% case "admin" %}
		<span>{%= "Admin user" %}</span>
	{% default %}
		<span>{%= "Unknown user" %}</span>
{% endswitch %}

10. Range improvement

Instead:

{% if len(p.Addresses) == 0 %}
   <span>No addresses</span>
{% endif %}
{% for _, v := range p.Addresses %}
	<li>{%= v.City %}</li>
{% endfor %}

What about:

{% for _, v := range p.Addresses %}
	<li>{%= v.City %}</li>
{% default %}
   <span>No addresses</span>
{% endfor %}

This construct is rarely found in template languages. To be honest, I have no idea why.

11. Else-If support

Mabye the switch is a better alternative anyway when it have at least the same capacibilities.

12. Compile a specific file only

Currently recursively all templ files are compiled.
I configured my IDE or modd to autocompile templ files on every change.

Feature request: boolean attributes

HTML supports boolean attributes, see https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes

<hr noshade/>

For true boolean attribute values, the spec states that <hr noshade="noshade"/> can be used.

However, the attribute name must be omitted for false values. <hr noshade=""/> is actually a true value. This makes it impossible for templ to dynamically omit a boolean attribute, because the current design only supports string expressions.

This causes problems for implementing Turbo support because flags such as the boolean attributes disabled and autoscroll are required to be altered based on template parameters.

To resolve this, I propose adding:

  • Support for constant boolean attributes: <hr noshade/> as per HTML.
  • Support for boolean expression attributes: <hr noshade={%= templ.Bool(true) %}/>

Note that the boolean expression attribute value starts with templ.Bool. This would be used in the parser to ensure that the generated code expects a boolean expression at compile time. If this marker wasn't present, then attribute expressions would have to return any type (interface{}) and the generated code would have to check at runtime whether the value was a string or boolean.

One of the goals of templ is to blow up at compile time, not runtime. Supporting an expression that returned anything (e.g. int64, time.Time, big.Rat) would mean checking types at runtime. I don't want to get templ to decide which date format is used on behalf of the developer displaying a date.

css: Support arguments in CSS components

I am attempting build dynamic pie charts using CSS where the percentage would be controlled by a CSS variable calculated on the server. I'm not sure if this can currently be achieved in templ because style attributes do not allow for templ expressions.

Feature request: Introduce context-aware escaping

templ currently uses simple escaping rules, described below:

{% templ Example() %}
<script type="text/javascript">
  {%= "will be escaped using templ.Escape, which isn't JavaScript-aware" %}
</script>
<div onClick={%= "will be escaped using templ.Escape, which isn't JavaScript aware" %}>
  {%= "will be escaped using templ.Escape, which is fine" %}</div>  
</div>
<style type="text/css">
  {%= "will be escaped using templ.Escape, which isn't CSS-aware" %}
</style>
<div style={%= "will be escaped using templ.Escape, which isn't CSS-aware" %}</div>
<div>{%= "will be escaped using templ.Escape, which is fine" %}</div>
<a href={%= "will be escaped using templ.Escape, which isn't hyperlink-aware" %}</div>
{% endtempl %}

This approach is safe when the content being applied to the onClick / on* / style, attributes and script / style element contents are from trusted sources, but if not, they could become attack vectors.

In most cases, developers won't be adding hyperlinks, or populating onClick elements from user-controlled content, but since it's a potential attack vector, it's probably worth making developers explicitly state the safety, despite the extra developer hassle.

templ's element type should be aware of href, on* and style attributes and the contents of script and style tags, and automatically apply context-aware escaping improve the security posture of templ.

In cases where developers need to use content (css, scripts, hyperlinks) from data that's under their control (i.e. not potentially under an attacker's control), they'll need to state that the content is "safe".

Language changes

Option 1 - New string expression operator

This could be done by adding a new context unaware string expression operator that only uses the templ.Escape function, rather than context-aware escaping. The syntax could be:

  • {%!=
  • {%= safe

Option 2 - Force a function call to safehtml

Make the CSS, onClick etc. take appropriate types from https://github.com/google/safehtml and force users to use safehtml.StyleFromConstant method calls.

I think this would be irritating, because it's such a long function call.

Option 3 - Wrap the function call to safehtml

Similar, to above, but create a github.com/a-h/templ/safe package and shorten the calls:

  • {%= safe.Style("background-color: red") %}
  • {%= safe.Script("alert('hello')") %}

Decision

I don't like adding new templ expressions unless really required, so while I like option 1 (particularly the {%!= operator), I think option 3 is the way to go, because it's very clear what's going on even if you've never seen templ before, and there's not many places where developers will actually need to do this (onClick handlers, contents of <script> tags, style attributes).

While it's potentially a breaking change for some users, we're not stable, so I think it's a good change.

turbo-stream elements have ugly formatting

Reformatting turbo-stream elements results in:

{% package templates %}

{% templ Action(action string, target string, template templ.Component) %}
	<turbo-stream action={%= action %} target={%= target %}><template>
	{%! template %}
</template></turbo-stream>
{% endtempl %}

Should be like this:

{% package templates %}

{% templ Action(action string, target string, template templ.Component) %}
	<turbo-stream action={%= action %} target={%= target %}>
		<template>
			{%! template %}
		</template>
	</turbo-stream>
{% endtempl %}

docs: create list of starter projects that use templ

The starter website might have:

  • /scripts - TypeScript or ES6 in here would be transpiled by esbuild.
    • package.json - To enable the use of 3rd party JavaScript packages.
    • default.ts - Will end up in the scripts/dist directory as default.js.
  • /routes
    • /default
      • default.templ - Template for the / page.
      • default.go - HTTP handler for /.
    • /about
      • about.templ - Template for the /about page.
      • about.go - HTTP handler for /about.
    • /register
      • register.templ - Template for the /register page.
      • register.go - HTTP handler for /register.
  • router.go - provides a router.
  • /layout
    • /global
      • page.templ - Overall template
      • header.templ - Header template
      • footer.templ - Footer template
  • /static
    • logo.png - image to include.
  • main.go - Entry point that runs everything as a web server.
  • README.md - includes tasks that demonstrate how to run everything, including templ generate, esbuild operations, hot reload.

Ideally, it would also have a way to output a CDK compatible version for AWS hosting, and maybe include a Github Actions or similar way of building.

Maybe there's a template project builder that can be applied for this purpose?

DOCTYPE declaration causes strangeness in the vscode extension

When creating a .templ file I noticed a very strange thing happening if the layout had a doctype declaration.

For example, this code (which looks like it should be valid to me):

{% package templates %}

{% templ Layout(content templ.Component) %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    {%! content %}
</body>
</html>
{% endtempl %}

{% templ Layout1(content templ.Component) %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    {%! content %}
</body>
</html>
{% endtempl %}

when this was saved in vscode, immediately turns into:

{% package templates %}

i.e. the actual templ declarations were removed.

The actual layout was much more detailed but I distilled it down to the fact that if any templ declaration with a doctype declaration exists in the templ file then all templ declarations are removed, but only if the first templ declaration is the one that contains the doctype. Having the templ declarations the other way round (Layout1 first, followed by Layout) it works fine.

I hope it's just me.

Any ideas?

bug: unexpected behaviour combining conditional attributes with css expressions

Template:

templ tbody(users map[int]user, modified map[int]bool) {
	<tbody id="tbody">
		for k, u := range users {
			<tr class={ row }
				if modified[k] && u.active {
					class={ activate }
				}

				if modified[k] && !u.active {
					class={ deactivate }
				}
				>
				<td></td>
				<td>{ u.name }</td>
				<td>{ u.email }</td>
				<td>
					if u.active {
						Active
					} else {
						Inactive
					}
				</td>
			</tr>
		}
	</tbody>
}

Output:

The result is the css expression activate is not resolved properly, causing a go compile error:
_, err = templBuffer.WriteString(templ.EscapeString(activate()))
cannot use activate (value of type func() templ.CSSClass) as string value in argument to templ.EscapeString

func tbody(users map[int]user, modified map[int]bool) templ.Component {
	....
		for k, u := range users {
			// Element (standard)
			// Element CSS
			var var_7 = []any{row}
			err = templ.RenderCSSItems(ctx, templBuffer, var_7...)
			if err != nil {
				return err
			}
			_, err = templBuffer.WriteString("<tr")
			if err != nil {
				return err
			}
			// Element Attributes
			_, err = templBuffer.WriteString(" class=")
			if err != nil {
				return err
			}
			_, err = templBuffer.WriteString("\"")
			if err != nil {
				return err
			}
			_, err = templBuffer.WriteString(templ.EscapeString(templ.CSSClasses(var_7).String()))
			if err != nil {
				return err
			}
			_, err = templBuffer.WriteString("\"")
			if err != nil {
				return err
			}
			if modified[k] && u.active {
				// Element Attributes
				_, err = templBuffer.WriteString(" class=")
				if err != nil {
					return err
				}
				_, err = templBuffer.WriteString("\"")
				if err != nil {
					return err
				}
				_, err = templBuffer.WriteString(templ.EscapeString(activate()))
				if err != nil {
					return err
				}
				_, err = templBuffer.WriteString("\"")
				if err != nil {
					return err
				}
			}

proposal: change to templ to use single braces

In #35, there's a suggestion that the templ expression start and end token of {% and %} is unwieldy.

Why did we end up with {% / %}?

Initially, when choosing delimiters I was looking for something that was easy to type, reasonable looking, and not likely to show up in code.

I considered double braces {{ but since the standard library, mustache and hugo all use these, and that double braces show up in Go code, I didn't think it would ideal.

I ended up with the {% idea because it isn't valid Go code.

What would be better?

I think a single brace { would be best, because it's the smallest amount of typing, but thought that the complexity of the parser would be high, since I'd have to parse Go code to find the end of statements.

How?

However, I think I've got a solution to remove the need for {% and to drop it to {.

The templ expressions only show up at particular points in the document (e.g. attribute values, within the main document), there's a strong expectation for the expression to be present, meaning that it's less important for the templ start/end token to be globally unique.

If I use a brace instead, the parser can parse until the closing brace. Braces in Go code must be balanced, so any Go code will balance the brace count, however, the parser would need to ignore braces that are within string literals, since they may contain unbalanced braces.

The basic algorithm is:

  • Start with an expression start e.g. { templ and set braceCount = 1
  • Read char
    • If " handle any escaped quotes or ticks until the end of the string.
    • If ``` read until the closing tick.
    • If { or }
      • If { do braceCount++
      • If } do braceCount--
      • If braceCount == 0, break
    • If EOL, break
    • If EOF, break
    • Default: add the char the expression, goto Read char
  • If braceCount != 0 throw an error

I've written an implementation here which shows how expressions can be parsed.

https://gist.github.com/a-h/c7c2a04afd5605c48496e5b346956455

Difference between current and new code

  • Old: {% if findOut(func() bool { return true }) %}

  • New: { if findOut(func() bool { return true }) }

  • Old: {% endif %}

  • New: { endif }

Since the only allowed expression here is a string expression, there's no need to specify the equals sign {%=, making it possible to simplify down by two chars.

  • Old: <a href={%= "https://google.com" %} />
  • New: <a href={ "https://google.com" } />

The same applies here.

  • Old: <div>{%= theData() %}</div>
  • Old: <div>{ theData() }</div>

However, loading a template would still need a specifier:

  • Old: <div>{%! header() %}</div>
  • New: <div>{! header() }</div>

Backwards compatibility

I don't think it's a good idea to break existing code, so I would:

  • Add a templ migrate function which does find and replace in templ files, replacing:
    • {% with {
    • {%= with {
    • {%! with {!
    • %} with }
  • Update templ generate and templ fmt - if they see the old pattern {% in the code, they would stop and print out a suggestion to run templ migrate, explain the reasoning for the change, and point to this issue.

Ecosystem

The templ vim plugin and VS Code plugin would need to be updated. I don't propose maintaining backwards compatibility for these, since the migration will be one way.

Thoughts / feedback?

Is this worth doing?
Any concerns on this migration?
@joerdav - I assume it's not a big job to migrate the vim plugin if I went ahead with this?

Getting multiple error message when parsing a simple templ file

Hi, I have a very simple (copied from the examples) template:

package templates

templ Hello(name string) {
    <div>Hello, { name }</div>
}

Which causes multiple repeating popups when the file in question is in a visible VSCode tab, namely:

[Error - 12:13:45 PM] Request textDocument/hover failed.
  Message: no package metadata for file file:///home/user/Dev/templTest/templates/main.templ
  Code: 0 
[Error - 12:13:46 PM] Request textDocument/semanticTokens/range failed.
  Message: semantictokens are disabled
  Code: 0
[Error - 12:13:46 PM] Request textDocument/semanticTokens/full failed.
  Message: semantictokens are disabled
  Code: 0 
[Error - 12:16:41 PM] Request textDocument/semanticTokens/range failed.
  Message: semantictokens are disabled
  Code: 0 
[Error - 12:16:42 PM] Request textDocument/semanticTokens/full failed.
  Message: semantictokens are disabled
  Code: 0 

These popups happen every time I switch to the template in the editor, and on every change to the templ file in question.

I've installed the VSCode extension and the templ cli application.

Can you think of anything I've missed that would cause this?

proposal: build in hot-reload (templ generate --watch)

The documentation suggests using air - https://templ.guide/commands-and-tools/hot-reload

But it's installing another tool, and having to configure it. Running templ generate --watch would be a better user experience.

It would make #80 irrelevant, since it would be able to maintain internal state such as the last-updated time. https://github.com/fsnotify/fsnotify seems to be the library to use.

Since templ doesn't know how the web server is configured, it can't easily inject client side code to force a refresh.

But... templ could ship with HTTP middleware that implements hot reload. The middleware would be able to set the target directory that contains the templates and use fsnotify to watch it, or figure it the target directory from os.Args, run templ generate and then start a replacement of itself based on the os.Args. Since it's HTTP middleware, it could parse the output HTML and inject stuff into the page.

Alternatively, it could break the problem into two parts... so that templ generate --watch starts a web server on localhost which controls hot reload, and it also ships a middleware component that injects a script to connect to the templ generate --watch port (e.g. http://localhost:14734/) and deals with CORS.

bug: empty string expressions result in syntax error

When writing a templ expression, you may write something like this as a placeholder:

<td>{}</td>

This is generated into Go code as:

// StringExpression
var var_10 string = 
_, err = templBuffer.WriteString(templ.EscapeString(var_10))
if err != nil {
	return err
}

Which results in an error like:

{
  "level": "info",
  "ts": "2023-04-20T09:55:26+01:00",
  "caller": "proxy/client.go:52",
  "msg": "client <- server: PublishDiagnostics: [0]",
  "diagnostic": {
    "range": {
      "start": {
        "line": 270,
        "character": 9
      },
      "end": {
        "line": 270,
        "character": 9
      }
    },
    "severity": 1,
    "source": "syntax",
    "message": "expected '==', found '='"
  }
}

In the case of an empty string expression, the correct behaviour would be to skip generating anything at all, or to use an empty string instead.

proposal: compare document handling logic with vscode-languageserver-node

The vscode-languageserver-node project contains the document type used by the TypeScript and Node.js language server implementations.

This implementations are potentially used by millions of users every day, and are therefore well tested, and may catch some edge cases that are not currently covered.

https://github.com/microsoft/vscode-languageserver-node/tree/main/textDocument

Two proposals:

Feature request: Style attribute support

Support constant attributes

{% templ StaticStyledComponent() %}
  <div style="background-color: red;">{%= "text" %}</div>
{% endtempl %}

Do not allow setting style as a dynamic string

This would not be allowed.

{% templ StyledComponent(backgroundColor string) %}
  <div style={%= "background-color: " + backgroundColor %}>{%= "text" %}</div>
{% endtempl %}

Do not allow the inclusion of any other elements or template items within a style element

This would not be allowed. Only SafeCSS would be allowed here, if anything.

{% templ StyledComponent(css string) %}
  <style type="text/css">
   {%= css %}
  </style>
{% endtempl %}

To render raw CSS, a templ.RawCSS component can be used

Support self-closing tags

Currently attempting to use self closing tags throws an error in some cases.

Case 1:

In this case since the input is the last in the parent element generator seems to allow it and writes a </input> after.

<div>
    <input type="text" name="title" id="title" placeholder="Todo..." />
</div>

Case 2:

In this case as self closing tags exist as children that aren't at the end of the parent an error is thrown:
parsing error: <meta>: mismatched end tag, expected '</meta>', got '</link>'

<head>
    <title>{%= "Hotwire Todo - " + title %}</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.min.css" />
    <script type="module">{%! Raw("import hotwiredTurbo from 'https://cdn.skypack.dev/@hotwired/turbo';") %}</script>
</head>

Parsing error given a large template.

I've generated a large template file for profiling using the following code:

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	file, _ := os.Create("t.templ")
	w := bufio.NewWriter(file)
	t := `
{% templ Fun%I%() %}
	{% for _, p := range "posts" %}
	<div>{%= string(p) %}</div>
	{% endfor %}
	{% if true %}
		<div>true</div>
	{% endif %}
{% endtempl %}`
	w.WriteString("{% package t %}")
	for i := 0; i < 500; i++ {
		w.WriteString(strings.ReplaceAll(t, "%I%", fmt.Sprint(i)))
	}
	w.Flush()
}

When running templ generate I get the following result at Fun52:

$ templ generate
Generated code for 1 templates with 1 errors in 5.724631ms
1 error occurred:
        * t.templ: t.templ parsing error: template expression: missing terminating newline at line 419, col 17 (index 8193)

Implement http.Handler so that templates can be rendered directly

At the moment, to output a template over HTTP, the template has to be wrapped by some boilerplate code.

func main() {
	http.Handle("/posts", PostHandler{})
	http.ListenAndServe(":8000", nil)
}

type PostHandler struct{}

func (ph PostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	posts := []Post{
		{
			Name:   "templ",
			Author: "author",
		},
	}
	err := postsTemplate(posts).Render(r.Context(), w)
	if err != nil {
		log.Println("error", err)
	}
}

If templ components implemented http.Handler, it could be shortened to:

func main() {
	http.Handle("/posts", postsTemplate([]Post{{ Name: "templ", Author: "author"}}))
	http.ListenAndServe(":8000", nil)
}

The component's ServeHTTP method would render a minimal error page, and return a 500 status code if the template failed to render.

In the case that the author of the template wanted to return a non HTTP 200 status code etc. then they'd use HTTP middleware to do it.

func main() {
	http.Handle("/404", withStatus(http.NotFound, errorTemplate404()))
	http.ListenAndServe(":8000", nil)
}

func withStatus(code int, next http.Handler) http.Handler {
	return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(code)
		next.ServeHTTP(w, r)
	})
}

propsal: better support for comments in templ files

Currently, HTML comments and Go comments are not well supported. Would be good to have them as an option.

// Support this comment, don't include anything in the HTML.
/* Do not support this syntax for ... reasons */
<!-- Support this syntax and include it in the output -->

Unable to specify font-family in css block.

Input:

{% css headings() %}
	margin: 0;
	font-family: {%= "Yanone Kaffeesatz" %};
	font-size: 38px;
{% endcss %}

Expected output:

.headings_d997 {
    margin: 0;
    font-family: "Yanone Kaffeesatz";
    font-size: 38px;
}

Actual output:

.headings_d997 {
    margin: 0;
    font-family: zTemplUnsafeCSSPropertyValue;
    font-size: 38px;
}

Remove the t name from the generated Go code

This won't compile:

{% templ Todo(t *todo.Todo) %}
  <div>
    <div>{%= t.Item %}</div>
  </div>
{% endtempl %}

Because there's already a (t templ.Component) return variable.

func Todo(t *todo.Todo) (t templ.Component) {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		_, err = io.WriteString(w, "<div>")
		if err != nil {
   ...

There just doesn't need to be.

question: How to handle conditional html attributes and self closing tags

Hi,

I have a question about tag building. The parser errors on fragments like these:

 <button class="close" type="button" aria-label="Close" data-dismiss="toast"
     if f.DismissAfter > 0 {
          data-delay={ f.DismissAfter.Milliseconds }
     } else {
          data-autohide="false"
     }
  >
      <i class="if if-close"></i>
  </button>

What is the best approach to tag building or handling optional attributes?

I also get parse errors with html 5 self closing tags like link and img if I don't add closing slashes. Is this intentional behaviour?

Thanks for a very promising looking project!

proposal: would templ generate be faster if it skipped generating files that haven't changed?

templ generate is pretty fast. It can generate code for 32 templates in 500ms or so.

Would it be even faster if it only parsed and generated files that have changed instead of doing them all? Or would the effort of maintaining the hash or last updated date of each templ file actually reduce the performance overall?

benchmarks/templ/template.templ complete in 1.027709ms
cmd/templ/lspcmd/httpdebug/list.templ complete in 1.050959ms
cmd/templ/visualize/sourcemapvisualisation.templ complete in 1.000875ms
examples/blog/posts.templ complete in 1.015458ms
examples/hello-world-ssr/hello.templ complete in 253.209ยตs
# snip...
generator/test-text/template.templ complete in 426.833ยตs
generator/test-templ-element/template.templ complete in 493.25ยตs
generator/test-void/template.templ complete in 249.834ยตs
generator/test-text-whitespace/template.templ complete in 996.5ยตs
storybook/_example/templates.templ complete in 410.458ยตs
turbo/stream.templ complete in 399.75ยตs
Generated code for 32 templates with 0 errors in 470.553625ms

Implicit package selection

As noted in #35, templ currently requires a `{% package "packageName" %} at the top of each file.

This is the same behaviour as Go, but to make it faster to write templates, the following approach could be used:

  • Ensure that the parser supports missing package instructions, and inserts them into the object model.
  • Ensure that templ fmt inserts missing package instructions.

The automatic package algorithm:

  • Uses the contents of the package instruction in the *.templ file if there is one.
  • Uses the name of the directory as the package name if it is a valid Go identifier (see https://go.dev/ref/spec#identifier)
  • Uses main as the package if it's not, or a directory context is not available (e.g. parsing a string).

This is simpler than attempting to read any Go files that already exist in the directory.

Feature request: JavaScript sanitisation

Script blocks support

This code:

{% script functionName(a int, b int) %}
  alert(a+b);
{% endscript %}

Will render:

<script>function functionName(a, b){alert(a+b};}</script>

Script blocks should not support script tags at all and should warn to use the {% script %} template instead

{% templ ScriptBlocksNotSupported(script string) %}
  <script type="text/javascript">
    {%= script %}
  </script>
{% endtempl %}

onClick / on* handlers should support constant values as well as {% script %} templates

{% templ BasicTemplate() %}
  <div>
	  <a onClick="alert('hello');">{%= "Say hello" %}</a>
  </div>
{% endtempl %}

Dynamic onClick / on* handlers with templates use sanitised values by forcing the use of {% script %} templates

The Google SafeHTML code describes how this can work: https://github.com/google/safehtml/blob/2057dd9c30f9e264f4d01c29d886d51f1b519302/script.go#L67

The named variables are inserted into the JavaScript template JSON escaped.

To render raw scripts, a templ.RawScript component can be used

This is described in the documentation, but not provided to encourage not doing that.

Feature request: Add text element support

Currently, to output some text, you have to remember to use a variable.

{% templ BasicTemplate() %}
  <div>{%= "Name" %}</div>
{% endtempl %}

I forget sometimes, and write this code:

{% templ BasicTemplate() %}
  <div>Name</div>
{% endtempl %}

And receive the error:

Generated code for 1 templates with 1 errors in 911.881ยตs
1 error occurred:
        * template.templ: template.templ parsing error: <div>: expected end tag not present or invalid tag contents at line 12, col 8 (index 178)

Improving the parser to parse HTML encoded text elements would complicate the code, but make a better developer experience, and lead to simpler templates.

Proposal: templ website and playground

It might be useful to have a templ playground so that people can share snippets of code and try out using templ without having to install it first.

It would need to have the following features:

  • A place to write Go code for the input struct definition, input data, and any helper functions, e.g. date formatting.
  • A place to write a templ file, which will take the input, e.g.:
{% templ Display(in Input) %}
{% endtempl %}
  • Output areas to display the generated HTML code, and the HTML as displayed in the browser.
  • A "Run" button to click to format the code and execute it.
    • Since it's basically going to execute arbitrary code, it would need to run in a Lambda or similar to prevent abuse.
    • Running in a Lambda would require the templ executable to be installed in the Lambda.
  • A "Share" button that creates a shareable web link.
    • This supposes the idea of a backing database, e.g. DynamoDB.

bug: cannot parse complex attributes

The parser cannot parse the complex attributes that are added to enable interactivity with Alpine.js.

Using the starting example from here with the counter example added:

templ Demo() {
  <html>
  <head>
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
  </head>
  <body>
    <h1 x-data="{ message: 'I โค๏ธ Alpine' }" x-text="message"></h1>
    <div x-data="{ count: 0 }">
      <button x-on:click="count++">Increment</button>
      <span x-text="count"></span>
    </div>
  </body>
  </html>
}

Generation results in the following error message:
demo.templ parsing error: boolConstantAttributeParser: expected attribute name to end with space, newline or '/>', but got ":": line 10, col 18

Changing x-on:click to @click will then produce this error message:
demo.templ parsing error: <button>: malformed open element: line 10, col 14

performance: update generation to directly target bytes.Buffer directly

templ is already 7x faster than React according to my benchmarks, but I wanted to see if there was any fat to trim off, so I started out with the current generator.

BenchmarkTempl-10        2651161               446.7 ns/op           288 B/op         11 allocs/op

By commenting out the following lines, I was able to remove 10 allocations. Those allocations happen regardless of whether they're required or not, simply so that there's not a nil value, so it's likely that they could be removed.

func SimpleTempl(u *model.User) templ.Component {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		//ctx, _ = templ.RenderedCSSClassesFromContext(ctx)
		//ctx, _ = templ.RenderedScriptsFromContext(ctx)

That removed 230ns per operation.

BenchmarkTempl-10        4951052               232.6 ns/op            16 B/op          1 allocs/op

Next, I noted that the cost of io.WriteString is significantly more than writing to a bytes.Buffer and that the code can be made approx 2x faster by writing to a bytes.Buffer directly, if the writer is a buffer, or by using a temporary buffer.

By extracting the rendering code into its own function, and switching it to use a bytes.Buffer, I was able to improve the performance.

func SimpleTempl(u *model.User) templ.Component {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		if buf, ok := w.(*bytes.Buffer); ok {
			return SimpleTemplRender(ctx, buf, u)
		}
		buf := new(bytes.Buffer)
		err = SimpleTemplRender(ctx, buf, u)
		if err != nil {
			return
		}
		_, err = io.Copy(w, buf)
		return
	})
}

func SimpleTemplRender(ctx context.Context, buf *bytes.Buffer, u *model.User) (err error) {
	//ctx, _ = templ.RenderedCSSClassesFromContext(ctx)
	//ctx, _ = templ.RenderedScriptsFromContext(ctx)

	// Element (standard)
	_, err = buf.WriteString("<html>")

This removed another 100ns or so from the time.

BenchmarkTempl-10       10625396               101.5 ns/op            16 B/op          1 allocs/op

At this point, it's 4x times faster than before.

However, it's possible to remove the final allocation (it's always good to reduce allocations to reduce the work the GC has to do) by swapping from using the templ.Component and using the generated function instead.

templbench.SimpleTempl(testData).Render(ctx, &buf)
templbench.SimpleTemplRender(ctx, &buf, testData)

That gets the results...

BenchmarkTempl-10       12489266                84.67 ns/op            0 B/op          0 allocs/op

If the generator for components used these functions instead of the templ.Component, overall the performance would be much better.

So, the proposal is to (in order):

  • Remove needless allocations from RenderedScriptsFromContext and RenderedCSSClassesFromContext.
  • Within the existing templ.Component code, use the passed-in bytes.Buffer, or create one and copy it to the io.Writer.
  • Start generating a <TemplateName>Render function for each template that takes the buffer, and update the <TemplateName> function to call it.
  • Update the generator to use the <TemplateName>Render function in preference to using the <TemplateName> function and calling the Render function on the result, to reduce allocations caused by nested components.

decision log: Getting parsed types to render themselves to Go code instead of using a generator

From a given templ file, templ generate writes out Go for each HTML element in a long function.

For example:

<h1>{%= p.name %}</h1>

Becomes:

                _, err = io.WriteString(w, "<h1>")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, templ.EscapeString(p.name))
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, "</h1>")
                if err != nil {
                        return err
                }

Attribute values are also handled:

                _, err = io.WriteString(w, "<div")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, " style=\"font-family: &#39;sans-serif&#39;\"")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, " id=\"test\"")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, " data-contents=")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, "\"")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, templ.EscapeString(`something with "quotes" and a <tag>`))
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, "\"")
                if err != nil {
                        return err
                }
                _, err = io.WriteString(w, ">")
                if err != nil {
                        return err
                }

This executes really fast (although I haven't done a benchmark), but I thought it might be "nicer" to convert the generation of HTML elements get converted into Go code into something like this:

templ.HTMLElement("div").
  Attribute("style", templ.AttributeValue("font-family: &#39;sans-serif&#39;")).
  Attribute("id", templ.AttributeValue("test")).
  Attribute("data-contents", `something with "quotes" and a <tag>`).
  Append(templ.HTMLText("Hello!")).
  Append(templ.HTMLElement("br")).
  Render(ctx, w)

However, this gets ugly when an "if" statement or other child element is required. So I'm not going to pursue this idea any more.

templ fmt: unexpected formatting result.

I have a template, and wanted to run templ fmt on it. I expected the various elements to be put onto more lines, however the opposite happened.

Input template:

{% templ form(action string, t todo, msg string) %}
        <div>
                <p class={%= templ.Classes(invalid()) %}>{%= msg %}</p>
                <form action={%= action %} method="post">
                    <span class={%= templ.Classes(cell()) %}><input type="text" value={%= t.name %} name="name"/></span>
                    <span class={%= templ.Classes(cell()) %}><input type="text" value={%= t.description %} name="description"/></span>
                    <span class={%= templ.Classes(cell()) %}>Done? <input type="checkbox" value="true" name="status" checked?={%= t.status %}/></span> 
                    <span class={%= templ.Classes(cell()) %}><input type="submit" value="Submit"/></span>
                </form>
        </div>
{% endtempl %}

Expected:

I'd expect it to either indent all elements or indent some of them depending on the length of them.

Actual:

{% templ form(action string, t todo, msg string) %}
        <div>
                <p class={%= templ.Classes(invalid()) %}>{%= msg %}</p>
                <form action={%= action %} method="post"><span class={%= templ.Classes(cell()) %}><input type="text" value={%= t.name %} name="name"/></span><span class={%= templ.Classes(cell()) %}><input type="text" value={%= t.description %} name="description"/></span><span class={%= templ.Classes(cell()) %}>Done? <input type="checkbox" value="true" name="status" checked?={%= t.status %}/></span><span class={%= templ.Classes(cell()) %}><input type="submit" value="Submit"/></span></form>
        </div>
{% endtempl %}

proposal: storybook - add select box option for variants

I'm working on a component library for tailwindcss, but I think there's some missing functionaility in the storybook package.

I plan on adding these once templ is upgraded to 1.18 as I think the solution will be different with generics.

Most component libraries have a concept of variants, so having a dropdown for these would be extremely valuable.

<br> tag handling

From the reference

A br element must have a start tag but must not have an end tag.
https://www.w3.org/TR/2011/WD-html-markup-20110113/br.html#br-tags

In templ br is treated as a void tag as per the above tech reference. Adding <br> in the templ file fails to compile. <br/> compiles OK but this is rendered as <br></br> which chrome interprets as a double <br> tag, e.g. <br><br> which creates a double line break.

parse error with templ elements

The following snippet:

templ x() {
	<li>
		<a href="/">
			Home
			@Icon("home", Inline)
		</a>
	</li>
}

gets formatted to become:

templ x() {
	<li><a href="/">
	Home
	@Icon("home", Inline)
</a></li>
}

I don't think this is expected behavior.

Even worse, this code:

templ x() {
	<li><a href="/"> @Icon("home", Inline) Home</a></li>
}

actually just errors out completely with a parsing error:

parsing error: <a>: expected end tag not present or invalid tag contents: line 2, col 0

Improve install process

Hello,

I'm trying to install templ, and I have a couple of suggestions to make it easier to install:

Include an "Install" section in README.md

I might have missed a section, but I didn't see how to install templ from the README, only how to build locally. It can be a really short section, but also really helpful :) If you'd like inspiration, I'm pretty happy with how my Install section turned out.

Make templ easily go installable

I was able to install templ with go install github.com/a-h/templ/cmd, but because the last directory is named cmd, the binary is now named cmd on my system. If you moved it to github.com/a-h/templ/cmd/templ, I would be able to run go install github.com/a-h/templ/cmd/templ and end up with a binary named templ

Use GoReleaser's HomeBrew support

GoReleaser can support generating Homebrew formulas so MacOS users can do something like brew install a-h/tap/templ if they wish. They won't even need GOPATH/bin in their PATH, because Homebrew will manage paths. I use this functionality for a little CLI I wrote and it works well once you get the tap repo and access token build- very much set up and forget. Feel free to take inspiration from my .goreleaser.yml

lsp: textDocument/definition failed

I was able to get an error by playing around in the LSP.

Screenshot 2023-05-05 at 12 53 37

What's happening is that VS Code is asking templ lsp for a definition. templ maintains a map of the code bits of the templ file over to the code bits in the generated Go code.

You can see that if you enable templ.http in your VS Code settings. The setting makes templ start a web server when it runs the LSP to show debug info.

{
    "workbench.colorTheme": "Default Dark+",
    "codesnap.containerPadding": "6em",
    "codesnap.transparentBackground": true,
    "codesnap.backgroundColor": "#ffffff",
    "templ.log": "/Users/adrian/logs/vscode-templ.txt",
    "templ.goplsLog": "/Users/adrian/logs/vscode-gopls.txt",
    "templ.http": "localhost:7575",
    "templ.goplsRPCTrace": true,
    "templ.pprof": false,
    "editor.minimap.enabled": false,
    "[typescript]": {
        "editor.defaultFormatter": "vscode.typescript-language-features"
    },
}

It's even got a UI where you can see the mapping.

Screenshot 2023-05-05 at 13 14 17

In this case, there's no Go code to look up, but templ is passing the request on to gopls anyway. In the logs, I can see this happening because it says "updatePosition: not found".

{"level":"info","ts":"2023-05-05T12:57:02+01:00","caller":"proxy/server.go:371","msg":"client -> server: Definition"}
{"level":"info","ts":"2023-05-05T12:57:02+01:00","caller":"proxy/server.go:67","msg":"updatePosition: not found","uri":"file:///Users/adrian/github.com/a-h/templ/examples/counter/components/components.templ","from":"20:69"}
{"level":"info","ts":"2023-05-05T12:57:02+01:00","caller":"proxy/server.go:379","msg":"client -> server: Definition end"}

gopls is confused by this request to get the definition of something it doesn't know about and returns the error message:

[Error - 13:07:52] Request textDocument/definition failed.
  Message: no identifier found
  Code: 0 

templ should not pass these requests on to gopls, and should return an empty response instead.

I don't think the error message is displayed by Neovim, but is displayed by VS Code, hence not noticing it earlier.

Cannot parse empty attribute

nav.templ:

    1 {% package templates %}
    2 
    3 {% import "container/types" %}
    4 
    5 {% templ NavTemplate(apps []types.AppConfig) %}
    6     <nav data-turbo-permanent>       
    7         <h1>{%= "Go Feed Me" %}</h1>
    8         <ul>
    9             {% for _, a := range apps %}
   10                 <li>
   11                     <a href={%= a.Url %}  data-turbo-frame="container">{%= a.Name %}</a>
   12                 </li>
   13             {% endfor %}
   14         </ul>
   15     </nav>
   16 {% endtempl %}

nav_templ.go (it stops after the imports):

>>  1 // Code generated by templ DO NOT EDIT.
    2 
    3 package templates
    4 
>>  5 import "github.com/a-h/templ"
>>  6 import "context"
>>  7 import "io"
>>  8 import "container/types"

Strangely enough this also fails when I try 'data-turbo-permanent="true"' potentially todo with the dashes aswell?

Tried doing a "valueless" attribute without dashes like "hidden". That also resulted in the same outut.

panic on Windows

On Windows, templ stop working after starting. As far as I looked log file, it seems panic occurred.

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x40 pc=0x96b52c]

goroutine 8 [running]:
github.com/sourcegraph/jsonrpc2.(*Conn).send(0x0, {0xc00009c040, 0xc0000718a0}, 0xc000086330, 0x1)
	C:/Users/mattn/go/pkg/mod/github.com/sourcegraph/[email protected]/jsonrpc2.go:352 +0x6c
github.com/sourcegraph/jsonrpc2.(*Conn).DispatchCall(0x0, {0xa2b078, 0xc000028440}, {0xc0000882d0, 0xa}, {0x98ff20, 0xc00009c040}, {0x0, 0x0, 0x0})
	C:/Users/mattn/go/pkg/mod/github.com/sourcegraph/[email protected]/jsonrpc2.go:449 +0x191
github.com/sourcegraph/jsonrpc2.(*Conn).Call(0x98ff20, {0xa2b078, 0xc000028440}, {0xc0000882d0, 0xc000094020}, {0x98ff20, 0xc00009c040}, {0x990260, 0xc0000b2000}, {0x0, ...})
	C:/Users/mattn/go/pkg/mod/github.com/sourcegraph/[email protected]/jsonrpc2.go:424 +0x72
github.com/a-h/templ/cmd/templ/lspcmd.(*Proxy).proxyInitialize(0xc000028480, {0xa2b078, 0xc000028440}, 0xc0000b0000, 0xc0000aa000)
	C:/Users/mattn/go/pkg/mod/github.com/a-h/[email protected]/cmd/templ/lspcmd/handler.go:230 +0x24b
github.com/a-h/templ/cmd/templ/lspcmd.(*Proxy).Handle(0xc000028480, {0xa2b078, 0xc000028440}, 0x0, 0xc0000aa000)
	C:/Users/mattn/go/pkg/mod/github.com/a-h/[email protected]/cmd/templ/lspcmd/handler.go:196 +0x75d
github.com/sourcegraph/jsonrpc2.(*Conn).readMessages(0xc00014a120, {0xa2b078, 0xc000028440})
	C:/Users/mattn/go/pkg/mod/github.com/sourcegraph/[email protected]/jsonrpc2.go:553 +0x2f8
created by github.com/sourcegraph/jsonrpc2.NewConn
	C:/Users/mattn/go/pkg/mod/github.com/sourcegraph/[email protected]/jsonrpc2.go:334 +0x28c

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.