Skip to content

Commit

Permalink
Merge pull request #11 from mbasso/SSR
Browse files Browse the repository at this point in the history
Support SSR (Server-side rendering)
  • Loading branch information
mbasso authored Dec 11, 2017
2 parents f2003d1 + a09f16d commit 33d92df
Show file tree
Hide file tree
Showing 119 changed files with 3,817 additions and 22,007 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
language: node_js
node_js:
- "4"
- "6"
- "7"
- "8"
Expand Down
5 changes: 4 additions & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Copyright for portions of project asm-dom are held by Simon Friis Vindum, 2015 as part of project snabbdom. All other copyright for project asm-dom are held by Matteo Basso.
Copyright for portions of project asm-dom are held by:
- Simon Friis Vindum, 2015 as part of project snabbdom
- project snabbdom-to-html
All other copyright for project asm-dom are held by Matteo Basso.

The MIT License (MIT)

Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Also, here is the list of the online Demos:

## Roadmap

- [ ] SSR (Server-side rendering) support
- [ ] Thunks support
- [ ] asm-dom aims to be even more powerful with [GC/DOM Integration](http://webassembly.org/docs/future-features/). Unfortunately this is a future feature 🦄, so, we have to be patient and wait a bit.

## Change Log
Expand All @@ -157,7 +157,10 @@ Every release, along with the migration instructions, is documented on the Githu

## Copyright and License

Copyright for portions of project asm-dom are held by Simon Friis Vindum, 2015 as part of project snabbdom. All other copyright for project asm-dom are held by Matteo Basso.
Copyright for portions of project asm-dom are held by:
- Simon Friis Vindum, 2015 as part of project snabbdom
- project snabbdom-to-html
All other copyright for project asm-dom are held by Matteo Basso.

Copyright (c) 2016, Matteo Basso.

Expand Down
Binary file modified compiled/asm-dom.a
Binary file not shown.
Binary file modified compiled/asm-dom.bc
Binary file not shown.
Binary file modified compiled/asm-dom.o
Binary file not shown.
183 changes: 93 additions & 90 deletions compiled/asmjs/asm-dom.asm.js

Large diffs are not rendered by default.

193 changes: 98 additions & 95 deletions compiled/wasm/asm-dom.js

Large diffs are not rendered by default.

Binary file modified compiled/wasm/asm-dom.wasm
Binary file not shown.
4 changes: 3 additions & 1 deletion cpp/Diff/diff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace asmdom {

const std::string emptyString;

void diffAttrs(VNode* __restrict__ const oldVnode, VNode* __restrict__ const vnode) {
if (oldVnode->data.attrs.empty() && vnode->data.attrs.empty()) return;

Expand Down Expand Up @@ -41,7 +43,7 @@ namespace asmdom {
Module['UTF8ToString']($1),
Module['UTF8ToString']($2)
);
}, vnode->elm, it.first.c_str(), it.second.c_str());
}, vnode->elm, it.first.c_str(), it.second == "true" ? emptyString.c_str() : it.second.c_str());

#ifndef ASMDOM_JS_SIDE
}
Expand Down
2 changes: 2 additions & 0 deletions cpp/asm-dom-server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include "utils/utils.cpp"
#include "toHTML/toHTML.cpp"
7 changes: 7 additions & 0 deletions cpp/asm-dom-server.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef asmdom_asmDom_server_hpp
#define asmdom_asmDom_server_hpp

#include "utils/utils.hpp"
#include "toHTML/toHTML.hpp"

#endif
1 change: 1 addition & 0 deletions cpp/asm-dom.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "VDOMConfig/VDOMConfig.cpp"
#include "VNode/VNode.cpp"
#include "h/h.cpp"
#include "toVNode/toVNode.cpp"
#include "Diff/diff.cpp"
#include "Patch/patch.cpp"
#include "Init/init.cpp"
1 change: 1 addition & 0 deletions cpp/asm-dom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "VNode/VNode.hpp"
#include "h/h.hpp"
#include "toVNode/toVNode.hpp"
#include "Patch/patch.hpp"
#include "Init/init.hpp"

