Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b4283e37bd | |||
| b467ad760a | |||
| 9fc6408ef9 | |||
| 394cb1a520 | |||
| ffec88549b | |||
| 4758bea187 | |||
| 6671471f75 | |||
| ae78dc7fb3 | |||
| b62af3d007 | |||
| 43ae44ecd5 | |||
| 5bab9d2f59 | |||
| 7edf1c8103 | |||
| 53b4eac955 |
@@ -29,6 +29,7 @@ const chromeExtensionIds = [
|
||||
'nedcanggplmbbgmlpcjiafgjcpdimpea', // YTBlock - Block any content from YouTube™
|
||||
'oadbjpccljkplmhnjekgjamejnbadlne', // demo.fun - Interactive product demos that convert
|
||||
'iopdafdcollfgaoffingmahpffckmjni', // SmartEReply: Elevate Your LinkedIn™ Engagement with AI 🚀📈
|
||||
'khjdmjcmpolknpccmaaipmidphjokhdf', // WorkFlowy MultiFlow
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -15,7 +15,14 @@ npx wxt@latest init <project-name>
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
bunx wxt@latest init <project-name>
|
||||
# The "wxt init" command currently fails when ran with bunx.
|
||||
# Use NPX as a workaround, and select "bun" as your package
|
||||
# manager. To stay up to date with this issue, follow
|
||||
# https://github.com/wxt-dev/wxt/issues/707
|
||||
#
|
||||
# bunx wxt@latest init <project-name>
|
||||
|
||||
npx wxt@latest init <project-name>
|
||||
```
|
||||
|
||||
:::
|
||||
@@ -96,7 +103,6 @@ pnpm dev
|
||||
```
|
||||
|
||||
:::tip 🎉 Well done!
|
||||
|
||||
The dev command will build the extension for development, open the browser, and reload the different parts of the extension when you save changes.
|
||||
:::
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ Firefox does not support sandboxed pages.
|
||||
:patterns="[
|
||||
['sandbox.html', 'sandbox.html'],
|
||||
['sandbox/index.html', 'sandbox.html'],
|
||||
['<name>.sandbox.html', '<name>.html` '],
|
||||
['<name>.sandbox/index.html', '<name>.html` '],
|
||||
['<name>.sandbox.html', '<name>.html'],
|
||||
['<name>.sandbox/index.html', '<name>.html'],
|
||||
]"
|
||||
/>
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
"docs:preview": "pnpm -s docs:gen && vitepress preview docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aklinker1/buildc": "^1.0.5",
|
||||
"@aklinker1/buildc": "^1.0.7",
|
||||
"@aklinker1/check": "^1.3.1",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"check": "buildc --deps-only -- check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.18.5"
|
||||
"wxt": ">=0.18.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^4.3.1"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"check": "buildc --deps-only -- check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.18.5"
|
||||
"wxt": ">=0.18.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"vite-plugin-solid": "^2.10.2"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"check": "buildc --deps-only -- check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.18.5"
|
||||
"wxt": ">=0.18.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.1"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"check": "buildc --deps-only -- check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wxt": ">=0.18.5"
|
||||
"wxt": ">=0.18.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.5"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "buildc -- wxt",
|
||||
"build": "buildc --deps-only -- wxt build",
|
||||
"dev": "buildc --deps-only -- wxt",
|
||||
"build": "buildc -- wxt build",
|
||||
"build:all": "buildc --deps-only -- run-s -s 'build:all:*'",
|
||||
"build:all:chrome-mv3": "wxt build",
|
||||
"build:all:chrome-mv2": "wxt build --mv2",
|
||||
|
||||
@@ -13,7 +13,7 @@ export default defineContentScript({
|
||||
anchor: 'form[role=search]',
|
||||
onMount: (container) => {
|
||||
const app = document.createElement('div');
|
||||
app.textContent = 'Custom content script UI';
|
||||
app.textContent = browser.i18n.getMessage('prompt_for_name');
|
||||
container.append(app);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -21,6 +21,9 @@ export default defineConfig({
|
||||
experimental: {
|
||||
viteRuntime: true,
|
||||
},
|
||||
runner: {
|
||||
startUrls: ['https://duckduckgo.com'],
|
||||
},
|
||||
example: {
|
||||
a: 'a',
|
||||
// @ts-expect-error: c is not defined, this should error out
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## v0.18.8
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.7...wxt-v0.18.8)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **dev:** Reload extension when public files change ([#752](https://github.com/wxt-dev/wxt/pull/752))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Don't load plugins twice in HTML pages ([#746](https://github.com/wxt-dev/wxt/pull/746))
|
||||
- Ignore .wxt file changes in dev ([#755](https://github.com/wxt-dev/wxt/pull/755))
|
||||
- **modules:** `addViteConfig` ignored user vite config ([#760](https://github.com/wxt-dev/wxt/pull/760))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Refactor client web socket util ([#753](https://github.com/wxt-dev/wxt/pull/753))
|
||||
- Add E2E test for `addImportPreset` ([9fc6408](https://github.com/wxt-dev/wxt/commit/9fc6408))
|
||||
|
||||
## v0.18.7
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.18.6...wxt-v0.18.7)
|
||||
|
||||
@@ -287,5 +287,29 @@ describe('Module Helpers', () => {
|
||||
|
||||
await expect(project.serializeOutput()).resolves.toContain(expectedText);
|
||||
});
|
||||
|
||||
it('should add preset', async () => {
|
||||
const project = new TestProject();
|
||||
project.addFile(
|
||||
'entrypoints/background.ts',
|
||||
`export default defineBackground(() => {
|
||||
customImport();
|
||||
});`,
|
||||
);
|
||||
project.addFile(
|
||||
'modules/test.ts',
|
||||
`import { defineWxtModule, addImportPreset } from 'wxt/modules';
|
||||
|
||||
export default defineWxtModule((wxt) => {
|
||||
addImportPreset(wxt, "vue");
|
||||
})`,
|
||||
);
|
||||
|
||||
await project.build();
|
||||
|
||||
await expect(
|
||||
project.serializeFile('.wxt/types/imports.d.ts'),
|
||||
).resolves.toContain("const ref: typeof import('vue')['ref']");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.18.7",
|
||||
"version": "0.18.8",
|
||||
"description": "Next gen framework for developing web extensions",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -13,10 +13,10 @@ describe('Module Utilities', () => {
|
||||
const userConfig = {};
|
||||
const moduleConfig = { build: { sourcemap: true } };
|
||||
|
||||
wxt.config.vite = () => userConfig;
|
||||
wxt.config.vite = () => Promise.resolve(userConfig);
|
||||
addViteConfig(wxt, () => moduleConfig);
|
||||
await wxt.hooks.callHook('ready', wxt);
|
||||
const actual: any = wxt.config.vite(wxt.config.env);
|
||||
const actual = await wxt.config.vite(wxt.config.env);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
@@ -32,7 +32,7 @@ describe('Module Utilities', () => {
|
||||
wxt.config.vite = () => userConfig;
|
||||
addViteConfig(wxt, () => moduleConfig);
|
||||
await wxt.hooks.callHook('ready', wxt);
|
||||
const actual: any = wxt.config.vite(wxt.config.env);
|
||||
const actual = await wxt.config.vite(wxt.config.env);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -46,13 +46,19 @@ try {
|
||||
// Use "pre" so the new script is added before vite bundles all the scripts
|
||||
order: 'pre',
|
||||
handler(html, _ctx) {
|
||||
const { document } = parseHTML(html);
|
||||
const script = document.createElement('script');
|
||||
script.type = 'module';
|
||||
script.src =
|
||||
const src =
|
||||
config.command === 'serve'
|
||||
? `http://${config.dev.server?.hostname}:${config.dev.server?.port}/@id/${virtualHtmlModuleId}`
|
||||
: virtualHtmlModuleId;
|
||||
|
||||
const { document } = parseHTML(html);
|
||||
const existing = document.querySelector(`script[src='${src}']`);
|
||||
if (existing) return;
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.type = 'module';
|
||||
script.src = src;
|
||||
|
||||
if (document.head == null) {
|
||||
const newHead = document.createElement('head');
|
||||
document.documentElement.prepend(newHead);
|
||||
|
||||
@@ -153,6 +153,7 @@ function createFileReloader(server: WxtDevServer) {
|
||||
|
||||
// Here, "path" is a non-normalized path (ie: C:\\users\\... instead of C:/users/...)
|
||||
if (path.startsWith(wxt.config.outBaseDir)) return;
|
||||
if (path.startsWith(wxt.config.wxtDir)) return;
|
||||
changeQueue.push([event, path]);
|
||||
|
||||
await fileChangedMutex.runExclusive(async () => {
|
||||
|
||||
@@ -100,6 +100,11 @@ describe('Detect Dev Changes', () => {
|
||||
describe('Public Assets', () => {
|
||||
it("should return 'extension-reload' without any groups to rebuild when the changed file is a public asset", () => {
|
||||
const changes = ['/root/src/public/image.svg'];
|
||||
setFakeWxt({
|
||||
config: {
|
||||
publicDir: '/root/src/public',
|
||||
},
|
||||
});
|
||||
const asset1 = fakeOutputAsset({
|
||||
fileName: 'image.svg',
|
||||
});
|
||||
@@ -114,10 +119,7 @@ describe('Detect Dev Changes', () => {
|
||||
const expected: DevModeChange = {
|
||||
type: 'extension-reload',
|
||||
rebuildGroups: [],
|
||||
cachedOutput: {
|
||||
...currentOutput,
|
||||
publicAssets: [asset2],
|
||||
},
|
||||
cachedOutput: currentOutput,
|
||||
};
|
||||
|
||||
const actual = detectDevChanges(changes, currentOutput);
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
BuildOutput,
|
||||
BuildStepOutput,
|
||||
EntrypointGroup,
|
||||
OutputAsset,
|
||||
OutputFile,
|
||||
} from '~/types';
|
||||
import { every, some } from '~/core/utils/arrays';
|
||||
@@ -50,12 +49,25 @@ export function detectDevChanges(
|
||||
findEffectedSteps(changedFile, currentOutput),
|
||||
),
|
||||
);
|
||||
if (changedSteps.size === 0) return { type: 'no-change' };
|
||||
if (changedSteps.size === 0) {
|
||||
const hasPublicChange = some(changedFiles, (file) =>
|
||||
file.startsWith(wxt.config.publicDir),
|
||||
);
|
||||
if (hasPublicChange) {
|
||||
return {
|
||||
type: 'extension-reload',
|
||||
rebuildGroups: [],
|
||||
cachedOutput: currentOutput,
|
||||
};
|
||||
} else {
|
||||
return { type: 'no-change' };
|
||||
}
|
||||
}
|
||||
|
||||
const unchangedOutput: BuildOutput = {
|
||||
manifest: currentOutput.manifest,
|
||||
steps: [],
|
||||
publicAssets: [],
|
||||
publicAssets: [...currentOutput.publicAssets],
|
||||
};
|
||||
const changedOutput: BuildOutput = {
|
||||
manifest: currentOutput.manifest,
|
||||
@@ -70,13 +82,6 @@ export function detectDevChanges(
|
||||
unchangedOutput.steps.push(step);
|
||||
}
|
||||
}
|
||||
for (const asset of currentOutput.publicAssets) {
|
||||
if (changedSteps.has(asset)) {
|
||||
changedOutput.publicAssets.push(asset);
|
||||
} else {
|
||||
unchangedOutput.publicAssets.push(asset);
|
||||
}
|
||||
}
|
||||
|
||||
const isOnlyHtmlChanges =
|
||||
changedFiles.length > 0 &&
|
||||
@@ -117,8 +122,8 @@ export function detectDevChanges(
|
||||
function findEffectedSteps(
|
||||
changedFile: string,
|
||||
currentOutput: BuildOutput,
|
||||
): DetectedChange[] {
|
||||
const changes: DetectedChange[] = [];
|
||||
): BuildStepOutput[] {
|
||||
const changes: BuildStepOutput[] = [];
|
||||
const changedPath = normalizePath(changedFile);
|
||||
|
||||
const isChunkEffected = (chunk: OutputFile): boolean =>
|
||||
@@ -135,11 +140,6 @@ function findEffectedSteps(
|
||||
if (effectedChunk) changes.push(step);
|
||||
}
|
||||
|
||||
const effectedAsset = currentOutput.publicAssets.find((chunk) =>
|
||||
isChunkEffected(chunk),
|
||||
);
|
||||
if (effectedAsset) changes.push(effectedAsset);
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
@@ -194,10 +194,3 @@ interface ContentScriptReload extends RebuildChange {
|
||||
type: 'content-script-reload';
|
||||
changedSteps: BuildStepOutput[];
|
||||
}
|
||||
|
||||
/**
|
||||
* When figuring out what needs reloaded, this stores the step that was changed, or the public
|
||||
* directory asset that was changed. It doesn't know what type of change is required yet. Just an
|
||||
* intermediate type.
|
||||
*/
|
||||
type DetectedChange = BuildStepOutput | OutputAsset;
|
||||
|
||||
@@ -104,13 +104,11 @@ export function addViteConfig(
|
||||
): void {
|
||||
wxt.hooks.hook('ready', (wxt) => {
|
||||
const userVite = wxt.config.vite;
|
||||
wxt.config.vite = (env) =>
|
||||
vite.mergeConfig(
|
||||
// Use config added by module as base
|
||||
viteConfig(env) ?? {},
|
||||
// Overwrite module config with user config
|
||||
userVite(env),
|
||||
);
|
||||
wxt.config.vite = async (env) => {
|
||||
const fromUser = await userVite(env);
|
||||
const fromModule = viteConfig(env) ?? {};
|
||||
return vite.mergeConfig(fromModule, fromUser);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { logger } from './utils/logger';
|
||||
|
||||
interface WebSocketMessage {
|
||||
type: string;
|
||||
event: string;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface WxtWebSocket extends WebSocket {
|
||||
addWxtEventListener(
|
||||
type: 'wxt:reload-extension',
|
||||
callback: (event: CustomEvent<undefined>) => void,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
addWxtEventListener(
|
||||
type: 'wxt:reload-content-script',
|
||||
callback?: (event: CustomEvent<ReloadContentScriptPayload>) => void,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
addWxtEventListener(
|
||||
type: 'wxt:reload-page',
|
||||
callback?: (event: CustomEvent<string>) => void,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
sendCustom(event: string, payload?: any): void;
|
||||
}
|
||||
|
||||
let ws: WxtWebSocket | undefined;
|
||||
|
||||
/**
|
||||
* Connect to the websocket and listen for messages.
|
||||
*
|
||||
* @param onMessage Optional callback that is called when a message is recieved and we've verified
|
||||
* it's structure is what we expect.
|
||||
*/
|
||||
export function getDevServerWebSocket(): WxtWebSocket {
|
||||
if (import.meta.env.COMMAND !== 'serve')
|
||||
throw Error(
|
||||
'Must be running WXT dev command to connect to call getDevServerWebSocket()',
|
||||
);
|
||||
|
||||
if (ws == null) {
|
||||
const serverUrl = `${__DEV_SERVER_PROTOCOL__}//${__DEV_SERVER_HOSTNAME__}:${__DEV_SERVER_PORT__}`;
|
||||
logger.debug('Connecting to dev server @', serverUrl);
|
||||
|
||||
ws = new WebSocket(serverUrl, 'vite-hmr') as WxtWebSocket;
|
||||
ws.addWxtEventListener = ws.addEventListener.bind(ws);
|
||||
ws.sendCustom = (event, payload) =>
|
||||
ws?.send(JSON.stringify({ type: 'custom', event, payload }));
|
||||
|
||||
ws.addEventListener('open', () => {
|
||||
logger.debug('Connected to dev server');
|
||||
});
|
||||
ws.addEventListener('close', () => {
|
||||
logger.debug('Disconnected from dev server');
|
||||
});
|
||||
ws.addEventListener('error', (event) => {
|
||||
logger.error('Failed to connect to dev server', event);
|
||||
});
|
||||
|
||||
ws.addEventListener('message', (e) => {
|
||||
try {
|
||||
const message = JSON.parse(e.data) as WebSocketMessage;
|
||||
if (message.type === 'custom') {
|
||||
ws?.dispatchEvent(
|
||||
new CustomEvent(message.event, { detail: message.data }),
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Failed to handle message', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
export interface ReloadContentScriptPayload {
|
||||
registration?: 'manifest' | 'runtime';
|
||||
contentScript: {
|
||||
matches: string[];
|
||||
js?: string[];
|
||||
css?: string[];
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import definition from 'virtual:user-background-entrypoint';
|
||||
import { initPlugins } from 'virtual:wxt-plugins';
|
||||
import { setupWebSocket } from './utils/setup-web-socket';
|
||||
import { getDevServerWebSocket } from '../sandbox/dev-server-websocket';
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
import { browser } from 'wxt/browser';
|
||||
import { keepServiceWorkerAlive } from './utils/keep-service-worker-alive';
|
||||
@@ -8,18 +8,19 @@ import { reloadContentScript } from './utils/reload-content-scripts';
|
||||
|
||||
if (import.meta.env.COMMAND === 'serve') {
|
||||
try {
|
||||
const ws = setupWebSocket((message) => {
|
||||
if (message.event === 'wxt:reload-extension') browser.runtime.reload();
|
||||
if (message.event === 'wxt:reload-content-script' && message.data != null)
|
||||
reloadContentScript(message.data);
|
||||
const ws = getDevServerWebSocket();
|
||||
ws.addWxtEventListener('wxt:reload-extension', () => {
|
||||
browser.runtime.reload();
|
||||
});
|
||||
ws.addWxtEventListener('wxt:reload-content-script', (event) => {
|
||||
reloadContentScript(event.detail);
|
||||
});
|
||||
|
||||
if (import.meta.env.MANIFEST_VERSION === 3) {
|
||||
// Tell the server the background script is loaded and ready to go
|
||||
ws.addEventListener('open', () => {
|
||||
const msg = { type: 'custom', event: 'wxt:background-initialized' };
|
||||
ws.send(JSON.stringify(msg));
|
||||
});
|
||||
ws.addEventListener('open', () =>
|
||||
ws.sendCustom('wxt:background-initialized'),
|
||||
);
|
||||
|
||||
// Web Socket will disconnect if the service worker is killed
|
||||
keepServiceWorkerAlive();
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { logger } from '../sandbox/utils/logger';
|
||||
import { setupWebSocket } from './utils/setup-web-socket';
|
||||
import { getDevServerWebSocket } from '../sandbox/dev-server-websocket';
|
||||
|
||||
if (import.meta.env.COMMAND === 'serve') {
|
||||
try {
|
||||
setupWebSocket((message) => {
|
||||
if (message.event === 'wxt:reload-page') {
|
||||
// We need to remove the initial slash from the path to compare correctly
|
||||
// "popup.html" === "/popup.html".substring(1)
|
||||
if (message.data === location.pathname.substring(1)) {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
const ws = getDevServerWebSocket();
|
||||
ws.addWxtEventListener('wxt:reload-page', (event) => {
|
||||
// "popup.html" === "/popup.html".substring(1)
|
||||
if (event.detail === location.pathname.substring(1)) location.reload();
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error('Failed to setup web socket connection with dev server', err);
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import { browser } from 'wxt/browser';
|
||||
import { logger } from '../../sandbox/utils/logger';
|
||||
import { MatchPattern } from 'wxt/sandbox';
|
||||
|
||||
interface ContentScript {
|
||||
matches: string[];
|
||||
js?: string[];
|
||||
css?: string[];
|
||||
}
|
||||
interface ReloadContentScriptPayload {
|
||||
registration?: 'manifest' | 'runtime';
|
||||
contentScript: ContentScript;
|
||||
}
|
||||
import type { ReloadContentScriptPayload } from '../../sandbox/dev-server-websocket';
|
||||
|
||||
export function reloadContentScript(payload: ReloadContentScriptPayload) {
|
||||
const manifest = browser.runtime.getManifest();
|
||||
@@ -32,6 +23,8 @@ export async function reloadContentScriptMv3({
|
||||
}
|
||||
}
|
||||
|
||||
type ContentScript = ReloadContentScriptPayload['contentScript'];
|
||||
|
||||
export async function reloadManifestContentScriptMv3(
|
||||
contentScript: ContentScript,
|
||||
) {
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import { logger } from '../../sandbox/utils/logger';
|
||||
|
||||
interface WebSocketMessage {
|
||||
type: string;
|
||||
event: string;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the websocket and listen for messages.
|
||||
*
|
||||
* @param onMessage Optional callback that is called when a message is recieved and we've verified
|
||||
* it's structure is what we expect.
|
||||
*/
|
||||
export function setupWebSocket(
|
||||
onMessage?: (message: WebSocketMessage) => void,
|
||||
) {
|
||||
const serverUrl = `${__DEV_SERVER_PROTOCOL__}//${__DEV_SERVER_HOSTNAME__}:${__DEV_SERVER_PORT__}`;
|
||||
logger.debug('Connecting to dev server @', serverUrl);
|
||||
const ws = new WebSocket(serverUrl, 'vite-hmr');
|
||||
|
||||
ws.addEventListener('open', () => {
|
||||
logger.debug('Connected to dev server');
|
||||
});
|
||||
ws.addEventListener('close', () => {
|
||||
logger.debug('Disconnected from dev server');
|
||||
});
|
||||
ws.addEventListener('error', (event) => {
|
||||
logger.error('Failed to connect to dev server', event);
|
||||
});
|
||||
|
||||
ws.addEventListener('message', (e) => {
|
||||
try {
|
||||
const message = JSON.parse(e.data) as WebSocketMessage;
|
||||
if (message.type === 'custom' && message.event?.startsWith?.('wxt:')) {
|
||||
onMessage?.(message);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Failed to handle message', err);
|
||||
}
|
||||
});
|
||||
|
||||
return ws;
|
||||
}
|
||||
Generated
+4
-4
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
'@aklinker1/buildc':
|
||||
specifier: ^1.0.5
|
||||
version: 1.0.5(typescript@5.4.5)
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7(typescript@5.4.5)
|
||||
'@aklinker1/check':
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1(typescript@5.4.5)
|
||||
@@ -377,8 +377,8 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
/@aklinker1/buildc@1.0.5(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-xM9tA6VpkHh2qTCVBwuXUGdBpgxtnj35zrDT0hMBWBLAoAvNXjQrGf4DaFN+gnBsd32TtFPDg1IfcW2ZcUF0ZQ==}
|
||||
/@aklinker1/buildc@1.0.7(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-8njwYe/uxeeyqfj1ryOOwWolNaoJpVjFMoR8muNezo4D6IL6NBNN2XNhqaCShlDBjHM5NG7mdsd/5rueqsKReg==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^5.0.0
|
||||
|
||||
Reference in New Issue
Block a user