-
Notifications
You must be signed in to change notification settings - Fork 124
/
render-static.js
83 lines (70 loc) · 2.58 KB
/
render-static.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
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { readFileSync } from "fs";
import puppeteer from "puppeteer";
import { getCodeAndDependencies } from "./bundle-utils";
async function prerender(bundle, html) {
// Make all scripts in the page inert. These are the non-preload scripts,
// we don't want to run them.
const noScriptHTML = html.replace(/<(\/?)script/g, "<$1noscript");
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.viewport(1280, 720);
page.on("pageerror", err => console.error("static-plugin-error", err));
// prerenderDone is called by our main component on first mount.
const done = page.evaluate(
() =>
new Promise(resolve => {
window.prerenderDone = resolve;
})
);
await page.setContent(noScriptHTML);
// This is the prerender version of the JS.
const scriptToRun = getCodeAndDependencies(bundle, "/main/bootstrap.tsx");
page.evaluate(scriptToRun);
await done;
const renderedHTML = await page.content();
browser.close();
const finalHTML = renderedHTML
// Remove all dynamically added script tags
.replace(/<script[^>]+src=[^>]+><\/script>/g, "")
// Remove all inject style calls (as they're already added)
.replace(/\w+\.styleInject\((["']).*?\1\);/g, "")
// Re-enable scripts
.replace(/<(\/?)noscript/g, "<$1script");
return finalHTML;
}
export default function renderStaticPlugin() {
const htmlPath = "dist/no-prerender.html";
return {
name: "render-static-plugin",
buildStart() {
this.addWatchFile(htmlPath);
},
async generateBundle(options, bundle) {
const originalHTML = readFileSync(htmlPath, {
encoding: "utf8"
});
const html = await prerender(bundle, originalHTML);
// Get rid of everything else in this build. We only care about the HTML.
for (const key of Object.keys(bundle)) {
delete bundle[key];
}
bundle["index.html"] = {
fileName: "index.html",
isAsset: true,
source: html
};
}
};
}