Expand Down
2 changes: 1 addition & 1 deletion cpp/asm-dom.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cpp/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var _domApi2 = _interopRequireDefault(_domApi);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

if (window === undefined && global !== undefined) global.window = {};
if (global !== undefined && global.window === undefined) global.window = {};

if (window.asmDomHelpers === undefined) window.asmDomHelpers = {};
window.asmDomHelpers.domApi = _domApi2['default'];
Expand Down
192 changes: 192 additions & 0 deletions cpp/toHTML/toHTML.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#include "toHTML.hpp"
#include "../utils/utils.hpp"
#include "../VNode/VNode.hpp"
#include "../VDOMConfig/VDOMConfig.hpp"
#include <emscripten/val.h>
#include <algorithm>
#include <vector>
#include <string>

namespace asmdom {

// All SVG children elements, not in this list, should self-close

std::vector<std::string> containerElements {
// http://www.w3.org/TR/SVG/intro.html#TermContainerElement
"a",
"defs",
"glyph",
"g",
"marker",
"mask",
"missing-glyph",
"pattern",
"svg",
"switch",
"symbol",
"text",

// http://www.w3.org/TR/SVG/intro.html#TermDescriptiveElement
"desc",
"metadata",
"title"
};

// http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
std::vector<std::string> voidElements {
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr"
};

#ifndef ASMDOM_JS_SIDE
// https://developer.mozilla.org/en-US/docs/Web/API/element
std::vector<std::string> omitProps {
"attributes",
"childElementCount",
"children",
"classList",
"clientHeight",
"clientLeft",
"clientTop",
"clientWidth",
"currentStyle",
"firstElementChild",
"innerHTML",
"lastElementChild",
"nextElementSibling",
"ongotpointercapture",
"onlostpointercapture",
"onwheel",
"outerHTML",
"previousElementSibling",
"runtimeStyle",
"scrollHeight",
"scrollLeft",
"scrollLeftMax",
"scrollTop",
"scrollTopMax",
"scrollWidth",
"tabStop",
"tagName"
};
#endif

std::string encode(const std::string& data) {
std::string encoded;
encoded.reserve(data.size());
for(size_t pos = 0; pos != data.size(); ++pos) {
switch(data[pos]) {
case '&': encoded.append("&amp;"); break;
case '\"': encoded.append("&quot;"); break;
case '\'': encoded.append("&apos;"); break;
case '<': encoded.append("&lt;"); break;
case '>': encoded.append("&gt;"); break;
case '`': encoded.append("&#96;"); break;
default: encoded.append(&data[pos], 1); break;
}
}
return encoded;
};

void appendAttributes(const VNode* const vnode, std::string& html) {
for (auto& it : vnode->data.attrs) {
if (it.first != "ns" && it.second != "false") {
html.append(" " + it.first + "=\"");
if (it.second != "true") {
html.append(encode(it.second));
}
html.append("\"");
}
}

#ifdef ASMDOM_JS_SIDE
html.append(
wstring_to_utf8(emscripten::val::global("window")["asmDomHelpers"].call<std::wstring>("appendProps", reinterpret_cast<std::uintptr_t>(vnode)))
);
#else
emscripten::val String = emscripten::val::global("String");
for (auto& it : vnode->data.props) {
if (std::find(omitProps.begin(), omitProps.end(), it.first) == omitProps.end()) {
std::string key = it.first;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
html.append(" " + key + "=\"" + encode(String(it.second).as<std::string>()) + "\"");
}
}
#endif
};

void toHTML(const VNode* const vnode, std::string& html) {
if (vnode == NULL) return;

if (vnode->sel.empty() && !vnode->text.empty()) {
html.append(encode(vnode->text));
return;
}

if (vnode->sel == "!") {
html.append("<!--" + vnode->text + "-->");
return;
}

bool isSvg = vnode->data.attrs.count("ns") != 0 && vnode->data.attrs.at("ns") == "http://www.w3.org/2000/svg";
bool isSvgContainerElement = isSvg && std::find(containerElements.begin(), containerElements.end(), vnode->sel) != containerElements.end();

html.append("<" + vnode->sel);
appendAttributes(vnode, html);
if (isSvg && !isSvgContainerElement) {
html.append(" /");
}
html.append(">");

if (
(isSvgContainerElement) ||
(!isSvg && std::find(voidElements.begin(), voidElements.end(), vnode->sel) == voidElements.end())
) {
#ifdef ASMDOM_JS_SIDE
html.append(
wstring_to_utf8(emscripten::val::global("window")["asmDomHelpers"].call<std::wstring>("insertInnerHTML", reinterpret_cast<std::uintptr_t>(vnode)))
);
#else
if (vnode->data.props.count("innerHTML") != 0) {
html.append(vnode->data.props.at("innerHTML").as<std::string>());
} else
#endif

if (!vnode->text.empty()) {
html.append(encode(vnode->text));
} else if (!vnode->children.empty()) {
for(Children::size_type i = 0; i != vnode->children.size(); ++i) {
toHTML(vnode->children[i], html);
}
}
html.append("</" + vnode->sel + ">");
}
};

std::string toHTML(const VNode* const vnode) {
std::string html;
toHTML(vnode, html);

#ifndef ASMDOM_JS_SIDE
if (VDOMConfig::getConfig().getClearMemory()) {
delete vnode;
}
#endif

return html;
};

}
13 changes: 13 additions & 0 deletions cpp/toHTML/toHTML.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef asmdom_tohtml_hpp
#define asmdom_tohtml_hpp

