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 | 2x
2x
2x
2x
2x
2x
8x
8x
8x
8x
8x
8x
2x
10x
10x
5x
5x
5x
5x
2x
8x
8x
2x
8x
8x
8x
3x
3x
5x
8x
8x
8x
5x
5x
5x
5x
5x
8x
2x
8x
8x
2x
10x
2x
| const path = require('path');
const React = require('react');
const { parse } = require('url');
const { renderToString } = require('react-dom/server');
const browserConfig = {
features: {
FetchExternalResources: ['script'],
ProcessExternalResources: ['script'],
SkipExternalResources: false,
},
};
const Browser = function(jsdom, fs, buildDirectory, pathname, html) {
this.fs = fs;
this.jsdom = jsdom;
this.html = html;
this.pathname = pathname;
this.host = parse(`http://${pathname}`).host;
this.buildDirectory = buildDirectory;
}
Browser.prototype.resourceLoader = async function(resource, callback) {
const resourcePathname = path.join(this.buildDirectory, resource.url.pathname);
if (resource.url.host !== this.host) {
return callback();
}
try {
const content = await this.fs.readFileSync(resourcePathname)
callback(null, content);
} catch(error) {
console.error(error);
callback(error);
}
}
Browser.prototype.created = function(resolve, reject, error, window) {
Iif (error) { console.error(error) }
this.jsdom.changeURL(window, 'http://' + this.pathname);
}
Browser.prototype.done = async function(resolve, reject, error, window) {
const app = window.app;
Iif (!app) {
return reject('No application found.');
}
let initialProps;
if (typeof app.getInitialProps === 'function') {
try {
initialProps = await app.getInitialProps();
} catch (error) {
return reject(error);
}
} else {
initialProps = {};
}
const content = renderToString(
React.createElement(app, initialProps)
);
window.document.getElementById('root').innerHTML = content;
if (initialProps) {
const script = window.document.createElement('script');
const stringifiedProps = JSON.stringify(initialProps);
script.text = `window.__INITIAL_PROPS__ = ${stringifiedProps}`;
const firstScript = window.document.body.getElementsByTagName('script')[0];
window.document.body.insertBefore(script, firstScript);
}
resolve(window.document.documentElement.outerHTML);
}
Browser.prototype.execute = function() {
return new Promise((resolve, reject) => {
this.jsdom.env({
html: this.html,
...browserConfig,
resourceLoader: this.resourceLoader.bind(this),
virtualConsole: this.jsdom.createVirtualConsole().sendTo(console),
created: this.created.bind(this, resolve, reject),
done: this.done.bind(this, resolve, reject),
});
});
}
const BrowserFactory = function(jsdom, fs, buildDirectory) {
return Browser.bind(null, jsdom, fs, buildDirectory);
};
module.exports = BrowserFactory;
|