Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 47 additions & 80 deletions packages/extension/src/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export const isIframe = window !== window.top;
export const isPopup = window.opener !== null;
const isIframe = window !== window.top;
const isPopup = window.opener !== null;
export const canLoadReactScan = !isIframe && !isPopup;

export const IS_CLIENT = typeof window !== 'undefined';
const IS_CLIENT = typeof window !== "undefined";

export const isInternalUrl = (url: string): boolean => {
if (!url) return false;

const allowedProtocols = ['http:', 'https:', 'file:'];
const allowedProtocols = ["http:", "https:", "file:"];
return !allowedProtocols.includes(new URL(url).protocol);
};

Expand All @@ -26,26 +26,42 @@ const ReactDetection = {
limits: {
MAX_DEPTH: 10,
MAX_ELEMENTS: 30,
ELEMENTS_PER_LEVEL: 5
ELEMENTS_PER_LEVEL: 5,
},
nonVisualTags: new Set([
// Document level
'HTML', 'HEAD', 'META', 'TITLE', 'BASE',
"HTML",
"HEAD",
"META",
"TITLE",
"BASE",
// Scripts and styles
'SCRIPT', 'STYLE', 'LINK', 'NOSCRIPT',
"SCRIPT",
"STYLE",
"LINK",
"NOSCRIPT",
// Media and embeds
'SOURCE', 'TRACK', 'EMBED', 'OBJECT', 'PARAM',
"SOURCE",
"TRACK",
"EMBED",
"OBJECT",
"PARAM",
// Special elements
'TEMPLATE', 'PORTAL', 'SLOT',
"TEMPLATE",
"PORTAL",
"SLOT",
// Others
'AREA', 'XML', 'DOCTYPE', 'COMMENT'
"AREA",
"XML",
"DOCTYPE",
"COMMENT",
]),
reactMarkers: {
root: '_reactRootContainer',
fiber: '__reactFiber',
instance: '__reactInternalInstance$',
container: '__reactContainer$'
}
root: "_reactRootContainer",
fiber: "__reactFiber",
instance: "__reactInternalInstance$",
container: "__reactContainer$",
},
} as const;

const childrenCache = new WeakMap<Element, Element[]>();
Expand Down Expand Up @@ -81,8 +97,8 @@ export const hasReactFiber = (): boolean => {
const rootContainer = elementWithRoot._reactRootContainer;

const hasLegacyRoot = rootContainer?._internalRoot?.current?.child != null;
const hasContainerRoot = Object.keys(elementWithRoot).some(key =>
key.startsWith(ReactDetection.reactMarkers.container)
const hasContainerRoot = Object.keys(elementWithRoot).some((key) =>
key.startsWith(ReactDetection.reactMarkers.container),
);

return hasLegacyRoot || hasContainerRoot;
Expand Down Expand Up @@ -133,59 +149,6 @@ export const saveLocalStorage = <T>(storageKey: string, state: T): void => {
} catch {}
};

export const removeLocalStorage = (storageKey: string): void => {
if (!IS_CLIENT) return;

try {
window.localStorage.removeItem(storageKey);
} catch {}
};

export const debounce = <T extends (enabled: boolean | null) => Promise<void>>(
fn: T,
wait: number,
options: { leading?: boolean; trailing?: boolean } = {},
) => {
let timeoutId: number | undefined;
let lastArg: boolean | null | undefined;
let isLeadingInvoked = false;

const debounced = (enabled: boolean | null) => {
lastArg = enabled;

if (options.leading && !isLeadingInvoked) {
isLeadingInvoked = true;
fn(enabled);
return;
}

if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}

if (options.trailing !== false) {
timeoutId = setTimeout(() => {
isLeadingInvoked = false;
timeoutId = undefined;
if (lastArg !== undefined) {
fn(lastArg);
}
}, wait);
}
};

debounced.cancel = () => {
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
timeoutId = undefined;
isLeadingInvoked = false;
lastArg = undefined;
}
};

return debounced;
};

type EventCallback<T = unknown> = (data: T) => void;
const eventBus = new Map<string, Set<EventCallback>>();

Expand Down Expand Up @@ -220,14 +183,16 @@ export const sleep = (ms: number): Promise<void> => {
return new Promise((resolve) => setTimeout(resolve, ms));
};

