Files
meteor/packages/server-render/server-sink.js
Ben Newman fb73388ce3 Make server-render API more flexible and isomorph-ish.
Render callbacks can now inject HTML content into multiple different
elements, and may also append content to the <head> or <body> elements, on
both the client and the server.

This new API was inspired by trying to use the styled-components npm
package on the server, which involves not only rendering and injecting
static HTML somewhere in the <body>, but also appending the resulting
<style> tag(s) into the <head>:

  import { onPageLoad } from "meteor/server-render";
  import { renderToString } from "react-dom/server";
  import { ServerStyleSheet } from "styled-components";

  onPageLoad(sink => {
    const sheet = new ServerStyleSheet();
    const html = renderToString(sheet.collectStyles(
      <App location={sink.request.url} />
    ));

    sink.renderIntoElementById("app", html);
    sink.appendToHead(sheet.getStyleTags());
  });

Note that the server-render package now exports an onPageLoad function,
rather than the old renderIntoElementById function. The functionality of
renderIntoElementById is now exposed by the {Client,Server}Sink API.

I say the client-side version of this API is 'isomorphish' to the
server-side version, because ClientSink methods can accept DOM nodes in
addition to raw HTML strings, whereas DOM nodes don't really make sense on
the server.
2017-06-29 15:08:32 -04:00

51 lines
1.1 KiB
JavaScript

export class ServerSink {
constructor(request, arch) {
this.request = request;
this.arch = arch;
this.head = "";
this.body = "";
this.htmlById = Object.create(null);
this.maybeMadeChanges = false;
}
appendToHead(html) {
if (appendContent(this, "head", html)) {
this.maybeMadeChanges = true;
}
}
appendToBody(html) {
if (appendContent(this, "body", html)) {
this.maybeMadeChanges = true;
}
}
appendToElementById(id, html) {
if (appendContent(this.htmlById, id, html)) {
this.maybeMadeChanges = true;
}
}
renderIntoElementById(id, html) {
this.htmlById[id] = "";
this.appendToElementById(id, html);
}
}
function appendContent(object, property, content) {
let madeChanges = false;
if (Array.isArray(content)) {
content.forEach(elem => {
if (appendContent(object, property, elem)) {
madeChanges = true;
}
});
} else if ((content = content && content.toString("utf8"))) {
object[property] = (object[property] || "") + content;
madeChanges = true;
}
return madeChanges;
}