-
Notifications
You must be signed in to change notification settings - Fork 1
/
elm-server.js
121 lines (94 loc) · 2.76 KB
/
elm-server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { parseHTML } from "linkedom";
import { XMLHttpRequest } from "xmlhttprequest";
const trueSetTimeout = setTimeout;
const trueRequestAnimationFrame = requestAnimationFrame;
function check(Component) {
return Component.$$elm;
}
function requestAnimationFrame(callback) {}
function setTimeout(callback, millis) {}
function addEventListener() {}
function addListeners(node) {
node.addEventListener = addEventListener;
let parent = { current: node.parentNode };
if (!Object.getOwnPropertyDescriptor(node, "parentNode")?.set) {
Object.defineProperty(node, "parentNode", {
get() {
return parent.current;
},
set(newParent) {
parent.current = newParent;
},
});
}
if (!Object.getOwnPropertyDescriptor(node, "value")?.set) {
let value = { current: node.value };
Object.defineProperty(node, "value", {
get() {
return value.current;
},
set(newValue) {
value.current = newValue;
},
});
}
}
async function renderToStaticMarkup(Component, props, slotted) {
const dom = parseHTML(
`<html><head></head><body><div id="app"></div></body></html>`
);
const document = dom.window.document;
global.document.createElementNS = (...args) => {
const node = document.createElementNS(...args);
addListeners(node);
return node;
};
global.document.replaceChild = (...args) => {
const node = document.replaceChild(...args);
addListeners(node);
return node;
};
global.document.createTextNode = (...args) => {
const node = document.createTextNode(...args);
addListeners(node);
return node;
};
global.document.createElement = (...args) => {
const node = document.createElement(...args);
addListeners(node);
return node;
};
global.document.createDocumentFragment = (...args) => {
const node = document.createDocumentFragment(...args);
addListeners(node);
return node;
};
addListeners(global.document);
addListeners(document.body);
global.document.body = document.body;
global.document.title = document.title;
global.XMLHttpRequest = XMLHttpRequest;
global.requestAnimationFrame = requestAnimationFrame;
global.setTimeout = setTimeout;
props.server = true;
try {
Component.init({
node: document.getElementById("app"),
flags: props,
});
} catch (e) {
// we allow `init` to fail, as the problem could be something that only
// happens on the server, and it will occur in the client's browser
console.error("Error server rending Elm component:");
console.error(e);
}
global.setTimeout = trueSetTimeout;
global.requestAnimationFrameout = trueRequestAnimationFrame;
return {
html: document.toString(),
};
}
export default {
check,
renderToStaticMarkup,
};