LogoJaspr

πŸš€ 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.

  1. On the server this starts a http server that renders the given component to html for every incoming request.

  2. 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 an App 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 for web/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.