#include "../VNode/VNode.hpp"
#include <string>

namespace asmdom {

std::string toHTML(const VNode* const vnode);

}

#endif
57 changes: 57 additions & 0 deletions cpp/toVNode/toVNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "toVNode.hpp"
#include "../VNode/VNode.hpp"
#include "../h/h.hpp"
#include <emscripten/val.h>
#include <algorithm>
#include <string>

namespace asmdom {

bool isElement(const emscripten::val& node) {
return node["nodeType"].as<int>() == 1;
};

bool isText(const emscripten::val& node) {
return node["nodeType"].as<int>() == 3;
};

bool isComment(const emscripten::val& node) {
return node["nodeType"].as<int>() == 8;
};

VNode* toVNode(const emscripten::val& node) {
VNode* vnode;
if (isElement(node)) {
std::string sel = node["tagName"].as<std::string>();
std::transform(sel.begin(), sel.end(), sel.begin(), ::tolower);

Data data;
int i = node["attributes"]["length"].as<int>();
while (i--) {
data.attrs.insert(
std::make_pair(
node["attributes"][i]["nodeName"].as<std::string>(),
node["attributes"][i]["nodeValue"].as<std::string>()
)
);
}

Children children;
i = 0;
for(int n = node["childNodes"]["length"].as<int>(); i < n; ++i) {
children.push_back(toVNode(node["childNodes"][i]));
}

vnode = h(sel, data, children);
} else if (isText(node)) {
vnode = h(node["textContent"].as<std::string>(), true);
} else if (isComment(node)) {
vnode = h("!", node["textContent"].as<std::string>());
} else {
vnode = h("");
}
vnode->elm = emscripten::val::global("window")["asmDomHelpers"]["domApi"].call<int>("addNode", node);
return vnode;
};

}
13 changes: 13 additions & 0 deletions cpp/toVNode/toVNode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef asmdom_tovnode_hpp
#define asmdom_tovnode_hpp

#include "../VNode/VNode.hpp"
#include <emscripten/val.h>

namespace asmdom {

VNode* toVNode(const emscripten::val& node);

}

#endif
Loading

0 comments on commit 33d92df

Please sign in to comment.