Skip to content

Chrome extension stuff #727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
*.local.*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
Expand Down
42 changes: 38 additions & 4 deletions docs/demos/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import "@preact/signals-debug";
import { render } from "preact";
import { LocationProvider, Router, useLocation, lazy } from "preact-iso";
import { signal, useSignal } from "@preact/signals";
import { signal, useComputed, useSignal } from "@preact/signals";
import { setFlashingEnabled, constrainFlashToChildren } from "./render-flasher";
import "@preact/signals-debug";

// disable flashing during initial render:
setFlashingEnabled(false);
setTimeout(setFlashingEnabled, 100, true);

const demos = {
Counter,
Sum,
GlobalCounter,
DuelingCounters,
Nesting: lazy(() => import("./nesting")),
Expand Down Expand Up @@ -58,7 +59,7 @@ function displayName(name: string) {
}

function Counter() {
const count = useSignal(0, "counter");
const count = useSignal(0, { name: "counter" });

return (
<div class="card">
Expand All @@ -69,7 +70,40 @@ function Counter() {
);
}

const globalCount = signal(0, "global-counter");
function Sum() {
const a = useSignal(0, { name: "a" });
const b = useSignal(0, { name: "b" });

const sum = useComputed(() => a.value + b.value, { name: "sum" });

return (
<div class="card">
<p>
<label>
A:{" "}
<input
type="number"
value={a}
onInput={e => (a.value = +e.currentTarget.value)}
/>
</label>
</p>
<p>
<label>
B:{" "}
<input
type="number"
value={b}
onInput={e => (b.value = +e.currentTarget.value)}
/>
</label>
</p>
<output>Sum: {sum}</output>
</div>
);
}

const globalCount = signal(0, { name: "global-counter" });
function GlobalCounter({ explain = true }) {
return (
<>
Expand Down
34 changes: 34 additions & 0 deletions extension/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Extension artifacts
*.crx
*.pem
*.zip

# Build outputs
dist/
build/

# Node modules
node_modules/

# Temporary files
.tmp/
.cache/

# OS files
.DS_Store
Thumbs.db

# IDE files
.vscode/
.idea/
*.swp
*.swo

# Web-ext artifacts
web-ext-artifacts/

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
129 changes: 129 additions & 0 deletions extension/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Background service worker for the extension

// Maps to store connections by tab ID
const contentConnections = new Map(); // tab ID -> content script port
const devtoolsConnections = new Map(); // tab ID -> devtools port

chrome.runtime.onConnect.addListener(port => {
if (port.name === "content-to-background") {
handleContentScriptConnection(port);
} else if (port.name === "devtools-to-background") {
handleDevToolsConnection(port);
} else {
console.warn("Unknown connection type:", port.name);
port.disconnect();
}
});

function handleContentScriptConnection(port) {
const tabId = port.sender?.tab?.id;

if (!tabId) {
console.error("Content script connection missing tab ID");
port.disconnect();
return;
}

contentConnections.set(tabId, port);

port.onMessage.addListener(message => {
// Forward message to devtools if connected
const devtoolsPort = devtoolsConnections.get(tabId);
if (devtoolsPort) {
try {
devtoolsPort.postMessage(message);
} catch (error) {
console.error("Failed to forward message to devtools:", error);
devtoolsConnections.delete(tabId);
}
} else {
console.log(
`No devtools connection for tab ${tabId}, message queued:`,
message.type
);
}
});

port.onDisconnect.addListener(() => {
contentConnections.delete(tabId);

// Notify devtools if connected
const devtoolsPort = devtoolsConnections.get(tabId);
if (devtoolsPort) {
try {
devtoolsPort.postMessage({ type: "CONTENT_SCRIPT_DISCONNECTED" });
} catch (error) {
console.error(
"Failed to notify devtools of content script disconnect:",
error
);
}
}
});
}

function handleDevToolsConnection(port) {
let tabId = null;
let isInitialized = false;

// Listen for the initial tab ID message
const tabIdListener = message => {
if (message.type === "DEVTOOLS_TAB_ID" && !isInitialized) {
tabId = message.tabId;
isInitialized = true;

devtoolsConnections.set(tabId, port);

// Remove the tab ID listener
port.onMessage.removeListener(tabIdListener);

// Set up the main message listener
port.onMessage.addListener(message => {
// Forward message to content script if connected
const contentPort = contentConnections.get(tabId);
if (contentPort) {
try {
contentPort.postMessage(message);
} catch (error) {
console.error(
"Failed to forward message to content script:",
error
);
contentConnections.delete(tabId);
}
} else {
console.log(`No content script connection for tab ${tabId}`);
}
});

// Send initial status to devtools
const contentPort = contentConnections.get(tabId);
try {
port.postMessage({
type: "BACKGROUND_READY",
contentScriptConnected: !!contentPort,
});
} catch (error) {
console.error("Failed to send initial status to devtools:", error);
}
}
};

port.onMessage.addListener(tabIdListener);

port.onDisconnect.addListener(() => {
if (tabId) {
devtoolsConnections.delete(tabId);
}
});
}

chrome.action.onClicked.addListener(tab => {
chrome.tabs.sendMessage(tab.id, { type: "OPEN_DEVTOOLS_HINT" });
});

// Clean up connections when tabs are closed
chrome.tabs.onRemoved.addListener(tabId => {
contentConnections.delete(tabId);
devtoolsConnections.delete(tabId);
});
Loading