• This repository has been archived on 21/Apr/2023
  • Stars
    star
    384
  • Rank 107,625 (Top 3 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Coordinate transfer of state from server to client view for isomorphic/universal JavaScript web applications

preboot

NOTE: This package is no longer maintained and is unnecessary with the recent versions of Angular.

The purpose of this library is to help manage the transition of state (i.e. events, focus, data) from a server-generated web view to a client-generated web view. This library works with any front end JavaScript framework (i.e. React, Vue, Ember, etc.), but does have a few extra convenience modules for Angular apps.

The key features of preboot include:

  1. Record and play back events
  2. Respond immediately to certain events in the server view
  3. Maintain focus even page is re-rendered
  4. Buffer client-side re-rendering for smoother transition
  5. Freeze page until bootstrap complete for certain events (ex. form submission)

In essence, this library is all about managing the user experience from the time from when a server view is visible until the client view takes over control of the page.

Installation

cd into your app root and run the following command:

npm i preboot --save

The following sections covers the three different configurations of preboot:

  • Angular Configuration
  • Non-Angular Server Configuration
  • Non-Angular Browser Configuration

Angular Configuration

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { PrebootModule } from 'preboot';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule.withServerTransition({ appId: 'foo' }),
    PrebootModule.withConfig({ appRoot: 'app-root' })
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

The key part here for preboot is to include PrebootModule.withConfig({ appRoot: 'app-root' }) where the appRoot is the selector(s) to find the root of your application. The options you can pass into withConfig() are in the PrebootOptions section below. In most cases, however, you will only need to specify the appRoot.

Non-Angular Server Configuration

import { getInlineDefinition, getInlineInvocation } from 'preboot';

const prebootOptions = {};  // see PrebootRecordOptions section below
const inlineCodeDefinition = getInlineDefinition(prebootOptions);
const inlineCodeInvocation = getInlineInvocation();

// now insert `inlineCodeDefinition` into a `<script>` tag in `<head>` and 
// an `inlineCodeInvocation` copy just after the opening tag of each app root
<html>
  <head>
    <script><%= inlineCodeDefinition %></script>
  </head>
  <body>
    <app1-root>
      <script><%= inlineCodeInvocation %></script>
      <h2>App1 header</h2>
      <div>content</div>
    </app1-root>
    <app2-root>
      <script><%= inlineCodeInvocation %></script>
      <h2>App2 header</h2>
      <span>content</span>
    </app2-root>
  </body>
</html>

Non-Angular Browser Configuration

import { EventReplayer } from 'preboot';

const replayer = new EventReplayer();

// once you are ready to replay events (usually after client app fully loaded)
replayer.replayAll();

PrebootOptions

  • appRoot (required) - One or more selectors for apps in the page (i.e. so one string or an array of strings).
  • buffer (default true) - If true, preboot will attempt to buffer client rendering to an extra hidden div. In most cases you will want to leave the default (i.e. true) but may turn off if you are debugging an issue.
  • minify (deprecated) - minification has been removed in v6. Minification should be handled by the end-user
  • disableOverlay (default true) - If true, freeze overlay would not get injected in the DOM.
  • eventSelectors (defaults below) - This is an array of objects which specify what events preboot should be listening for on the server view and how preboot should replay those events to the client view. See Event Selector section below for more details but note that in most cases, you can just rely on the defaults and you don't need to explicitly set anything here.
  • replay (default true) - The only reason why you would want to set this to false is if you want to manually trigger the replay yourself. This contrasts with the event selector replay, because this option is global

This comes in handy for situations where you want to hold off on the replay and buffer switch until AFTER some async events occur (i.e. route loading, http calls, etc.). By default, replay occurs right after bootstrap is complete. In some apps, there are more events after bootstrap however where the page continues to change in significant ways. Basically if you are making major changes to the page after bootstrap then you will see some jank unless you set replay to false and then trigger replay yourself once you know that all async events are complete.

To manually trigger replay, inject the EventReplayer like this:

import { Injectable } from '@angular/core';
import { EventReplayer } from 'preboot';

@Injectable()
class Foo {
  constructor(private replayer: EventReplayer) {}

  // you decide when to call this based on what your app is doing
  manualReplay() {
    this.replayer.replayAll();
  }
}

Event Selectors

This part of the options drives a lot of the core behavior of preboot. Each event selector has the following properties:

  • selector - The selector to find nodes under the server root (ex. input, .blah, #foo)
  • events - An array of event names to listen for (ex. ['focusin', 'keyup', 'click'])
  • keyCodes - Only do something IF event includes a key pressed that matches the given key codes. Useful for doing something when user hits return in a input box or something similar.
  • preventDefault - If true, event.preventDefault() will be called to prevent any further event propagation.
  • freeze - If true, the UI will freeze which means displaying a translucent overlay which prevents any further user action until preboot is complete.
  • action - This is a function callback for any custom code you want to run when this event occurs in the server view.
  • replay - If false, the event won't be recorded or replayed. Useful when you utilize one of the other options above.

Here are some examples of event selectors from the defaults:

var eventSelectors = [

  // for recording changes in form elements
  { selector: 'input,textarea', events: ['keypress', 'keyup', 'keydown', 'input', 'change'] },
  { selector: 'select,option', events: ['change'] },

  // when user hits return button in an input box
  { selector: 'input', events: ['keyup'], preventDefault: true, keyCodes: [13], freeze: true },
  
  // when user submit form (press enter, click on button/input[type="submit"])
  { selector: 'form', events: ['submit'], preventDefault: true, freeze: true },

  // for tracking focus (no need to replay)
  { selector: 'input,textarea', events: ['focusin', 'focusout', 'mousedown', 'mouseup'], replay: false },

  // user clicks on a button
  { selector: 'button', events: ['click'], preventDefault: true, freeze: true }
];

Using with manual bootstrap (e.g. with ngUpgrade)

Preboot registers its reply code at the APP_BOOTSTRAP_LISTENER token which is called by Angular for every component that is bootstrapped. If you don't have the bootstrap property defined in your AppModule's NgModule but you instead use the ngDoBootrap method (which is done e.g. when using ngUpgrade) this code will not run at all.

To make Preboot work correctly in such a case you need to specify replay: false in the Preboot options and replay the events yourself. That is, import PrebootModule like this:

PrebootModule.withConfig({
  appRoot: 'app-root',
  replay: false,
})

and replay events in AppComponent like this:

import { isPlatformBrowser } from '@angular/common';
import { Component, OnInit, PLATFORM_ID, Inject, ApplicationRef } from '@angular/core';
import { Router } from '@angular/router';
import { filter, take } from 'rxjs/operators';
import { EventReplayer } from 'preboot';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
  constructor(
    private router: Router,
    @Inject(PLATFORM_ID) private platformId: string,
    private appRef: ApplicationRef,
    private replayer: EventReplayer,
  ) {}

  ngOnInit() {
    this.router.initialNavigation();
    if (isPlatformBrowser(this.platformId)) {
      this.appRef.isStable
        .pipe(
          filter(stable => stable),
          take(1),
        ).subscribe(() => {
        this.replayer.replayAll();
      });
    }
  }
}

PrebootComplete

When you are manually replaying events, you often will want to know when Preboot is done replaying events and switching the buffers. To do this, use the following code in your app:

window.document.addEventListener('PrebootComplete', () => {
  // put your code here that you want to run once preboot is complete
});

Adding a nonce

If you're using a CSP, you'll need to add a nonce property to preboot's inline script. Preboot allows you to configure this by exporting an optional PREBOOT_NONCE token. Example usage is as follows (for an Express server):

import {PREBOOT_NONCE} from 'preboot';
import * as express from 'express';
import {v4} from 'uuid';
import * as csp from 'helmet-csp';

const app = express();

app.use((req, res, next) => {
  res.locals.nonce = v4();
  next();
});

app.use(csp({
  directives: {
    scriptSrc: [`'self'`, (req, res) => `'nonce-${ res.locals.nonce }'`],
    ...
  }
});

... express boilerplate ...

/* when it comes time to render the request, we can inject our new token */

app.get('*', (req, res) => {
  res.render('index', {
    req,
    res,
    providers: [
      {
        provide: PREBOOT_NONCE,
        useValue: res.locals.nonce
      }
    ]
  });
});

... other express route handling (see Universal guide for details) ...

Please note that only the nonce tag will appear on the script, the value is not rendered in modern browsers. If you want to make sure your nonce is generating correctly, you can add a callback onto your render method to examine the resultant HTML as follows:

res.render('index', (req, res) => {
  ...
}, function(error, html) {
  console.log(html.substring(0, 50)); // we only care about the top part
  res.send(html);
});

Browser support

If you wish to support Internet Explorer 9-11, you will need to include a Polyfill for CustomEvent.

More Repositories

1

angular

The modern web developerโ€™s platform
TypeScript
91,840
star
2

angular.js

AngularJS - HTML enhanced for web apps!
JavaScript
59,091
star
3

angular-cli

CLI tool for Angular
TypeScript
26,587
star
4

components

Component infrastructure and Material Design components for Angular
TypeScript
24,075
star
5

material

Material design for AngularJS
JavaScript
16,637
star
6

angular-seed

Seed project for angular apps.
JavaScript
13,050
star
7

protractor

E2E test framework for Angular apps
JavaScript
8,780
star
8

angularfire

Angular + Firebase = โค๏ธ
TypeScript
7,595
star
9

flex-layout

Provides HTML UI layout for Angular applications; using Flexbox and a Responsive API
TypeScript
5,911
star
10

universal

Server-side rendering and Prerendering for Angular
TypeScript
4,029
star
11

zone.js

Implements Zones for JavaScript
TypeScript
3,243
star
12

quickstart

Angular QuickStart - source from the documentation
JavaScript
3,128
star
13

angular-phonecat

Tutorial on building an angular application.
JavaScript
3,128
star
14

batarang

AngularJS WebInspector Extension for Chrome
JavaScript
2,444
star
15

material-start

Starter Repository for AngularJS Material
JavaScript
2,214
star
16

universal-starter

Angular Universal starter kit by @AngularClass
TypeScript
2,028
star
17

mobile-toolkit

Tools for building progressive web apps with Angular
JavaScript
1,344
star
18

in-memory-web-api

The code for this project has moved to the angular/angular repo. This repo is now archived.
TypeScript
1,172
star
19

angular.io

Website for the Angular project (see github.com/angular/angular for the project repo)
HTML
1,032
star
20

angular2-seed

TypeScript
1,011
star
21

tsickle

Tsickle โ€” TypeScript to Closure Translator
TypeScript
893
star
22

material.angular.io

Docs site for Angular Components
TypeScript
859
star
23

di.js

Dependency Injection Framework for the future generations...
JavaScript
822
star
24

react-native-renderer

Use Angular and React Native to build applications for Android and iOS
TypeScript
789
star
25

dgeni

Flexible JavaScript documentation generator used by AngularJS, Protractor and other JS projects
TypeScript
770
star
26

angular-cn

Chinese localization of angular.io
Pug
761
star
27

vscode-ng-language-service

Angular extension for Visual Studio Code
TypeScript
757
star
28

router

The Angular 1 Component Router
JavaScript
667
star
29

angular-electron

Angular2 + Electron
TypeScript
610
star
30

devkit

549
star
31

bower-material

This repository is used for publishing the AngularJS Material v1.x library
JavaScript
506
star
32

watchtower.js

ES6 Port of Angular.dart change detection code.
JavaScript
410
star
33

angular-hint

run-time hinting for AngularJS applications
JavaScript
368
star
34

angular-bazel-example

MOVED to the bazel nodejs monorepo ๐Ÿ‘‰
TypeScript
350
star
35

builtwith.angularjs.org

builtwith.angularjs.org
HTML
271
star
36

protractor-accessibility-plugin

Runs a set of accessibility audits
JavaScript
263
star
37

angularjs.org

code for angularjs.org site
JavaScript
260
star
38

angular-update-guide

An interactive guide to updating the version of Angular in your apps
TypeScript
245
star
39

webdriver-manager

A binary manager for E2E testing
TypeScript
227
star
40

bower-angular

Bower package for AngularJS
CSS
224
star
41

angular-ja

repository for Japanese localization of angular.io
HTML
208
star
42

ngSocket

WebSocket support for angular
JavaScript
204
star
43

peepcode-tunes

Peepcode's Backbone.js Music Player Reimplemented in AngularJS
JavaScript
204
star
44

clutz

Closure to TypeScript `.d.ts` generator
Java
163
star
45

benchpress

JavaScript
160
star
46

code.angularjs.org

code.angularjs.org
153
star
47

ngcc-validation

Angular Ivy library compatibility validation project
TypeScript
146
star
48

dgeni-packages

A collection of dgeni packages for generating documentation from source code.
JavaScript
143
star
49

bower-angular-route

angular-route bower repo
JavaScript
143
star
50

atscript-playground

A repo to play with AtScript.
JavaScript
141
star
51

bower-angular-animate

Bower package for the AngularJS animation module
JavaScript
137
star
52

protractor-cookbook

Examples for using Protractor in various common scenarios.
TypeScript
130
star
53

diary.js

Flexible logging and profiling library for JavaScript
JavaScript
127
star
54

bower-angular-i18n

internationalization module for AngularJS
JavaScript
125
star
55

ts-minify

A tool to aid minification of Typescript code, using Typescript's type information.
TypeScript
119
star
56

closure-demo

TypeScript
114
star
57

ngMigration-Forum

109
star
58

material-adaptive

Adaptive template development with Angular Material
JavaScript
101
star
59

watScript

The next generation JavaScript language that will kill ALL the frameworks!
101
star
60

bower-angular-sanitize

angular-sanitize bower repo
JavaScript
99
star
61

code-of-conduct

A code of conduct for all Angular projects
99
star
62

clang-format

Node repackaging of the clang-format native binary
Python
97
star
63

tactical

Data access library for Angular
TypeScript
93
star
64

bower-angular-resource

angular-resource bower repo
JavaScript
92
star
65

dashboard.angularjs.org

AngularJS Dashboard
JavaScript
89
star
66

angular-jquery-ui

jQueryUI widgets wrapped as angular widgets
JavaScript
88
star
67

bower-angular-mocks

angular-mocks.js bower repo
JavaScript
87
star
68

bower-angular-cookies

angular-cookies bower repo
JavaScript
85
star
69

issue-zero

TypeScript
82
star
70

bower-angular-touch

JavaScript
79
star
71

templating

Templating engine for Angular 2.0
JavaScript
76
star
72

a

Library for annotating ES5
JavaScript
67
star
73

material-icons

Common resources for material design in AngularJS
66
star
74

vladivostok

TypeScript
65
star
75

bower-angular-messages

JavaScript
63
star
76

angular-component-spec

Specification for reusable AngularJS components
61
star
77

ci.angularjs.org

ci.angularjs.org CI server scripts
Shell
60
star
78

projects

github reference application for Angular 2.0
JavaScript
58
star
79

dev-infra

Angular Development Infrastructure
JavaScript
57
star
80

code.material.angularjs.org

Documentation site for AngularJS Material
HTML
50
star
81

material-tools

Tools for AngularJS Material
TypeScript
47
star
82

jasminewd

Adapter for Jasmine-to-WebDriverJS
JavaScript
46
star
83

material-update-tool

Standalone update tool for updating Angular CDK and Material
TypeScript
46
star
84

material-builds

Build snapshots for @angular/material
JavaScript
45
star
85

material2-docs-content

Docs content for @angular/material
HTML
37
star
86

benchpress-tree

A reference implementation of a benchpress deep-tree benchmark as seen in Angular
JavaScript
37
star
87

cdk-builds

Angular CDK builds
JavaScript
37
star
88

router-builds

@angular/router build artifacts
JavaScript
36
star
89

angular-ko

HTML
36
star
90

prophecy

Deferred/Promise for AngularJS 2.0
JavaScript
36
star
91

answers-app

TypeScript
36
star
92

assert

A runtime type assertion library.
JavaScript
35
star
93

ngo

TypeScript
34
star
94

protractor-console-plugin

Checks the browser log after each test for warnings and errors
JavaScript
34
star
95

codelabs

31
star
96

introduction-to-angular

TypeScript
31
star
97

microsites

Master repository for sites on the angular.io subdomains (universal.angular.io, material.angular.io, etc)
HTML
29
star
98

core-builds

@angular/core build artifacts
JavaScript
29
star
99

ngtools-webpack-builds

Build artifacts for @ngtools/webpack
JavaScript
28
star
100

service-worker-builds

Build artifacts for @angular/service-worker
JavaScript
27
star