Skip to content

Commit

Permalink
Merge pull request #1 from Juice10/merge-improved-state-machine
Browse files Browse the repository at this point in the history
Merge improved state machine
  • Loading branch information
Juice10 authored Sep 8, 2020
2 parents 0bbaf5a + f4ec446 commit 8364222
Show file tree
Hide file tree
Showing 26 changed files with 1,425 additions and 296 deletions.
8 changes: 3 additions & 5 deletions guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ rrweb.record({
});

// send last two events array to the backend
window.onerror = function() {
window.onerror = function () {
const len = eventsMatrix.length;
const events = eventsMatrix[len - 2].concat(eventsMatrix[len - 1]);
const body = JSON.stringify({ events });
Expand Down Expand Up @@ -168,7 +168,7 @@ rrweb.record({
});

// send last two events array to the backend
window.onerror = function() {
window.onerror = function () {
const len = eventsMatrix.length;
const events = eventsMatrix[len - 2].concat(eventsMatrix[len - 1]);
const body = JSON.stringify({ events });
Expand Down Expand Up @@ -260,7 +260,6 @@ So rrweb expose a public API `on` which allow developers listen to the events an
| ---------------------- | ---------------------------------- |
| start | started to replay |
| pause | paused the replay |
| resume | resumed the replay |
| finish | finished the replay |
| fullsnapshot-rebuilded | rebuilded a full snapshot |
| load-stylesheet-start | started to load remote stylesheets |
Expand Down Expand Up @@ -298,8 +297,7 @@ class Replayer {
public getMetaData(): playerMetaData;
public getTimeOffset(): number;
public play(timeOffset?: number): void;
public pause(): void;
public resume(timeOffset?: number): void;
public pause(timeOffset?: number): void;
}

type playerConfig = {
Expand Down
11 changes: 5 additions & 6 deletions guide.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ setInterval(save, 10 * 1000);

#### 重新制作快照

默认情况下,要重放内容需要所有的event,如果你不想存储所有的event,可以使用`checkout`配置。
默认情况下,要重放内容需要所有的 event,如果你不想存储所有的 event,可以使用`checkout`配置。

**多数时候你不必这样配置**。但比如在页面错误发生时,你只想捕获最近的几次 event ,这里有一个例子:

Expand All @@ -129,7 +129,7 @@ rrweb.record({
});

// 向后端传送最新的两个 event 数组
window.onerror = function() {
window.onerror = function () {
const len = eventsMatrix.length;
const events = eventsMatrix[len - 2].concat(eventsMatrix[len - 1]);
const body = JSON.stringify({ events });
Expand All @@ -143,7 +143,7 @@ window.onerror = function() {
};
```

由于rrweb 使用了增量快照机制,我们不能指定数量来捕获最近的几次 event。上面这个例子,你可以拿到最新的 200-400 个 event 来发送给你的后端。
由于 rrweb 使用了增量快照机制,我们不能指定数量来捕获最近的几次 event。上面这个例子,你可以拿到最新的 200-400 个 event 来发送给你的后端。

类似的,你可以通过配置 `checkoutEveryNms` 来捕获最近指定时间的 event :

Expand All @@ -164,7 +164,7 @@ rrweb.record({
});

// 向后端传送最新的两个 event 数组
window.onerror = function() {
window.onerror = function () {
const len = eventsMatrix.length;
const events = eventsMatrix[len - 2].concat(eventsMatrix[len - 1]);
const body = JSON.stringify({ events });
Expand Down Expand Up @@ -274,8 +274,7 @@ class Replayer {
public getMetaData(): playerMetaData;
public getTimeOffset(): number;
public play(timeOffset?: number): void;
public pause(): void;
public resume(timeOffset?: number): void;
public pause(timeOffset?: number): void;
}

type playerConfig = {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@juice10/rrweb",
"version": "0.14.0",
"version": "0.15.0-beta.6",
"description": "record and replay the web",
"scripts": {
"test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts",
Expand Down Expand Up @@ -92,7 +92,7 @@
"webpack-hot-middleware": "^2.25.0"
},
"dependencies": {
"@juice10/rrweb-snapshot": "0.9.0",
"@juice10/rrweb-snapshot": "0.9.1",
"@types/smoothscroll-polyfill": "^0.3.0",
"@xstate/fsm": "^1.4.0",
"mitt": "^1.1.3",
Expand Down
194 changes: 194 additions & 0 deletions scripts/repl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/* tslint:disable: no-console */

import * as fs from 'fs';
import * as path from 'path';
import * as EventEmitter from 'events';
import * as inquirer from 'inquirer';
import * as puppeteer from 'puppeteer';
import { eventWithTime } from '../src/types';

const emitter = new EventEmitter();

function getCode(): string {
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
return fs.readFileSync(bundlePath, 'utf8');
}

(async () => {
const code = getCode();
let events: eventWithTime[] = [];

start();

async function start() {
events = [];
const { url } = await inquirer.prompt<{ url: string }>([
{
type: 'input',
name: 'url',
message:
'Enter the url you want to record, e.g https://react-redux.realworld.io: ',
},
]);

console.log(`Going to open ${url}...`);
await record(url);
console.log('Ready to record. You can do any interaction on the page.');

const { shouldReplay } = await inquirer.prompt<{ shouldReplay: boolean }>([
{
type: 'confirm',
name: 'shouldReplay',
message: `Once you want to finish the recording, enter 'y' to start replay: `,
},
]);

emitter.emit('done', shouldReplay);

const { shouldStore } = await inquirer.prompt<{ shouldStore: boolean }>([
{
type: 'confirm',
name: 'shouldStore',
message: `Persistently store these recorded events?`,
},
]);

if (shouldStore) {
saveEvents();
}

const { shouldRecordAnother } = await inquirer.prompt<{
shouldRecordAnother: boolean;
}>([
{
type: 'confirm',
name: 'shouldRecordAnother',
message: 'Record another one?',
},
]);

if (shouldRecordAnother) {
start();
} else {
process.exit();
}
}

async function record(url: string) {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: {
width: 1600,
height: 900,
},
args: ['--start-maximized', '--ignore-certificate-errors'],
});
const page = await browser.newPage();
await page.goto(url, {
waitUntil: 'domcontentloaded',
});

await page.exposeFunction('_replLog', (event: eventWithTime) => {
events.push(event);
});
await page.evaluate(`;${code}
window.__IS_RECORDING__ = true
rrweb.record({
emit: event => window._replLog(event),
recordCanvas: true
});
`);
page.on('framenavigated', async () => {
const isRecording = await page.evaluate('window.__IS_RECORDING__');
if (!isRecording) {
await page.evaluate(`;${code}
window.__IS_RECORDING__ = true
rrweb.record({
emit: event => window._replLog(event),
recordCanvas: true
});
`);
}
});

emitter.once('done', async (shouldReplay) => {
await browser.close();
if (shouldReplay) {
await replay();
}
});
}

async function replay() {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: {
width: 1600,
height: 900,
},
args: ['--start-maximized'],
});
const page = await browser.newPage();
await page.goto('about:blank');
await page.addStyleTag({
path: path.resolve(__dirname, '../dist/rrweb.min.css'),
});
await page.evaluate(`${code}
const events = ${JSON.stringify(events)};
const replayer = new rrweb.Replayer(events);
replayer.play();
`);
}

function saveEvents() {
const tempFolder = path.join(__dirname, '../temp');
console.log(tempFolder);

if (!fs.existsSync(tempFolder)) {
fs.mkdirSync(tempFolder);
}
const time = new Date()
.toISOString()
.replace(/[-|:]/g, '_')
.replace(/\..+/, '');
const fileName = `replay_${time}.html`;
const content = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Record @${time}</title>
<link rel="stylesheet" href="../dist/rrweb.min.css" />
</head>
<body>
<script src="../dist/rrweb.min.js"></script>
<script>
/*<!--*/
const events = ${JSON.stringify(events).replace(
/<\/script>/g,
'<\\/script>',
)};
/*-->*/
const replayer = new rrweb.Replayer(events, {
UNSAFE_replayCanvas: true
});
replayer.play();
</script>
</body>
</html>
`;
const savePath = path.resolve(tempFolder, fileName);
fs.writeFileSync(savePath, content);
console.log(`Saved at ${savePath}`);
}

process
.on('uncaughtException', (error) => {
console.error(error);
})
.on('unhandledRejection', (error) => {
console.error(error);
});
})();
3 changes: 3 additions & 0 deletions src/electron-inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ record({
};
ipcRenderer.send('recordedEvent', JSON.stringify(message));
},
sampling: {
mousemove: false,
},
});
13 changes: 13 additions & 0 deletions src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function record<T = eventWithTime>(
packFn,
sampling = {},
mousemoveWait,
recordCanvas = false,
} = options;
// runtime checks for user options
if (!emit) {
Expand Down Expand Up @@ -106,6 +107,7 @@ function record<T = eventWithTime>(
blockClass,
inlineStylesheet,
maskInputOptions,
recordCanvas,
);

if (!node) {
Expand Down Expand Up @@ -237,11 +239,22 @@ function record<T = eventWithTime>(
},
}),
),
canvasMutationCb: (p) =>
wrappedEmit(
wrapEvent({
type: EventType.IncrementalSnapshot,
data: {
source: IncrementalSource.CanvasMutation,
...p,
},
}),
),
blockClass,
ignoreClass,
maskInputOptions,
inlineStylesheet,
sampling,
recordCanvas,
},
hooks,
),
Expand Down
Loading

0 comments on commit 8364222

Please sign in to comment.