Views
Before rendering views you need to assign a rendering function to your server.
This rendering function is used to render views when invoking send.View()
.
You can choose between two types of rendering functions: csr
and ssr
.
Csr Function
Section titled “Csr Function”The csr function simply reads the contents of your index.html
, injects the view properties into the document and returns the result.
You can create a csr function using csr.New()
.
package main
import ( "embed" "main/lib/core/server" "main/lib/core/view/csr" "os")
//go:embed app/distvar efs embed.FSvar srv = server.New()var dev = os.Getenv("DEV") == "1"var render = csr.New(ssr.Config{ Efs: efs, Disk: dev })
func main() { defer server.Start(srv) srv.Render = render srv.Efs = efs}
Ssr Function
Section titled “Ssr Function”The ssr function uses a JavaScript engine in order to render svelte components on the fly and returns the result.
You can create an ssr function using ssr.New()
.
package main
import ( "embed" "main/lib/core/server" "main/lib/core/view/ssr" "os")
//go:embed app/distvar efs embed.FSvar srv = server.New()var dev = os.Getenv("DEV") == "1"var render = ssr.New(ssr.Config{Efs: efs, Disk: dev})
func main() { defer server.Start(srv) srv.Render = render srv.Efs = efs}
What are views?
Section titled “What are views?”Views are svelte components exported by
app/exports.server.ts
and/or app/exports.client.ts
.
Directoryapp
- exports.client.ts
- exports.server.ts
- …
Server Exports
Section titled “Server Exports”Views that are meant to be rendered on the server should be exported by app/exports.server.ts
.
import Welcome from '$lib/views/Welcome.svelte'import Profile from '$lib/views/Profile.svelte'
export const views = { // Defines that components "Welcome" and "Profile" // can be rendered on the server when sent with send.View(). "Welcome": Welcome, "Profile": Profile,}
Client Exports
Section titled “Client Exports”Views that are meant to be rendered on the client should be exported by app/exports.client.ts
.
export const views = { // Defines that components "Welcome" and "Profile" // can be bundled and rendered on the client when // sent with send.View(). "Welcome": import('$lib/views/Welcome.svelte'), "Profile": import('$lib/views/Profile.svelte'),}
These views are being imported asynchronously in order to split them in different bundles, however you can simply create fake promises in order to bundle them all together and eliminate network latency when transitioning between view.
import Welcome from '$lib/views/Welcome.svelte'import Profile from '$lib/views/Profile.svelte'
export const views = { "Welcome": Promise.resolve(Welcome), "Profile": Promise.resolve(Profile),}
Keys in app/exports.server.ts
and app/exports.client.ts
are not mutually exclusive.
You can render the same component on both the server and the client at the same time.
See Render Modes below.
Send Views
Section titled “Send Views”Use send.View()
to send a view.
package lib
import ( "main/lib/core/client" "main/lib/core/send" "main/lib/core/view")
func View(c *client.Client) { send.View(c, view.View{Name: "Welcome"}) // Sends view "Welcome".}
The Name of the view will be used to lookup the view component exported by app/exports.server.ts and/or app/exports.client.ts.
Default View
Section titled “Default View”There is no way to specify a “default view”.
However, you can use send.FileOrElse()
in order to send the requested file or run custom logic if it doesn’t exist.
package lib
import ( "main/lib/core/client" "main/lib/core/send" "main/lib/core/view")
func View(c *client.Client) { send.FileOrElse(c, func () { // Attempts to send requested file, or else... send.View(c, view.View{Name: "Welcome"}) // ...sends view "Welcome". })}
Usually you would map this handler to the default GET /
pattern, which automatically captures
all unmatched requests.
package main
import ( "embed" "main/lib/core/client" "main/lib/core/server")
//go:embed app/distvar efs embed.FSvar srv = server.Default(efs) // Creates server config.var route = route.Route{ // Creates route. Pattern: "GET /", // Sets route pattern. Handler: welcome.View, // Sets route handler.}
func main() { defer server.Start(srv) // Starts the server. srv.Routes = append(srv.Routes, route) // Adds the route to the server.}
View Properties
Section titled “View Properties”Optionally, you can specify properties for your View
with the Props
field.
package lib
import ( "main/lib/core/client" "main/lib/core/send" "main/lib/core/view")
func View(c *client.Client) { send.View(c, view.View{ // Sends view. Name: "Welcome", // Sets view name. Props: map[string]string{ // Sets view props, which will be injected into the svelte component. "name": "world", // Adds property "name" with value "world". }, })}
These properties are passed down to your view component.
<script lang="ts"> type Props = { name: string } let {name}:Props = $props() // Retrieves view props.</script>
<h1>Hello {name}</h1>
View properties are initialized with $state() and thus are reactive by default.
You can also use getContext(“view”) to retrieve your properties.
<script lang="ts"> import type { View } from "$lib/scripts/core/types.ts" const view = getContext("view") as View<{ name: string }> // Retrieves the same server props, // but can be used anywhere in the project // regardless of the component hierarchy.</script>
<h1>Hello {view.props.name}</h1>
view
is initialized with $state() and thus is reactive.
Render Modes
Section titled “Render Modes”You can choose how to render views with the RenderMode
property.
RenderFull
Section titled “RenderFull”Using RenderFull
, the view is rendered on both the server and the client.
This is the default mode.
package lib
import ( "main/lib/core/client" "main/lib/core/send" "main/lib/core/view")
func View(c *client.Client) { send.View(c, view.View{ // Sends view. Name: "Welcome", // Sets view name. RenderMode: view.RenderModeFull, // Renders view on server and client. })}
Requires an ssr function.
RenderServer
Section titled “RenderServer”Using RenderServer
, the view is rendered only on the server.
You’ll have to deal away with apis such as fetch;
your new best friend is form.
package lib
import ( "main/lib/core/client" "main/lib/core/send" "main/lib/core/view")
func View(c *client.Client) { send.View(c, view.View{ // Sends view. Name: "Welcome", // Sets view name. RenderMode: view.RenderModeServer, // Renders view only on server. })}
Requires an ssr function.
While using RenderServer
the view won’t serve a JavaScript bundle,
but you can still use the <svelte:head>
special
tag in order to load scripts dynamically.
<svelte:head> <script type="text/javascript" src="https://some.cdn/file.js" /></svelte:head>
RenderClient
Section titled “RenderClient”Using RenderClient
, the view is rendered only on the client by loading a JavaScript bundle asynchronously.
package lib
import ( "main/lib/core/client" "main/lib/core/send" "main/lib/core/view")
func View(c *client.Client) { send.View(c, view.View{ // Sends view. Name: "Welcome", // Sets view name. RenderMode: view.RenderModeClient, // Renders view only on client. })}
You can combine any of these render modes with adaptive hyperlinks and forms. Read more about web standards.
Why use Csr Function at all?
Section titled “Why use Csr Function at all?”Since the ssr function supports all rendering modes, you might ask yourself why bother using a csr function at all?
When using a csr function, the server-side JavaScript engine is completely eliminated from your final binary, reducing its size from a minimum of 24MB, to a minimum of 10MB.