Hydrate App
The hydrate app is a Stencil output target which generates a module that can be used on a NodeJS server to hydrate HTML and implement server side rendering (SSR). This functionality is used internally by the Stencil compiler for prerendering, as well as for the Angular Universal SSR for the Ionic framework. However, like Stencil components, the hydrate app itself is not restricted to one framework.
Note that Stencil does NOT use Puppeteer for SSR or prerendering.
How to Use the Hydrate App
Server side rendering (SSR) can be accomplished in a similar way to
prerendering. Instead of using the --prerender
CLI flag, you can an output
target of type 'dist-hydrate-script'
to your stencil.config.ts
, like so:
outputTargets: [
{
type: 'dist-hydrate-script',
},
];
This will generate a hydrate
app in your root project directory that can be
imported and used by your Node server.
After publishing your component library, you can import the hydrate app into your server's code like this:
import { hydrateDocument, renderToString, streamToString } from 'yourpackage/hydrate';
The hydrate app module exports 3 functions, hydrateDocument
, renderToString
and streamToString
. hydrateDocument
takes a document as its input while renderToString
as well as streamToString
takes a raw HTML string. While hydrateDocument
and renderToString
return a Promise which wraps a result object, streamToString
returns a Readable
stream that can be passed into a server response.
hydrateDocument
You can use hydrateDocument
as a part of your server's response logic before
serving the web page. hydrateDocument
takes two arguments, a
document and a
config object. The function returns a promise with the hydrated results, with
the hydrated HTML under the html
property.
Example taken from Ionic Angular server
import { hydrateDocument } from 'yourpackage/hydrate';
export function hydrateComponents(doc) {
return hydrateDocument(doc)
.then((hydrateResults) => {
// execute logic based on results
console.log(hydrateResults.html);
return hydrateResults;
});
}
hydrateDocument Options
canonicalUrl
- stringconstrainTimeouts
- booleanclientHydrateAnnotations
- booleancookie
- stringdirection
- stringlanguage
- stringmaxHydrateCount
- numberreferrer
- stringremoveScripts
- booleanremoveUnusedStyles
- booleanresourcesUrl
- stringtimeout
- numbertitle
- stringurl
- stringuserAgent
- string
renderToString
The hydrate app also has a renderToString
function that takes an HTML string
and returns a promise of HydrateResults
. The optional second parameter is a
config object that can alter the output of the markup. Like hydrateDocument
,
the hydrated HTML can be found under the html
property.
Example taken from Ionic Core
const results = await hydrate.renderToString(
`<my-component first="Stencil" last="'Don't call me a framework' JS"></my-component>`,
{
fullDocument: false,
serializeShadowRoot: true,
prettyHtml: true,
}
);
console.log(results.html);
/**
* outputs:
* ```html
* <my-component class="hydrated sc-my-component-h" first="Stencil" last="'Don't call me a framework' JS" s-id="1">
* <template shadowrootmode="open">
* <style sty-id="sc-my-component">
* .sc-my-component-h{display:block}
* </style>
* <div c-id="1.0.0.0" class="sc-my-component">
* <!--t.1.1.1.0-->
* Hello, World! I'm Stencil 'Don't call me a framework' JS\n" +
* </div>
* </template>
* <!--r.1-->
* </my-component>
* ```
*/
renderToString Options
approximateLineWidth
Type: number
Determines when line breaks are being set when serializing the component.
prettyHtml
Default: false
Type: boolean
If set to true
it prettifies the serialized HTML code, intends elements and escapes text nodes.
removeAttributeQuotes
Type: boolean
Default: false
If set to true
it removes attribute quotes when possible, e.g. replaces someAttribute="foo"
to someAttribute=foo
.
removeEmptyAttributes
Type: boolean
Default: true
If set to true
it removes attribute that don't have values, e.g. remove class=""
.
removeHtmlComments
Type: boolean
Default: false
If set to true
it removes any abundant HTML comments. Stencil still requires to insert hydration comments to be able to reconcile the component.
beforeHydrate
Type: (document: Document, url: URL) => <void> | Promise<void>
Allows to modify the document and all its containing components to be modified before the hydration process starts.
afterHydrate
Type: (document: Document, url: URL, results: PrerenderUrlResults) => <void> | Promise<void>
Allows to modify the document and all its containing components after the component was rendered in the virtual DOM and before the serialization process starts.
serializeShadowRoot
Default: true
Type: boolean
If set to true
Stencil will render a component defined with a shadow: true
flag into a Declarative Shadow DOM, e.g.:
const results = await hydrate.renderToString(
`<my-component first="Stencil" last="'Don't call me a framework' JS"></my-component>`,
{
fullDocument: false,
serializeShadowRoot: true,
prettyHtml: true,
}
);
console.log(results.html);
/**
* outputs:
* ```html
* <my-component class="hydrated sc-my-component-h" first="Stencil" last="'Don't call me a framework' JS" s-id="1">
* <template shadowrootmode="open">
* <style sty-id="sc-my-component">
* .sc-my-component-h{display:block}
* </style>
* <div c-id="1.0.0.0" class="sc-my-component">
* <!--t.1.1.1.0-->
* Hello, World! I'm Stencil 'Don't call me a framework' JS
* </div>
* </template>
* <!--r.1-->
* </my-component>
* ```
*/
When set to false
, the component renders with its light DOM but delays hydration until runtime.
const results = await hydrate.renderToString(
`<my-component first="Stencil" last="'Don't call me a framework' JS">👋</my-component>`,
{
fullDocument: false,
serializeShadowRoot: false,
prettyHtml: true,
}
);
console.log(results.html);
/**
* outputs:
* ```html
* <my-component class="hydrated" first=Stencil last="'Don't call me a framework' JS" s-id=1>