export const storageGetItem = async <T>(
storageKey: string,
key: string,
): Promise<T | null> => {
const isStorageRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null;

export const storageGetItem = async <T>(storageKey: string, key: string): Promise<T | null> => {
try {
const result = await chrome.storage.local.get(storageKey);
const data = result[storageKey];
return data?.[key] ?? null;
if (!isStorageRecord(data)) return null;
const value = data[key];
return value === undefined ? null : (value as T);
} catch {
return null;
}
Expand All @@ -240,9 +205,11 @@ export const storageSetItem = async <T>(
): Promise<void> => {
try {
const result = await chrome.storage.local.get(storageKey);
const data = result[storageKey] || {};
data[key] = value;
await chrome.storage.local.set({ [storageKey]: data });
} catch {
}
const data = result[storageKey];
const updatedData = {
...(isStorageRecord(data) ? data : {}),
[key]: value,
};
await chrome.storage.local.set({ [storageKey]: updatedData });
} catch {}
};
130 changes: 65 additions & 65 deletions packages/scan/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,66 @@
"version": "0.5.7",
"description": "Scan your React app for renders",
"keywords": [
"performance",
"react",
"react-scan",
"react scan",
"render",
"performance"
"react-scan",
"render"
],
"homepage": "https://react-scan.million.dev",
"bugs": {
"url": "https://github.com/aidenybai/react-scan/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/aidenybai/react-scan.git"
},
"license": "MIT",
"author": {
"name": "Aiden Bai",
"email": "aiden@million.dev",
"url": "https://million.dev"
},
"scripts": {
"build": "pnpm build:css && NODE_ENV=production tsup",
"build:copy": "pnpm build && cat dist/auto.global.js | pbcopy",
"build:css": "postcss ./src/web/assets/css/styles.tailwind.css -o ./src/web/assets/css/styles.css",
"dev:css": "postcss ./src/web/assets/css/styles.tailwind.css -o ./src/web/assets/css/styles.css --watch",
"dev:tsup": "NODE_ENV=development tsup --watch",
"dev": "pnpm run --parallel \"/^dev:(css|tsup)/\"",
"pack": "npm version patch && pnpm build && npm pack",
"pack:bump": "node scripts/bump-version.mjs && pnpm run pack && echo $(pwd)/react-scan-$(node -p \"require('./package.json').version\").tgz | pbcopy",
"publint": "publint",
"test": "vp test run",
"test:watch": "vp test",
"lint": "vp lint",
"format": "vp fmt",
"typecheck": "tsc --noEmit"
"repository": {
"type": "git",
"url": "git+https://github.com/aidenybai/react-scan.git"
},
"bin": "bin/cli.js",
"files": [
"dist",
"bin",
"package.json",
"README.md",
"LICENSE",
"auto.d.ts"
],
"main": "dist/index.js",
"module": "dist/index.mjs",
"browser": "dist/auto.global.js",
"types": "dist/index.d.ts",
"typesVersions": {
"*": {
"react-component-name/vite": [
"./dist/react-component-name/vite.d.ts"
],
"react-component-name/webpack": [
"./dist/react-component-name/webpack.d.ts"
],
"react-component-name/esbuild": [
"./dist/react-component-name/esbuild.d.ts"
],
"react-component-name/rspack": [
"./dist/react-component-name/rspack.d.ts"
],
"react-component-name/rolldown": [
"./dist/react-component-name/rolldown.d.ts"
],
"react-component-name/rollup": [
"./dist/react-component-name/rollup.d.ts"
],
"react-component-name/astro": [
"./dist/react-component-name/astro.d.ts"
],
"react-component-name/loader": [
"./dist/react-component-name/loader.d.ts"
]
}
},
"exports": {
"./package.json": "./package.json",
Expand Down Expand Up @@ -164,47 +189,25 @@
"require": "./dist/react-component-name/loader.js"
}
},
"main": "dist/index.js",
"module": "dist/index.mjs",
"browser": "dist/auto.global.js",
"types": "dist/index.d.ts",
"typesVersions": {
"*": {
"react-component-name/vite": [
"./dist/react-component-name/vite.d.ts"
],
"react-component-name/webpack": [
"./dist/react-component-name/webpack.d.ts"
],
"react-component-name/esbuild": [
"./dist/react-component-name/esbuild.d.ts"
],
"react-component-name/rspack": [
"./dist/react-component-name/rspack.d.ts"
],
"react-component-name/rolldown": [
"./dist/react-component-name/rolldown.d.ts"
],
"react-component-name/rollup": [
"./dist/react-component-name/rollup.d.ts"
],
"react-component-name/astro": [
"./dist/react-component-name/astro.d.ts"
],
"react-component-name/loader": [
"./dist/react-component-name/loader.d.ts"
]
}
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "pnpm build:css && NODE_ENV=production tsup",
"build:copy": "pnpm build && cat dist/auto.global.js | pbcopy",
"build:css": "postcss ./src/web/assets/css/styles.tailwind.css -o ./src/web/assets/css/styles.css",
"dev:css": "postcss ./src/web/assets/css/styles.tailwind.css -o ./src/web/assets/css/styles.css --watch",
"dev:tsup": "NODE_ENV=development tsup --watch",
"dev": "pnpm run --parallel \"/^dev:(css|tsup)/\"",
"pack": "npm version patch && pnpm build && npm pack",
"pack:bump": "node scripts/bump-version.mjs && pnpm run pack && echo $(pwd)/react-scan-$(node -p \"require('./package.json').version\").tgz | pbcopy",
"publint": "publint",
"test": "vp test run",
"test:watch": "vp test",
"lint": "vp lint",
"format": "vp fmt",
"typecheck": "tsc --noEmit"
},
"bin": "bin/cli.js",
"files": [
"dist",
"bin",
"package.json",
"README.md",
"LICENSE",
"auto.d.ts"
],
"dependencies": {
"@babel/core": "^7.29.0",
"@babel/types": "^7.29.0",
Expand Down Expand Up @@ -253,8 +256,5 @@
},
"optionalDependencies": {
"unplugin": "^3.0.0"
},
"publishConfig": {
"access": "public"
}
}
Loading
Loading