Skip to content

Commit

Permalink
Add firefox extension build
Browse files Browse the repository at this point in the history
  • Loading branch information
thetarnav committed Nov 5, 2023
1 parent 342f3fc commit 9bd5628
Show file tree
Hide file tree
Showing 21 changed files with 239 additions and 200 deletions.
30 changes: 15 additions & 15 deletions configs/tsconfig.base.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"noEmit": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"types": ["@total-typescript/ts-reset"]
}
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"noEmit": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"types": ["@total-typescript/ts-reset"]
}
}
108 changes: 62 additions & 46 deletions packages/extension/background/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,37 @@ It has to coordinate the communication between the different scripts based on th
*/

import { error, log } from '@solid-devtools/shared/utils'
import {
ConnectionName,
DetectionState,
ForwardPayload,
OnMessageFn,
PostMessageFn,
Versions,
createPortMessanger,
isForwardMessage,
once,
} from '../src/bridge'
import { EventBus } from '../src/event-bus'
import icons from '../src/icons'
import * as bridge from '../shared/bridge'
import { icons } from '../shared/icons'

log('Background script working.')

let activeTabId: number = -1
chrome.tabs.onActivated.addListener(({ tabId }) => (activeTabId = tabId))

type TabDataConfig = {
toContent: TabData['toContent']
fromContent: TabData['fromContent']
forwardToDevtools: TabData['forwardToDevtools']
forwardToClient: TabData['forwardToClient']
}

class EventBus<T> extends Set<(payload: T) => void> {
emit(..._: void extends T ? [payload?: T] : [payload: T]): void
emit(payload?: any) {
for (const cb of this) cb(payload)
}
}

