π Run your App#
To run your app, use the runApp
function and provide your root component.
runApp(MyComponent());
This function works both on the client and on the server when you use server-side rendering.
-
On the server this starts a http server that renders the given component to html for every incoming request.
-
On the client this attaches the given component to the DOM and thereby making your app interactive.
Let's look at a simple example on how this works in practice. A minimal file structure looks like this:
βββ lib/
β βββ app.dart
β βββ main.dart
βββ web/
βββ main.dart
This consists of
-
an
lib/app.dart
with anApp
component that we want to use both for server-side rendering and client-side hydration, -
a
lib/main.dart
file that is the entrypoint on the server for our app// Server-specific import import 'package:jaspr/server.dart'; // Our main component import 'app.dart'; void main() { // Starts the server and renders the app component runApp( // Special component that sets up the main document tags // like <html>, <head>, and <body>. // More on this later Document( // Links to the `web/main.dart` file. scriptName: 'main', // Renders the component inside the <body> tag body: App(), ), ); }
-
a
web/main.dart
file that is the entrypoint on the client for our app// Client-specific import import 'package:jaspr/browser.dart'; // Our main component import 'lib/app.dart'; void main() { // Attaches the app component to the <body> tag // and hydrates the component / makes it interactive. runApp(App(), attachTo: 'body'); }
It is important that you attach your component on the client to the same location in the tree where you rendered it on the server. This does not need to be <body>, but must be the same.
π The Document#
The Document
component helps you to set up a basic document structure at the root of your app.
It renders the main <html>
, <head>
and <body>
tags and takes a set of standard parameters,
e.g. to set the title
or meta
attributes inside the <head>
.
The Document
component can only be used on the server and is therefore also only available using the
package:jaspr/server.dart
import.
The standard Document
constructor takes the following arguments:
String? title
: Sets the title of your website.String? base
: Sets the<base>
tag of your website.String? charset
: Sets the charset, defaults to 'utf-8'.String? viewport
: Sets the viewport for mobile devices, defaults to 'width=device-width, initial-scale=1.0'.Map<String, String>? meta
: Sets additional<meta>
properties.List<StyleRule>? styles
: A global set of style-rules, rendered as a<style>
section inside<head>
.String? scriptName
: The name of the script that corresponds to your web entrypoint, e.g.main
forweb/main.dart
.List<Component> head
: Additional components to render inside<head>
.Component body
: The component to render inside<body>
.
There are also one other constructors that you can use instead:
-
Document.file() where you can use an external html file that defines the document markup.
See the
classic
template for an example setup.
βClient Components#
With the previous approach you have to set up and link the entrypoints for the client manually.
However, jaspr can also do that for you using the @client
annotation.
Annotate a component that you want to be shipped and hydrated on the client with @client
like this:
import 'package:jaspr/jaspr.dart';
// marks this as a client component
@client
class App extends StatelessComponent {
@override
Iterable<Component> build(BuildContext context) sync* {
yield ...;
}
}
When you use the @client annotation, your web entrypoints will be automatically generated and used in your
server-rendered markup. Therefore, you don't need to have a web/main.dart
file and don't need to set Document.scriptName
.
Additionally, in your main.dart
modify the code to call Jaspr.initializeApp()
before runApp()
:
import 'package:jaspr/server.dart';
// will be generated by jaspr
import 'jaspr_options.dart';
void main() {
Jaspr.initializeApp(options: defaultJasprOptions);
runApp(Document(...));
}
Using this component in your server-rendered application anywhere in the tree under Document()
will
automatically set up this component also on the client.
You can also have multiple components annotated with @client
to have separate interactive 'islands' on the client.
However, nesting client components is currently not possible.