Skip to content

Commit

Permalink
Add static template hoisting to SSR
Browse files Browse the repository at this point in the history
  • Loading branch information
ryansolid committed Feb 3, 2021
1 parent 1a22878 commit 86c9ff1
Show file tree
Hide file tree
Showing 23 changed files with 381 additions and 415 deletions.
4 changes: 1 addition & 3 deletions packages/babel-plugin-jsx-dom-expressions/src/dom/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,7 @@ function transformAttributes(path, results) {
} else if (DelegatedEvents.has(ev) || config.delegatedEvents.indexOf(ev) !== -1) {
// can only hydrate delegated events
hasHydratableEvent = true;
const events =
attribute.scope.getProgramParent().data.events ||
(attribute.scope.getProgramParent().data.events = new Set());
const events = attribute.state.events
events.add(ev);
let handler = value.expression;
if (t.isArrayExpression(value.expression)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ function registerTemplate(path, results) {
const { hydratable } = config;
let decl;
if (results.template.length) {
const templates =
path.scope.getProgramParent().data.templates ||
(path.scope.getProgramParent().data.templates = []);
const templates = path.state.templates;
let templateDef, templateId;
if ((templateDef = templates.find(t => t.template === results.template))) {
templateId = templateDef.id;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import * as t from "@babel/types";
import { registerImportMethod } from "./utils";
import { appendTemplates } from "../dom/template";
import { appendTemplates as appendTemplatesDOM } from "../dom/template";
import { appendTemplates as appendTemplatesSSR } from "../ssr/template";
import config from "../config";

// add to the top/bottom of the module.
export default path => {
if (path.scope.data.events) {
if (path.state.events.size) {
registerImportMethod(path, "delegateEvents");
path.node.body.push(
t.expressionStatement(
t.callExpression(t.identifier("_$delegateEvents"), [
t.arrayExpression(Array.from(path.scope.data.events).map(e => t.stringLiteral(e)))
t.arrayExpression(Array.from(path.state.events).map(e => t.stringLiteral(e)))
])
)
);
}
if (path.scope.data.templates) appendTemplates(path, path.scope.data.templates);
if (path.state.templates.length) {
const appendTemplates = config.generate === "ssr" ? appendTemplatesSSR : appendTemplatesDOM;
appendTemplates(path, path.state.templates);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ export default path => {
}
path.skip();
}
path.state = {
templates: [],
events: new Set()
}
};
50 changes: 34 additions & 16 deletions packages/babel-plugin-jsx-dom-expressions/src/ssr/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,40 @@ export function createTemplate(path, result) {
return result.exprs[0];
}

// uncomment to optimize non-hoisted, needs more thorough testing
// if (!config.async) {
// if (!Array.isArray(result.template)) return t.stringLiteral(result.template);
// if (result.template.length === 1) return t.stringLiteral(result.template[0]);
// const quasis = result.template.map(tmpl => t.TemplateElement({ raw: tmpl }));
// return t.TemplateLiteral(quasis, result.templateValues);
// }
let template, id;

registerImportMethod(path, "ssr");
if (!Array.isArray(result.template))
return t.callExpression(t.identifier(`_$ssr`), [t.stringLiteral(result.template)]);
if (result.template.length === 1)
return t.callExpression(t.identifier(`_$ssr`), [t.stringLiteral(result.template[0])]);
const strings = result.template.map(tmpl => t.stringLiteral(tmpl));
return t.callExpression(t.identifier(`_$ssr`), [
t.arrayExpression(strings),
...result.templateValues
]);
if (!Array.isArray(result.template)) {
template = t.stringLiteral(result.template);
} else if (result.template.length === 1) {
template = t.stringLiteral(result.template[0]);
} else {
const strings = result.template.map(tmpl => t.stringLiteral(tmpl));
template = t.arrayExpression(strings);
}

const found = path.state.templates.find(tmp => {
if (t.isArrayExpression(tmp[1]) && t.isArrayExpression(template)) {
return tmp[1].elements.every(
(el, i) => template.elements[i] && el.value === template.elements[i].value
);
}
return tmp[1].value === template.value;
});
if (!found) {
id = path.scope.generateUidIdentifier("tmpl$");
path.state.templates.push([id, template]);
} else id = found[0];

return t.callExpression(
t.identifier(`_$ssr`),
result.template.length > 1 ? [id, ...result.templateValues] : [id]
);
}

export function appendTemplates(path, templates) {
const declarators = templates.map(template => {
return t.variableDeclarator(template[0], template[1]);
});
path.node.body.unshift(t.variableDeclaration("const", declarators));
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@ import { createComponent as _$createComponent } from "r-server";
import { ssrSpread as _$ssrSpread } from "r-server";
import { escape as _$escape } from "r-server";
import { ssr as _$ssr } from "r-server";

const template = _$ssr(
'<svg width="400" height="180"><rect stroke-width="2" x="50" y="20" rx="20" ry="20" width="150" height="150" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"></rect><linearGradient gradientTransform="rotate(25)"><stop offset="0%"></stop></linearGradient></svg>'
);

const template2 = _$ssr(
[
const _tmpl$ =
'<svg width="400" height="180"><rect stroke-width="2" x="50" y="20" rx="20" ry="20" width="150" height="150" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"></rect><linearGradient gradientTransform="rotate(25)"><stop offset="0%"></stop></linearGradient></svg>',
_tmpl$2 = [
'<svg width="400" height="180"><rect class="',
'" stroke-width="',
'" x="',
'" y="',
'" rx="20" ry="20" width="150" height="150" style="',
'"></rect></svg>'
],
_tmpl$3 = ['<svg width="400" height="180"><rect ', "></rect></svg>"],
_tmpl$4 = '<rect x="50" y="20" width="150" height="150"></rect>',
_tmpl$5 = [
'<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><a xlink:href="',
'"><text x="10" y="25">MDN Web Docs</text></a></svg>'
],
_tmpl$6 = [
'<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><text x="10" y="25">',
"</text></svg>"
];

const template = _$ssr(_tmpl$);

const template2 = _$ssr(
_tmpl$2,
_$escape(state.name, true),
_$escape(state.width, true),
_$escape(state.x, true),
Expand All @@ -27,33 +38,18 @@ const template2 = _$ssr(
(";opacity:" + 0.5)
);

const template3 = _$ssr(
['<svg width="400" height="180"><rect ', "></rect></svg>"],
_$ssrSpread(props, true, false)
);
const template3 = _$ssr(_tmpl$3, _$ssrSpread(props, true, false));

const template4 = _$ssr('<rect x="50" y="20" width="150" height="150"></rect>');
const template4 = _$ssr(_tmpl$4);

const template5 = _$ssr('<rect x="50" y="20" width="150" height="150"></rect>');
const template5 = _$ssr(_tmpl$4);

const template6 = _$createComponent(Component, {
get children() {
return _$ssr('<rect x="50" y="20" width="150" height="150"></rect>');
return _$ssr(_tmpl$4);
}
});

const template7 = _$ssr(
[
'<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><a xlink:href="',
'"><text x="10" y="25">MDN Web Docs</text></a></svg>'
],
_$escape(url, true)
);
const template7 = _$ssr(_tmpl$5, _$escape(url, true));

const template8 = _$ssr(
[
'<svg viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg"><text x="10" y="25">',
"</text></svg>"
],
_$escape(text)
);
const template8 = _$ssr(_tmpl$6, _$escape(text));
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { ssr as _$ssr } from "r-server";
import { escape as _$escape } from "r-server";
import { ssrClassList as _$ssrClassList } from "r-server";
import { ssrSpread as _$ssrSpread } from "r-server";

const template = _$ssr(
[
const _tmpl$ = [
'<div id="main" ',
' class="',
'" style="',
Expand All @@ -16,6 +14,16 @@ const template = _$ssr(
'" class="',
'"><a href="/">Welcome</a></h1></div>'
],
_tmpl$2 = ["<div><div>", "</div><div>", "</div></div>"],
_tmpl$3 = ['<div id="', '" style="', '" name="', '">', "</div>"],
_tmpl$4 = ['<div class="', '"></div>'],
_tmpl$5 = ['<div style="', '">Hi</div>'],
_tmpl$6 = ['<div style="', '"></div>'],
_tmpl$7 = "<div></div>",
_tmpl$8 = ['<input type="checkbox"', ">"];

const template = _$ssr(
_tmpl$,
_$ssrSpread(results, false, true),
_$ssrClassList({
selected: selected
Expand All @@ -29,28 +37,24 @@ const template = _$ssr(
})
);

const template2 = _$ssr(
["<div><div>", "</div><div>", "</div></div>"],
_$escape(rowId),
_$escape(row.label)
);
const template2 = _$ssr(_tmpl$2, _$escape(rowId), _$escape(row.label));

const template3 = _$ssr(
['<div id="', '" style="', '" name="', '">', "</div>"],
_tmpl$3,
_$escape(state.id, true),
"background-color:" + _$escape(state.color, true),
_$escape(state.name, true),
_$escape(state.content)
);

const template4 = _$ssr(['<div class="', '"></div>'], `hi ${_$escape(state.class, true) || ""}`);
const template4 = _$ssr(_tmpl$4, `hi ${_$escape(state.class, true) || ""}`);

const template5 = _$ssr(['<div class="', '"></div>'], `a b`);
const template5 = _$ssr(_tmpl$4, `a b`);

const template6 = _$ssr(['<div style="', '">Hi</div>'], _$ssrStyle(someStyle()));
const template6 = _$ssr(_tmpl$5, _$ssrStyle(someStyle()));

const template7 = _$ssr(
['<div style="', '"></div>'],
_tmpl$6,
_$ssrStyle({
"background-color": color(),
"margin-right": "40px",
Expand All @@ -61,16 +65,16 @@ const template7 = _$ssr(

let refTarget;

const template8 = _$ssr("<div></div>");
const template8 = _$ssr(_tmpl$7);

const template9 = _$ssr("<div></div>");
const template9 = _$ssr(_tmpl$7);

const template10 = _$ssr("<div></div>");
const template10 = _$ssr(_tmpl$7);

const template11 = _$ssr("<div></div>");
const template11 = _$ssr(_tmpl$7);

const template12 = _$ssr("<div></div>");
const template12 = _$ssr(_tmpl$7);

const template13 = _$ssr(['<input type="checkbox"', ">"], _$ssrBoolean("checked", true));
const template13 = _$ssr(_tmpl$8, _$ssrBoolean("checked", true));

const template14 = _$ssr(['<input type="checkbox"', ">"], _$ssrBoolean("checked", state.visible));
const template14 = _$ssr(_tmpl$8, _$ssrBoolean("checked", state.visible));
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@ import { createComponent as _$createComponent } from "r-server";
import { mergeProps as _$mergeProps } from "r-server";
import { ssr as _$ssr } from "r-server";
import { escape as _$escape } from "r-server";
const _tmpl$ = ["<div>Hello ", "</div>"],
_tmpl$2 = ["<div>", "</div>"],
_tmpl$3 = "<div>From Parent</div>",
_tmpl$4 = ["<div>", "", "", "</div>"],
_tmpl$5 = "<div></div>",
_tmpl$6 = ["<div>", " | ", " | ", " | ", " | ", " | ", "</div>"],
_tmpl$7 = ["<div>", " | ", "", " | ", "", " | ", "</div>"],
_tmpl$8 = ["<div> | ", " | | | ", " | </div>"];
import { Show } from "somewhere";

const Child = props => [
_$ssr(["<div>Hello ", "</div>"], _$escape(props.name)),
_$ssr(["<div>", "</div>"], _$escape(props.children))
_$ssr(_tmpl$, _$escape(props.name)),
_$ssr(_tmpl$2, _$escape(props.children))
];

const template = props => {
let childRef;
const { content } = props;
return _$ssr(
["<div>", "", "", "</div>"],
_tmpl$4,
_$createComponent(
Child,
_$mergeProps(
Expand All @@ -26,7 +34,7 @@ const template = props => {
booleanProperty: true,

get children() {
return _$ssr("<div>From Parent</div>");
return _$ssr(_tmpl$3);
}
}
)
Expand All @@ -35,7 +43,7 @@ const template = props => {
name: "Jason",

get children() {
return _$ssr(["<div>", "</div>"], _$escape(content));
return _$ssr(_tmpl$2, _$escape(content));
}
}),
_$createComponent(Context.Consumer, {
Expand All @@ -61,13 +69,13 @@ const template2 = _$createComponent(Child, {

const template3 = _$createComponent(Child, {
get children() {
return [_$ssr("<div></div>"), _$ssr("<div></div>"), _$ssr("<div></div>"), "After"];
return [_$ssr(_tmpl$5), _$ssr(_tmpl$5), _$ssr(_tmpl$5), "After"];
}
});

const template4 = _$createComponent(Child, {
get children() {
return _$ssr("<div></div>");
return _$ssr(_tmpl$5);
}
});

Expand Down Expand Up @@ -102,7 +110,7 @@ const template6 = _$createComponent(_$For, {

const template7 = _$createComponent(Child, {
get children() {
return [_$ssr("<div></div>"), () => state.dynamic];
return [_$ssr(_tmpl$5), () => state.dynamic];
}
});

Expand All @@ -117,7 +125,7 @@ const template9 = _$createComponent(_garbage, {
});

const template10 = _$ssr(
["<div>", " | ", " | ", " | ", " | ", " | ", "</div>"],
_tmpl$6,
_$createComponent(Link, {
children: "new"
}),
Expand All @@ -139,7 +147,7 @@ const template10 = _$ssr(
);

const template11 = _$ssr(
["<div>", " | ", "", " | ", "", " | ", "</div>"],
_tmpl$7,
_$createComponent(Link, {
children: "new"
}),
Expand All @@ -161,7 +169,7 @@ const template11 = _$ssr(
);

const template12 = _$ssr(
["<div> | ", " | | | ", " | </div>"],
_tmpl$8,
_$createComponent(Link, {
children: "comments"
}),
Expand Down

0 comments on commit 86c9ff1

Please sign in to comment.