Skip to content

sergei-svistunov/go-ssr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoSSR: Go Generator for HTML Server-Side Rendering

GoSSR is a Go-based tool that simplifies the development of web applications by generating http.Handler implementations. It leverages your project's directory structure to define routing and uses HTML templates for efficient server-side rendering (SSR).

Key features

  • Directory-based routing: Define web routes based on your project’s folder structure. Folders with leading and trailing underscores (e.g., _userId_) are interpreted as dynamic URL parameters, accessible via the UrlParam method in the request object.
  • HTML template rendering: Transform HTML templates into Go code, enabling fast, type-safe server-side rendering.
  • Dynamic URL parameters: Use folder names to define dynamic parts of URLs, which are passed as parameters to the corresponding handlers.
  • Data providers: Automatically generate interfaces that allow injecting custom application logic into handlers via RouteDataProvider.
  • Static asset management: Seamlessly integrate with gossr-assets-webpack-plugin to manage static assets (CSS, JavaScript, images) and dynamically replace paths with hashed filenames.
  • Automatic rebuild: Watches for file changes, rebuilding assets and templates as needed, and automatically restarts the project.

It's very fast

The example below shows how you can benchmark SSR handler performance:

var (
    ssrHandler = ctxMiddleware{
        pages.NewSsrHandler(
            web.NewDataProvider(&model.Model{}), mux.Options{},
        ),
    }
    req1    = httptest.NewRequest(http.MethodGet, "/home", nil)
    req2    = httptest.NewRequest(http.MethodGet, "/users/johndoe123/info", nil)
    dw      = DiscardWriter{}
)

func BenchmarkSsrHandlerSimple(b *testing.B) {
    for i := 0; i < b.N; i++ {
        ssrHandler.ServeHTTP(dw, req1)
    }
}

func BenchmarkSsrHandlerDeep(b *testing.B) {
    for i := 0; i < b.N; i++ {
        ssrHandler.ServeHTTP(dw, req2)
    }
}

Results:

goos: linux
goarch: amd64
pkg: github.com/sergei-svistunov/go-ssr/example/internal/web/pages
cpu: AMD Ryzen 7 5800H with Radeon Graphics         
BenchmarkSsrHandlerSimple
BenchmarkSsrHandlerSimple-16    	  432955	      2343 ns/op
BenchmarkSsrHandlerDeep
BenchmarkSsrHandlerDeep-16      	  164113	      7131 ns/op

Installation

To install GoSSR, run:

go install github.com/sergei-svistunov/go-ssr@latest

Usage

Initialize a new project

To initialize a new project, run the generator in your project directory:

go-ssr -init -pkg-name <appname>

This generates a boilerplate for your application.

Generate GoSSR files

Run the generator to create the necessary SSR files:

go-ssr

Automatically rebuild the project

Run the generator in watch mode to automatically rebuild your project when changes are detected:

go-ssr -watch

Building static files in production mode

Just add the argument -prod:

go-ssr -prod

GoSSR config

The config for the current project is in the gossr.yaml file with the following structure:

type Config struct {
  WebDir           string            `yaml:"webDir"`           // Directory containing SSR handlers and templates
  WebPackage       string            `yaml:"webPackage"`       // Full path to the web package
  GoRunArgs        string            `yaml:"goRunArgs"`        // Arguments for `go run`
  Env              map[string]string `yaml:"env"`              // Environment variables
  GenDataProviders bool              `yaml:"genDataProviders"` // Enable basic DataProviders implementation generation (experimental)
}

Project structure

Create a directory for all GoSSR files, such as internal/web. This directory must include:

  • pages/: Contains routes, GoSSR templates, TypeScript, and SCSS files. Each subdirectory is a route. Key files include:
    • index.html: Required, the page template.
    • index.ts: Optional, the page script.
    • styles.scss: Optional, the page's CSS styles.
    • ssrhandler_gen.go: Auto-generated, only in pages directory, contains common DataProvider interface and SSR router constructor.
    • ssrroute_gen.go: Auto-generated, defines route DataProvider interface and code for rendering templates.
  • package.json: Contains JS and CSS dependencies.
  • tsconfig.json: TypeScript configuration.
  • webpack.config.js: Webpack configuration for building static assets.
  • webpack-assets.json: Auto-generated file with asset information.

Static asset management

GoSSR integrates with Webpack for managing JavaScript, CSS, and images using the gossr-assets-webpack-plugin. Key features include:

  • JavaScript & styles: The plugin automatically includes index.ts and styles.scss as entry point dependencies if they exist in the directory.
  • Image management: Images are copied to the /static folder, and their paths are updated to use hashed filenames. For example:
<img src="./logo.png">
<!-- becomes -->
<img src="/static/images/logo.<hash>.png">

Template syntax

Expressions

GoSSR templates support expressions for inserting dynamic data between HTML tags or within attributes. For example:

<p>Some text: {{ textValue }}</p>
<span class="name {{ dynamicClass }}">Text</span>

Operators

Supported operators include:

  • Arithmetic: +, -, *, /, %
  • Comparisons: ==, !=, <, <=, >, >=
  • Logical: &&, ||, !
  • Accessors: . for struct fields, [] for arrays
  • Function calls: funcName(arg1, arg2, ...)
  • Ternary if: <boolean expression> ? <true value> : <false value>

Example:

<p>Sum: {{ a + b }}</p>
<p>Age: {{ user.Age >= 18 ? 'Adult' : 'Minor' }}</p>

Declaring variables

Variables in GoSSR templates must have explicitly defined types. Declare them using the following syntax:

<ssr:var name="varName" type="varType"/>

Embedding content

For routes with nested sub-routes, use the <ssr:content/> tag to embed child templates. You can also specify a default child route using the default attribute:

<ssr:content default="/info"/>

Conditional rendering

Render elements conditionally using ssr:if, ssr:else-if, and ssr:else attributes:

<span ssr:if="user.Age <= 18">0-18</span>
<span ssr:else-if="user.Age <= 30">19-30</span>
<span ssr:else>60+</span>

Loops

Use loops to iterate over arrays:

<ul>
    <li ssr:for="phone in phones">{{ phone }}</li>
</ul>

With an index variable:

<p ssr:for="i, phone in phones">{{ i }}: {{ phone }}</p>

Example

For a working example, refer to the example folder. It demonstrates directory-based routing, template embedding, dynamic URL parameters, and asset management with Webpack.

Contributing

Contributions are welcome! Feel free to submit pull requests for new features, bug fixes, or improvements to documentation.

License

GoSSR is licensed under the MIT License. See the LICENSE file for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published