Skip to content

Commit

Permalink
add devtools
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmood committed Oct 21, 2024
1 parent 447a91e commit 014c8b8
Show file tree
Hide file tree
Showing 42 changed files with 2,537 additions and 176 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ dist-ssr
test-results/
.vite-playwright
__screenshots__/
.rollup.cache/
5 changes: 5 additions & 0 deletions chrome-extension/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
76 changes: 76 additions & 0 deletions chrome-extension/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { type Plugin } from "vite";
import { writeFileSync } from "fs";
import { execSync } from "child_process";

const appFilename = "index.html";
const jsFilename = "devtools.js";
const htmlFilename = "devtools.html";
const communicator = "communicator";
const background = "background";
const contentScript = "content-script";
const manifestFilename = "manifest.json";
const dist = "dist";

function genManifest() {
const manifest = {
manifest_version: 3,
name: "Stalo Chrome Extension",
version: "0.0.1",
description: "Chrome extension for stalo debugging",
devtools_page: `${htmlFilename}`,
background: {
service_worker: background + ".js",
},
content_scripts: [
{
matches: ["<all_urls>"],
js: [contentScript + ".js"],
run_at: "document_start",
},
],
permissions: ["storage"],
host_permissions: ["file:///*", "http://*/*", "https://*/*"],
web_accessible_resources: [
{
resources: [communicator + ".js"],
matches: ["<all_urls>"],
},
],
};

writeFileSync(
`${dist}/${jsFilename}`,
`chrome.devtools.panels.create("Stalo", undefined, "${appFilename}");`
);
console.info("Generated chrome extension js entrypoint");

writeFileSync(
`${dist}/${htmlFilename}`,
`<html><script src="${jsFilename}"></script></html>`
);
console.info("Generated chrome extension html entrypoint");

execSync(`npx rollup -c rollup.config.js`, {
stdio: "inherit",
env: {
...process.env,
ENTRIES: [communicator, background, contentScript].join(","),
},
});

writeFileSync(
`${dist}/${manifestFilename}`,
JSON.stringify(manifest, null, 2)
);
console.info("Generated chrome extension manifest");
}

const plugin: Plugin = {
name: "generate-manifest",
closeBundle: genManifest,
buildStart() {
this.addWatchFile("src/inject.ts");
},
};

export default plugin;
27 changes: 27 additions & 0 deletions chrome-extension/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import injectProcessEnv from 'rollup-plugin-inject-process-env';

// eslint-disable-next-line no-undef
const entries = process.env.ENTRIES.split(',');

export default entries.map(entry => {
return {
input: `src/${entry}.ts`, // Entry file
output: {
file: `dist/${entry}.js`, // Output file
format: 'iife', // Immediately Invoked Function Expression format
sourcemap: true
},
treeshake: true,
plugins: [
typescript(), // Compile TypeScript
resolve(), // Resolve node_modules dependencies
commonjs({ extensions: ['.js', '.ts'] }), // Convert CommonJS modules to ES6
injectProcessEnv({
NODE_ENV: 'production',
})
],
};
})
1 change: 1 addition & 0 deletions chrome-extension/src/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "webext-bridge/background";
29 changes: 29 additions & 0 deletions chrome-extension/src/communicator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getDevtools, devtoolsKey } from "stalo/lib/devtools";
import { eventInit, eventRecord, eventUpdate, StaloEvent } from "./types";

(async () => {
await new Promise<void>((resolve) => {
if (getDevtools()) resolve();
window.addEventListener(devtoolsKey, () => {
resolve();
});
});

const devtools = getDevtools();

if (!devtools) {
return;
}

window.dispatchEvent(
new CustomEvent(eventInit, { detail: devtools.initRecord })
);

devtools.subscribe((record) => {
window.dispatchEvent(new CustomEvent(eventRecord, { detail: record }));
});

window.addEventListener(eventUpdate, (e) => {
devtools.state = JSON.parse((e as StaloEvent).detail);
});
})();
23 changes: 23 additions & 0 deletions chrome-extension/src/content-script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { sendMessage, onMessage } from "webext-bridge/content-script";
import { StaloEvent, eventInit, eventRecord, eventUpdate } from "./types";

