packages/server-render/server-register.js
import { WebAppInternals } from "meteor/webapp";
import MagicString from "magic-string";
import { SAXParser } from "parse5";
import { create as createStream } from "combined-stream2";
import { ServerSink } from "./server-sink.js";
import { onPageLoad } from "./server.js";
WebAppInternals.registerBoilerplateDataCallback(
"meteor/server-render",
(request, data, arch) => {
const sink = new ServerSink(request, arch);
return onPageLoad.chain(
callback => callback(sink, request)
).then(() => {
if (! sink.maybeMadeChanges) {
return false;
}
let reallyMadeChanges = false;
function rewrite(property) {
const html = data[property];
if (typeof html !== "string") {
return;
}
const magic = new MagicString(html);
const parser = new SAXParser({
locationInfo: true
});
data[property] = parser;
if (Object.keys(sink.htmlById).length) {
const stream = createStream();
let lastStart = magic.start;
parser.on("startTag", (name, attrs, selfClosing, loc) => {
attrs.some(attr => {
if (attr.name === "id") {
let html = sink.htmlById[attr.value];
if (html) {
reallyMadeChanges = true;
const start = magic.slice(lastStart, loc.endOffset);
stream.append(Buffer.from(start, "utf8"));
stream.append(
typeof html === "string"
? Buffer.from(html, "utf8")
: html
);
lastStart = loc.endOffset;
}
return true;
}
});
});
parser.on("endTag", (name, location) => {
if (location.endOffset === html.length) {
// reached the end of the template
const end = magic.slice(lastStart);
stream.append(Buffer.from(end, "utf8"));
}
});
data[property] = stream;
}
parser.write(html, parser.end.bind(parser));
}
if (sink.head) {
data.dynamicHead = (data.dynamicHead || "") + sink.head;
reallyMadeChanges = true;
}
if (Object.keys(sink.htmlById).length > 0) {
// We don't currently allow injecting HTML into the <head> except
// by calling sink.appendHead(html).
rewrite("body");
rewrite("dynamicBody");
}
if (sink.body) {
data.dynamicBody = (data.dynamicBody || "") + sink.body;
reallyMadeChanges = true;
}
if (sink.statusCode) {
data.statusCode = sink.statusCode;
reallyMadeChanges = true;
}
if (Object.keys(sink.responseHeaders)){
data.headers = sink.responseHeaders;
reallyMadeChanges = true;
}
return reallyMadeChanges;
});
}
);