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).
- 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 theUrlParam
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.
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
To install GoSSR, run:
go install github.com/sergei-svistunov/go-ssr@latest
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.
Run the generator to create the necessary SSR files:
go-ssr
Run the generator in watch mode to automatically rebuild your project when changes are detected:
go-ssr -watch
Just add the argument -prod
:
go-ssr -prod
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)
}
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 inpages
directory, contains commonDataProvider
interface and SSR router constructor.ssrroute_gen.go
: Auto-generated, defines routeDataProvider
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.
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
andstyles.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">
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>
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>
Variables in GoSSR templates must have explicitly defined types. Declare them using the following syntax:
<ssr:var name="varName" type="varType"/>
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"/>
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>
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>
For a working example, refer to the example folder. It demonstrates directory-based routing, template embedding, dynamic URL parameters, and asset management with Webpack.
Contributions are welcome! Feel free to submit pull requests for new features, bug fixes, or improvements to documentation.
GoSSR is licensed under the MIT License. See the LICENSE file for details.