class TabData {
public connected = true

private disconnectBus = new EventBus()
private connectListeners = new Set<
(toContent: PostMessageFn, fromContent: OnMessageFn) => void
(toContent: bridge.PostMessageFn, fromContent: bridge.OnMessageFn) => void
>()

private toContent: PostMessageFn
private fromContent: OnMessageFn
public forwardToDevtools: (fn: (message: ForwardPayload) => void) => void
public forwardToClient: (message: ForwardPayload) => void
private toContent: bridge.PostMessageFn
private fromContent: bridge.OnMessageFn
public forwardToDevtools: (fn: (message: bridge.ForwardPayload) => void) => void
public forwardToClient: (message: bridge.ForwardPayload) => void

constructor(
public tabId: number,
Expand All @@ -57,7 +50,7 @@ class TabData {
}

onContentScriptConnect(
fn: (toContent: PostMessageFn, fromContent: OnMessageFn) => void,
fn: (toContent: bridge.PostMessageFn, fromContent: bridge.OnMessageFn) => void,
): VoidFunction {
if (this.connected) fn(this.toContent.bind(this), this.fromContent.bind(this))
this.connectListeners.add(fn)
Expand Down Expand Up @@ -88,29 +81,29 @@ class TabData {
this.forwardToDevtools = () => {}
}

#versions: Versions | undefined
#versionsBus = new EventBus<Versions>()
onVersions(fn: (versions: Versions) => void) {
#versions: bridge.Versions | undefined
#versionsBus = new EventBus<bridge.Versions>()
onVersions(fn: (versions: bridge.Versions) => void) {
if (this.#versions) fn(this.#versions)
else this.#versionsBus.add(fn)
}
setVersions(versions: Versions) {
setVersions(versions: bridge.Versions) {
this.#versions = versions
this.#versionsBus.emit(versions)
this.#versionsBus.clear()
}

#detected: DetectionState = {
#detected: bridge.DetectionState = {
Solid: false,
SolidDev: false,
Devtools: false,
}
#detectedListeners = new EventBus<DetectionState>()
onDetected(fn: (state: DetectionState) => void) {
#detectedListeners = new EventBus<bridge.DetectionState>()
onDetected(fn: (state: bridge.DetectionState) => void) {
fn(this.#detected)
this.#detectedListeners.add(fn)
}
detected(state: DetectionState) {
detected(state: bridge.DetectionState) {
this.#detected = state
this.#detectedListeners.emit(state)
}
Expand All @@ -123,9 +116,10 @@ let lastDisconnectedTabData: TabData | undefined
let lastDisconnectedTabId: number | undefined

function handleContentScriptConnection(port: chrome.runtime.Port, tabId: number) {
const { onPortMessage: fromContent, postPortMessage: toContent } = createPortMessanger(port)
const { onPortMessage: fromContent, postPortMessage: toContent } =
bridge.createPortMessanger(port)

let forwardHandler: ((message: ForwardPayload) => void) | undefined
let forwardHandler: ((message: bridge.ForwardPayload) => void) | undefined
let data: TabData

const config: TabDataConfig = {
Expand All @@ -150,7 +144,7 @@ function handleContentScriptConnection(port: chrome.runtime.Port, tabId: number)
tabDataMap.set(tabId, data)

// "Versions" from content-script
once(fromContent, 'Versions', v => {
bridge.once(fromContent, 'Versions', v => {
data.setVersions(v)

// Change the popup icon to indicate that Solid is present on the page
Expand All @@ -167,29 +161,51 @@ function handleContentScriptConnection(port: chrome.runtime.Port, tabId: number)
lastDisconnectedTabId = tabId
})

port.onMessage.addListener((message: ForwardPayload | any) => {
port.onMessage.addListener((message: bridge.ForwardPayload | any) => {
// HANDLE FORWARDED MESSAGES FROM CLIENT (content-script)
forwardHandler && isForwardMessage(message) && forwardHandler(message)
forwardHandler && bridge.isForwardMessage(message) && forwardHandler(message)
})
}

function withTabData(
const ACTIVE_TAB_QUERY = { active: true, currentWindow: true } as const
const queryActiveTabId = async (): Promise<number | Error> => {
try {
const tabs = await chrome.tabs.query(ACTIVE_TAB_QUERY)
if (tabs.length === 0) return new Error('No active tab')
const tab = tabs[0]!
if (!tab.id) return new Error('Active tab has no id')
return tab.id
} catch (e) {
return e instanceof Error ? e : new Error('Unknown error')
}
}

const withTabData = async (
port: chrome.runtime.Port,
fn: (data: TabData, m: ReturnType<typeof createPortMessanger>) => void,
): void {
const data = tabDataMap.get(activeTabId)
if (!data) return error('No data for active tab', activeTabId)
const m = createPortMessanger(port)
fn(data, m)
callback: (data: TabData, m: ReturnType<typeof bridge.createPortMessanger>) => void,
): Promise<void> => {
const active_tab_id = await queryActiveTabId()
if (active_tab_id instanceof Error) {
error(active_tab_id)
return
}

const data = tabDataMap.get(active_tab_id)
if (!data) {
error('No data for active tab', active_tab_id, 'when connecing', port.name)
return
}

callback(data, bridge.createPortMessanger(port))
}

chrome.runtime.onConnect.addListener(port => {
switch (port.name) {
case ConnectionName.Content:
case bridge.ConnectionName.Content:
port.sender?.tab?.id && handleContentScriptConnection(port, port.sender.tab.id)
break

case ConnectionName.Devtools:
case bridge.ConnectionName.Devtools:
withTabData(port, (data, { postPortMessage: toDevtools }) => {
data.onContentScriptConnect(toContent => {
// "Versions" means the devtools client is present
Expand All @@ -200,7 +216,7 @@ chrome.runtime.onConnect.addListener(port => {
})
break

case ConnectionName.Panel:
case bridge.ConnectionName.Panel:
withTabData(port, (data, { postPortMessage: toPanel, onForwardMessage }) => {
data.onContentScriptConnect((toContent, fromContent) => {
data.onVersions(v => {
Expand All @@ -222,7 +238,7 @@ chrome.runtime.onConnect.addListener(port => {
})
break

case ConnectionName.Popup:
case bridge.ConnectionName.Popup:
withTabData(port, (data, { postPortMessage: toPopup }) => {
data.onVersions(v => toPopup('Versions', v))
data.onDetected(state => toPopup('Detected', state))
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/content/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
makeMessageListener,
makePostMessage,
startListeningWindowMessages,
} from '../src/bridge'
} from '../shared/bridge'

import.meta.env.DEV && log('Content-Script working.')

Expand Down
6 changes: 5 additions & 1 deletion packages/extension/content/debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ Debugger Client injected into the inspected page
import { useDebugger } from '@solid-devtools/debugger'
import { Debugger } from '@solid-devtools/debugger/types'
import { log, warn } from '@solid-devtools/shared/utils'
import { makeMessageListener, makePostMessage, startListeningWindowMessages } from '../src/bridge'
import {
makeMessageListener,
makePostMessage,
startListeningWindowMessages,
} from '../shared/bridge'

import.meta.env.DEV && log('Debugger-Client loaded')

Expand Down
2 changes: 1 addition & 1 deletion packages/extension/content/detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ and notify the content script

import '@solid-devtools/debugger/types'
import { detectSolid, onSolidDevDetect, onSolidDevtoolsDetect } from '@solid-devtools/shared/detect'
import { DETECT_MESSAGE, DetectEvent, DetectionState } from '../src/bridge'
import { DETECT_MESSAGE, DetectEvent, DetectionState } from '../shared/bridge'

const state: DetectionState = {
Solid: false,
Expand Down
18 changes: 8 additions & 10 deletions packages/extension/devtools/devtools.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
</head>

<head>
<meta charset="utf-8">
</head>

<body>
<script src="./devtools.ts" type="module"></script>
</body>

</html>
<body>
<script src="./devtools.ts" type="module"></script>
</body>
</html>
18 changes: 12 additions & 6 deletions packages/extension/devtools/devtools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ It connects to the background script.
*/

import { error, log } from '@solid-devtools/shared/utils'
import { ConnectionName, createPortMessanger, once } from '../src/bridge'
import icons from '../src/icons'
import { ConnectionName, createPortMessanger, once } from '../shared/bridge'
import { icons } from '../shared/icons'

log('Devtools-Script working.')

Expand All @@ -35,8 +35,14 @@ once(fromBackground, 'Versions', async () => {

const createPanel = () =>
new Promise<chrome.devtools.panels.ExtensionPanel>((resolve, reject) => {
chrome.devtools.panels.create('Solid', icons.normal[32], 'index.html', newPanel => {
if (chrome.runtime.lastError) reject(chrome.runtime.lastError)
else resolve(newPanel)
})
chrome.devtools.panels.create(
'Solid',
/* firefox requires absolute paths */
'/' + icons.disabled[32],
'/index.html',
newPanel => {
if (chrome.runtime.lastError) reject(chrome.runtime.lastError)
else resolve(newPanel)
},
)
})
1 change: 1 addition & 0 deletions packages/extension/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ declare global {
// import.meta.env.EXPECTED_CLIENT
interface ImportMetaEnv {
EXPECTED_CLIENT: string
BROWSER: 'chrome' | 'firefox'
}
}

Expand Down
26 changes: 12 additions & 14 deletions packages/extension/index.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Solid Devtools</title>
</head>

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Solid Devtools</title>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

<script src="./src/index.tsx" type="module"></script>
</body>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

<script src="./src/panel.tsx" type="module"></script>
</body>
</html>
Loading

0 comments on commit 9bd5628

Please sign in to comment.