Skip to content

Commit

Permalink
[RC 0.1.2] - cleanup, improvements, Re-renders History, Components Tr…
Browse files Browse the repository at this point in the history
…ee and more (#195)

  fix: cleanup + biiome - 0 errors, 0 warnings
  feat: custom postcss plugin rem2px to prevent target page styles to brake ours
  feat: Re-renders History
  feat: Components Tree
  feat: Search
  feat: Breadcrumb
  feat: Resizing + preserve dimentions
  improve: extension now work with new outlines
  improve: inspector UI animations and components
  improve: getOverrideMethods
  improve: chain updates through all renderers to ensure consistency across different React renderers (e.g., React DOM + React Native Web in the same app)
  improve: overrideContext: using overrideProps internally to update the context provider's value prop
  • Loading branch information
pivanov committed Feb 2, 2025
1 parent 4b48e82 commit 609fb61
Show file tree
Hide file tree
Showing 88 changed files with 5,435 additions and 3,148 deletions.
6 changes: 3 additions & 3 deletions BROWSER_EXTENSION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@
## Chrome

1. Download the [`chrome-react-scanner-extension-v1.0.2.zip`](https://github.com/aidenybai/react-scan/tree/main/packages/extension/build) file.
1. Download the [`chrome-extension-v1.0.3.zip`](https://github.com/aidenybai/react-scan/tree/main/packages/extension/build) file.
2. Unzip the file.
3. Open Chrome and navigate to `chrome://extensions/`.
4. Enable "Developer mode" if it is not already enabled.
5. Click "Load unpacked" and select the unzipped folder (or drag the folder into the page).

## Firefox

1. Download the [`firefox-react-scanner-extension-v1.0.2.zip`](https://github.com/aidenybai/react-scan/tree/main/packages/extension/build) file.
1. Download the [`firefox-extension-v1.0.3.zip`](https://github.com/aidenybai/react-scan/tree/main/packages/extension/build) file.
2. Unzip the file.
3. Open Firefox and navigate to `about:debugging#/runtime/this-firefox`.
4. Click "Load Temporary Add-on..."
5. Select `manifest.json` from the unzipped folder

## Brave

1. Download the [`brave-react-scanner-extension-v1.0.2.zip`](https://github.com/aidenybai/react-scan/tree/main/packages/extension/build) file.
1. Download the [`brave-extension-v1.0.3.zip`](https://github.com/aidenybai/react-scan/tree/main/packages/extension/build) file.
2. Unzip the file.
3. Open Brave and navigate to `brave://extensions`.
4. Click "Load unpacked" and select the unzipped folder (or drag the folder into the page).
Expand Down
5 changes: 3 additions & 2 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"enabled": true
},
"linter": {
"enabled": false,
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
Expand All @@ -49,7 +49,8 @@
}
},
"suspicious": {
"noExplicitAny": "error"
"noExplicitAny": "error",
"noConsole": "error"
},
"security": {
"noDangerouslySetInnerHtml": "error"
Expand Down
7 changes: 0 additions & 7 deletions packages/extension/.eslintrc.js

This file was deleted.

6 changes: 3 additions & 3 deletions packages/extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ pnpm pack:all
```

This will create:
- `chrome-react-scanner-extension-v1.0.2.zip`
- `firefox-react-scanner-extension-v1.0.2.zip`
- `brave-react-scanner-extension-v1.0.2.zip`
- `chrome-extension-v1.0.3.zip`
- `firefox-extension-v1.0.3.zip`
- `brave-extension-v1.0.3.zip`

in the `build` directory.
44 changes: 44 additions & 0 deletions packages/extension/build-worker.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { build } from 'vite';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

async function buildWorker() {
try {
const entryPath = path.resolve(
__dirname,
'../../packages/scan/src/new-outlines/offscreen-canvas.worker.ts',
);
const outputPath = path.resolve(__dirname, 'dist/assets');

// biome-ignore lint/suspicious/noConsole: Intended debug output
console.log('Building worker with entry:', entryPath);
// biome-ignore lint/suspicious/noConsole: Intended debug output
console.log('Output directory:', outputPath);

await build({
build: {
lib: {
entry: entryPath,
formats: ['iife'],
fileName: () => 'offscreen-canvas.worker.js',
name: 'OffscreenCanvasWorker',
},
outDir: outputPath,
emptyOutDir: false,
copyPublicDir: false,
assetsDir: 'assets',
},
});

// biome-ignore lint/suspicious/noConsole: Intended debug output
console.log('Worker build completed successfully!');
} catch (error) {
// biome-ignore lint/suspicious/noConsole: Intended debug output
console.error('Worker build failed:', error);
process.exit(1);
}
}

buildWorker();
Binary file removed packages/extension/build/brave-extension-v1.0.0.zip
Binary file not shown.
Binary file removed packages/extension/build/brave-extension-v1.0.1.zip
Binary file not shown.
Binary file removed packages/extension/build/brave-extension-v1.0.2.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 2 additions & 1 deletion packages/extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@react-scan/extension",
"version": "1.0.2",
"version": "1.0.3",
"private": true,
"type": "module",
"scripts": {
Expand Down Expand Up @@ -31,6 +31,7 @@
"@types/webextension-polyfill": "^0.10.0",
"@vitejs/plugin-react": "^4.2.1",
"bestzip": "^2.2.1",
"bippy": "0.2.7",
"cross-env": "^7.0.3",
"vite": "^6.0.7",
"vite-plugin-web-extension": "^4.4.3",
Expand Down
89 changes: 56 additions & 33 deletions packages/extension/src/content/index.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,71 @@
import { storageGetItem, storageSetItem } from '@pivanov/utils';
import type { Options } from 'react-scan';
import browser from 'webextension-polyfill';
import { BroadcastSchema } from '../types/messages';
import { broadcast, readLocalStorage } from '../utils/helpers';
import {
broadcast,
readLocalStorage,
saveLocalStorage,
} from '../utils/helpers';

chrome.runtime.onMessage.addListener(async (message: unknown, _sender, sendResponse) => {
const result = BroadcastSchema.safeParse(message);
if (!result.success) {
return false;
}

const data = result.data;

if (data.type === 'react-scan:ping') {
sendResponse({ pong: true });
return false;
}
chrome.runtime.onMessage.addListener(
async (message: unknown, _sender, sendResponse) => {
const result = BroadcastSchema.safeParse(message);
if (!result.success) {
return false;
}

if (data.type === 'react-scan:is-running') {
const options = readLocalStorage<{ enabled: boolean; showToolbar: boolean }>('react-scan-options');
const response = { isRunning: options?.enabled && options?.showToolbar };
sendResponse(response);
return false;
}
const data = result.data;

if (data.type === 'react-scan:toggle-state') {
let toggledState = false;
if (data.type === 'react-scan:ping') {
sendResponse({ pong: true });
return false;
}

const options = readLocalStorage<{ showToolbar: boolean }>('react-scan-options');
if (options !== null) {
toggledState = !options?.showToolbar;
if (data.type === 'react-scan:is-running') {
const options = readLocalStorage<{
enabled: boolean;
showToolbar: boolean;
}>('react-scan-options');
const response = { isRunning: options?.enabled && options?.showToolbar };
sendResponse(response);
return false;
}

if (data.type === 'react-scan:toggle-state') {
const isEnabled = await storageGetItem<boolean>(
'react-scan-extension',
'isEnabled',
);

let toggledState = true;

broadcast.onmessage = (type, data) => {
if (type === 'react-scan:react-version' && data.version) {
sendResponse({ hasReact: toggledState });
if (isEnabled !== null) {
toggledState = !isEnabled;
}
};

broadcast.postMessage('react-scan:toggle-state', { state: toggledState });
return true;
}
void storageSetItem('react-scan-extension', 'isEnabled', toggledState);

return false;
});
const options = readLocalStorage<Options>('react-scan-options');
saveLocalStorage('react-scan-options', {
...options,
enabled: isEnabled,
showToolbar: isEnabled,
});

broadcast.onmessage = (type, data) => {
if (type === 'react-scan:react-version' && data.version) {
sendResponse({ hasReact: toggledState });
}
};

broadcast.postMessage('react-scan:toggle-state', { state: toggledState });
return true;
}

return false;
},
);

window.addEventListener('DOMContentLoaded', () => {
broadcast.onmessage = (type, data) => {
Expand Down
54 changes: 36 additions & 18 deletions packages/extension/src/inject/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
import { sleep, storageGetItem, storageSetItem } from '@pivanov/utils';
import { sleep, storageGetItem } from '@pivanov/utils';
import * as reactScan from 'react-scan';
import type { Options } from 'react-scan';
import { broadcast, canLoadReactScan, hasReactFiber } from '../utils/helpers';
import { createReactNotAvailableUI, toggleReactIsNotAvailable } from './react-is-not-available';
import {
createReactNotAvailableUI,
toggleReactIsNotAvailable,
} from './react-is-not-available';


window.reactScan = reactScan.setOptions;

storageGetItem<boolean>('react-scan-extension', 'isEnabled').then(
(isEnabled) => {
const options: Partial<Options> = {
enabled: false,
showToolbar: false,
dangerouslyForceRunInProduction: true,
};

if (isEnabled !== null) {
options.enabled = isEnabled;
options.showToolbar = isEnabled;
}

reactScan.scan(options);
},
);


window.addEventListener('DOMContentLoaded', async () => {
Expand All @@ -13,42 +38,35 @@ window.addEventListener('DOMContentLoaded', async () => {
const isReactAvailable = hasReactFiber();

if (!isReactAvailable) {
_reactScan.setOptions({
reactScan.setOptions({
enabled: false,
showToolbar: false,
});
createReactNotAvailableUI();
}

const isDefaultEnabled = await storageGetItem<boolean>(
'react-scan',
'enabled',
);
_reactScan.setOptions({
enabled: !!isDefaultEnabled,
showToolbar: !!isDefaultEnabled,
});

broadcast.onmessage = async (type, data) => {
if (type === 'react-scan:toggle-state') {
broadcast.postMessage('react-scan:react-version', {
version: isReactAvailable,
});

if (isReactAvailable) {
const state = data?.state;
_reactScan.setOptions({
enabled: state,
showToolbar: state,
const isEnabled = data?.state;

reactScan.setOptions({
enabled: isEnabled,
showToolbar: isEnabled,
});
void storageSetItem('react-scan', 'enabled', state);

reactScan.start();
} else {
toggleReactIsNotAvailable();
}
}
};

_reactScan.ReactScanInternals.Store.inspectState.subscribe((state) => {
reactScan.ReactScanInternals.Store.inspectState.subscribe((state) => {
broadcast.postMessage('react-scan:is-focused', {
state: state.kind === 'focused',
});
Expand Down
11 changes: 3 additions & 8 deletions packages/extension/src/inject/react-scan.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import * as reactScan from 'react-scan';
import { installRDTHook } from 'bippy';
import { canLoadReactScan, saveLocalStorage } from '../utils/helpers';

saveLocalStorage('useExtensionWorker', true);
window.reactScan = reactScan.setOptions;
globalThis._reactScan = reactScan;
saveLocalStorage('use-extension-worker', true);

if (canLoadReactScan) {
reactScan.scan({
enabled: true,
showToolbar: false,
});
installRDTHook();
}
58 changes: 58 additions & 0 deletions packages/extension/src/manifest.chrome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"manifest_version": 3,
"name": "React Scan",
"version": "1.0.0",
"description": "Scan React apps for performance problems",
"icons": {
"16": "icon/16.png",
"32": "icon/32.png",
"48": "icon/48.png",
"96": "icon/96.png",
"128": "icon/128.png"
},
"action": {
"default_icon": {
"16": "icon/16.png",
"32": "icon/32.png",
"48": "icon/48.png",
"96": "icon/96.png",
"128": "icon/128.png"
}
},
"background": {
"service_worker": "src/background/index.ts"
},
"permissions": [
"activeTab",
"tabs",
"scripting",
"storage",
"declarativeNetRequest"
],
"host_permissions": ["<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["src/inject/react-scan.ts"],
"run_at": "document_start",
"world": "MAIN"
},
{
"matches": ["<all_urls>"],
"js": ["src/inject/index.ts"],
"run_at": "document_start",
"world": "MAIN"
},
{
"matches": ["<all_urls>"],
"js": ["src/content/index.ts"],
"run_at": "document_start"
}
],
"web_accessible_resources": [
{
"resources": ["icon/*", "workers/*"],
"matches": ["<all_urls>"]
}
]
}
Loading

0 comments on commit 609fb61

Please sign in to comment.