(() => {
window.addEventListener(eventInit, (e) => {
sendMessage(eventInit, (e as StaloEvent).detail, "devtools");
});

window.addEventListener(eventRecord, (e) => {
sendMessage(eventRecord, (e as StaloEvent).detail, "devtools");
});

onMessage(eventUpdate, ({ data }) => {
const event = new CustomEvent(eventUpdate, { detail: data });
window.dispatchEvent(event);
});

window.addEventListener("load", () => {
const script = document.createElement("script");
script.src = chrome.runtime.getURL("communicator.js");
document.head.appendChild(script);
});
})();
31 changes: 31 additions & 0 deletions chrome-extension/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import ReactDOM from "react-dom/client";
import { onMessage, sendMessage } from "webext-bridge/devtools";
import { eventInit, eventRecord, eventUpdate } from "./types";
import { Record } from "stalo/lib/devtools";
import { plug, Connection, Panel } from "@stalo/devtools-ui";

connect();

const root = document.createElement("div");

document.body.appendChild(root);

ReactDOM.createRoot(root).render(<Panel />);

function connect() {
const conn: Connection = {
setState(json) {
sendMessage(eventUpdate, json, "content-script");
},
};

plug(conn);

onMessage(eventInit, async ({ data }) => {
conn.onInit?.(data as Record<unknown>);
});

onMessage(eventRecord, async ({ data }) => {
conn.onRecord?.(data as Record<unknown>);
});
}
7 changes: 7 additions & 0 deletions chrome-extension/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const eventInit = "stalo-init";
export const eventRecord = "stalo-record";
export const eventUpdate = "stalo-update";

export interface StaloEvent extends Event {
detail: string;
}
22 changes: 22 additions & 0 deletions chrome-extension/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "Bundler",
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,

"types": ["chrome"]
}
}
12 changes: 12 additions & 0 deletions chrome-extension/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import manifest from "./manifest";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), manifest],
optimizeDeps: { exclude: ["fsevents"] },
build: {
sourcemap: true,
},
});
4 changes: 4 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
{
"words": [
"codemirror",
"immer",
"okaidia",
"stalo",
"todomvc",
"todos",
"treeshake",
"tsbuildinfo",
"webext",
"wouter",
"zustand"
]
Expand Down
1 change: 1 addition & 0 deletions devtools-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/lib/
50 changes: 50 additions & 0 deletions devtools-ui/dev/Components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import create from "stalo";
import Panel from "../src/Panel";
import { compose } from "stalo/lib/utils";
import devtools, { description, name } from "stalo/lib/devtools";
import immer from "stalo/lib/immer";

const initStat = 0;

const [useCount, baseSetCount] = create(initStat);

const setCount = compose(baseSetCount, immer, devtools(initStat));

export function App() {
return (
<div
style={{
display: "flex",
}}
>
<div style={{ width: 200, margin: 30 }}>
<Counter />
</div>
<div
style={{
flex: 1,
height: "100vh",
borderLeft: "1px solid #ccc",
overflowY: "scroll",
}}
>
<Panel />
</div>
</div>
);
}

export function Counter() {
return (
<button
onClick={() =>
setCount((c) => c + 1, {
[name]: "Increment",
[description]: "Increase the count by 1",
})
}
>
Increase {useCount()}
</button>
);
}
20 changes: 20 additions & 0 deletions devtools-ui/dev/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import ReactDOM from "react-dom/client";
import connect from "../src/connect";
import { App } from "./Components";
import { StrictMode } from "react";

connect();

setup();

function setup() {
const root = document.createElement("div");

document.body.appendChild(root);

ReactDOM.createRoot(root).render(
<StrictMode>
<App />
</StrictMode>
);
}
5 changes: 5 additions & 0 deletions devtools-ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body style="margin: 0">
<script type="module" src="./dev/index.tsx"></script>
</body>
</html>
32 changes: 32 additions & 0 deletions devtools-ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@stalo/devtools-ui",
"version": "0.0.1",
"description": "UI for stalo devtools",
"type": "module",
"scripts": {
"start": "vite --open",
"build": "tsc -b"
},
"main": "./lib/index.js",
"exports": {
".": "./lib/index.js"
},
"files": [
"./lib"
],
"repository": {
"type": "git",
"url": "https://github.com/ysmood/stalo/tree/main/packages/devtools-ui"
},
"dependencies": {
"@codemirror/lang-json": "^6.0.1",
"@emotion/css": "^11.13.4",
"@uiw/codemirror-theme-okaidia": "^4.23.5",
"@uiw/react-codemirror": "^4.23.5",
"deep-equal": "^2.2.3",
"stalo": "file:.."
},
"devDependencies": {
"@types/deep-equal": "^1.0.4"
}
}
Loading

0 comments on commit 014c8b8

Please sign in to comment.