* create rrdom package * test(rrdom): add unit tests for polyfill.ts * fix(rrweb snapshot): type check errors Errors are caused by the declaration similarity of @types/mocha and @types/jest if we install both of them in the whole project. * Set tagNames to upper case by default This mirrors the `Element.tagName` implementation: ``` For DOM trees which represent HTML documents, the returned tag name is always in the canonical upper-case form. For example, tagName called on a <div> element returns "DIV". ``` https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName * Add workspace file * VSCode settings for rrdom tests * Add basic test for RRDocument * Only setup jest tests for rrdom * mock Node type and Event type for nodejs environment * test(rrdom): add snapshot for document.test.ts * fix issue of nwsapi import and add unit tests for rrdom * fix: querySelectorAll returns nothing when querying elements with ids and classNames * fix: error of unit test for Event polyfill Since Event class is built in nodejs after v15.0.0 * add a dummy implementation of canvas * add style element support * add unit test for style element Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import { RRDocument, RRNode } from './document-nodejs';
|
|
|
|
/**
|
|
* Polyfill the performance for nodejs.
|
|
*/
|
|
export function polyfillPerformance() {
|
|
if (typeof window !== 'undefined' || 'performance' in global) return;
|
|
((global as Window & typeof globalThis)
|
|
.performance as unknown) = require('perf_hooks').performance;
|
|
}
|
|
|
|
/**
|
|
* Polyfill requestAnimationFrame and cancelAnimationFrame for nodejs.
|
|
*/
|
|
export function polyfillRAF() {
|
|
if (typeof window !== 'undefined' || 'requestAnimationFrame' in global)
|
|
return;
|
|
|
|
const FPS = 60,
|
|
INTERVAL = 1_000 / FPS;
|
|
let timeoutHandle: NodeJS.Timeout | null = null,
|
|
rafCount = 0,
|
|
requests = Object.create(null);
|
|
|
|
function onFrameTimer() {
|
|
const currentRequests = requests;
|
|
requests = Object.create(null);
|
|
timeoutHandle = null;
|
|
Object.keys(currentRequests).forEach(function (id) {
|
|
const request = currentRequests[id];
|
|
if (request) request(Date.now());
|
|
});
|
|
}
|
|
|
|
function requestAnimationFrame(callback: (timestamp: number) => void) {
|
|
const cbHandle = ++rafCount;
|
|
requests[cbHandle] = callback;
|
|
if (timeoutHandle === null)
|
|
timeoutHandle = setTimeout(onFrameTimer, INTERVAL);
|
|
return cbHandle;
|
|
}
|
|
|
|
function cancelAnimationFrame(handleId: number) {
|
|
delete requests[handleId];
|
|
if (Object.keys(requests).length === 0 && timeoutHandle !== null) {
|
|
clearTimeout(timeoutHandle);
|
|
timeoutHandle = null;
|
|
}
|
|
}
|
|
|
|
(global as Window &
|
|
typeof globalThis).requestAnimationFrame = requestAnimationFrame;
|
|
(global as Window &
|
|
typeof globalThis).cancelAnimationFrame = cancelAnimationFrame;
|
|
}
|
|
|
|
/**
|
|
* Try to polyfill Event type.
|
|
* The implementation of Event so far is empty because rrweb doesn't strongly depend on it in nodejs mode.
|
|
* Note: The Event class is available through the global object from nodejs v15.0.0.
|
|
*/
|
|
export function polyfillEvent() {
|
|
if (typeof Event !== 'undefined') return;
|
|
(global.Event as unknown) = function () {};
|
|
}
|
|
|
|
/**
|
|
* Polyfill Node type with RRNode for nodejs.
|
|
*/
|
|
export function polyfillNode() {
|
|
if (typeof Node !== 'undefined') return;
|
|
(global.Node as unknown) = RRNode;
|
|
}
|
|
|
|
/**
|
|
* Polyfill document object with RRDocument for nodejs.
|
|
*/
|
|
export function polyfillDocument() {
|
|
if (typeof document !== 'undefined') return;
|
|
const rrdom = new RRDocument();
|
|
(() => {
|
|
rrdom.appendChild(rrdom.createElement('html'));
|
|
rrdom.documentElement.appendChild(rrdom.createElement('head'));
|
|
rrdom.documentElement.appendChild(rrdom.createElement('body'));
|
|
})();
|
|
global.document = (rrdom as unknown) as Document;
|
|
}
|