basic impl of wait for stylesheet loaded

This commit is contained in:
Yanzhen Yu
2018-11-26 18:19:07 +08:00
parent 9228a8f04a
commit 2c0a0edf36
4 changed files with 50 additions and 3 deletions

View File

@@ -55,6 +55,6 @@
"dependencies": { "dependencies": {
"delegated-events": "git+https://git@github.com/rrweb-io/delegated-events.git", "delegated-events": "git+https://git@github.com/rrweb-io/delegated-events.git",
"mitt": "^1.1.3", "mitt": "^1.1.3",
"rrweb-snapshot": "^0.6.4" "rrweb-snapshot": "^0.6.6"
} }
} }

View File

@@ -14,6 +14,13 @@ function getCode(): string {
return fs.readFileSync(bundlePath, 'utf8'); return fs.readFileSync(bundlePath, 'utf8');
} }
function safeStringify(obj: Object): string {
return JSON.stringify(obj)
.replace(/&/g, '&amp')
.replace(/</g, '&lt')
.replace(/>/g, '&gt');
}
(async () => { (async () => {
const code = getCode(); const code = getCode();
@@ -110,7 +117,7 @@ function getCode(): string {
path: path.resolve(__dirname, '../dist/rrweb.min.css'), path: path.resolve(__dirname, '../dist/rrweb.min.css'),
}); });
await page.evaluate(`${code} await page.evaluate(`${code}
const events = ${JSON.stringify(events)}; const events = ${safeStringify(events)};
const replayer = new rrweb.Replayer(events); const replayer = new rrweb.Replayer(events);
replayer.play(); replayer.play();
`); `);
@@ -139,7 +146,7 @@ function getCode(): string {
<body> <body>
<script src="../dist/rrweb.min.js"></script> <script src="../dist/rrweb.min.js"></script>
<script> <script>
const data = ${JSON.stringify({ events })} const data = ${safeStringify({ events })}
const replayer = new rrweb.Replayer(data.events); const replayer = new rrweb.Replayer(data.events);
replayer.play(); replayer.play();
</script> </script>

View File

@@ -27,6 +27,7 @@ const mitt = (mittProxy as any).default || mittProxy;
const defaultConfig: playerConfig = { const defaultConfig: playerConfig = {
speed: 1, speed: 1,
root: document.body, root: document.body,
loadTimeout: 10 * 1000,
}; };
export class Replayer { export class Replayer {
@@ -207,6 +208,7 @@ export class Replayer {
event: fullSnapshotEvent & { timestamp: number }, event: fullSnapshotEvent & { timestamp: number },
) { ) {
mirror.map = rebuild(event.data.node, this.iframe.contentDocument!)[1]; mirror.map = rebuild(event.data.node, this.iframe.contentDocument!)[1];
this.waitForStylesheetLoad();
// avoid form submit to refresh the iframe // avoid form submit to refresh the iframe
off('submit', 'form', this.preventDefault, { off('submit', 'form', this.preventDefault, {
document: this.iframe.contentDocument!, document: this.iframe.contentDocument!,
@@ -223,6 +225,43 @@ export class Replayer {
}); });
} }
/**
* pause when loading style sheet, resume when loaded all timeout exceed
*/
private waitForStylesheetLoad() {
const { head } = this.iframe.contentDocument!;
if (head) {
const unloadSheets: Set<HTMLLinkElement> = new Set();
let timer: number;
head
.querySelectorAll('link[rel="stylesheet"]')
.forEach((css: HTMLLinkElement) => {
if (!css.sheet) {
if (unloadSheets.size === 0) {
this.pause();
this.emitter.emit('wait-stylesheet');
timer = window.setTimeout(() => {
this.resume();
// mark timer was called
timer = -1;
}, this.config.loadTimeout);
}
unloadSheets.add(css);
css.addEventListener('load', () => {
unloadSheets.delete(css);
if (unloadSheets.size === 0 && timer !== -1) {
this.resume();
this.emitter.emit('stylesheet-loaded');
if (timer) {
window.clearTimeout(timer);
}
}
});
}
});
}
}
private preventDefault(evt: Event) { private preventDefault(evt: Event) {
evt.preventDefault(); evt.preventDefault();
} }

View File

@@ -226,6 +226,7 @@ export type hookResetter = () => void;
export type playerConfig = { export type playerConfig = {
speed: number; speed: number;
root: Element; root: Element;
loadTimeout: number;
}; };
export type playerMetaData = { export type playerMetaData = {