Skip to content
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

fix(security): Use import.meta.hot for communication with Vite 6.0.9+ (and 5.4.14+) dev server #1411

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion packages/wxt-demo/src/entrypoints/background.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export default defineBackground({
// type: 'module',
type: 'module',

main() {
console.log(browser.runtime.id);
Expand Down
3 changes: 3 additions & 0 deletions packages/wxt/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ export default defineBuildConfig([
...virtualEntrypointModuleNames.map((name) => `virtual:user-${name}`),
'virtual:wxt-plugins',
'virtual:app-config',
'wxt/background-client',
'wxt/browser',
'wxt/sandbox',
'wxt/client',
'wxt/testing',
'http://localhost:3000/@id/wxt/background-client',
'http://localhost:3000/@vite/client',
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO:

Suggested change
'http://localhost:3000/@id/wxt/background-client',
'http://localhost:3000/@vite/client',
'__DEV_SERVER_ORIGIN__/@id/wxt/background-client',
'__DEV_SERVER_ORIGIN__/@vite/client',

],
})),
]);
Expand Down
6 changes: 5 additions & 1 deletion packages/wxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
"./modules": {
"types": "./dist/modules.d.ts",
"default": "./dist/modules.mjs"
},
"./background-client": {
"types": "./dist/background-client.d.ts",
"default": "./dist/background-client.mjs"
}
},
"scripts": {
Expand Down Expand Up @@ -123,7 +127,7 @@
"publish-browser-extension": "^2.2.2",
"scule": "^1.3.0",
"unimport": "^3.13.1",
"vite": "^5.0.0 || ^6.0.0",
"vite": "^5.0.0 || <=6.0.8",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"vite": "^5.0.0 || <=6.0.8",
"vite": "^5.0.0 || ^6.0.0",

"vite-node": "^2.1.4",
"web-ext-run": "^0.2.1",
"webextension-polyfill": "^0.12.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,48 @@
import { browser } from 'wxt/browser';
import { logger } from '../../sandbox/utils/logger';
import { logger } from './sandbox/utils/logger';
import { MatchPattern } from 'wxt/sandbox';
import type { ReloadContentScriptPayload } from '../../sandbox/dev-server-websocket';

export function reloadContentScript(payload: ReloadContentScriptPayload) {
console.log('HOT', import.meta.hot);
if (import.meta.hot) {
import.meta.hot.on('wxt:reload-extension', () => browser.runtime.reload());
import.meta.hot.on('wxt:reload-content-script', (event) =>
reloadContentScript(event),
);

if (import.meta.env.MANIFEST_VERSION === 3) {
let backgroundInitialized = false;
// Tell the server the background script is loaded and ready to go
import.meta.hot.on('vite:ws:connect', () => {
if (backgroundInitialized) return;

import.meta.hot?.send('wxt:background-initialized');
backgroundInitialized = true;
});

// Web Socket will disconnect if the service worker is killed
keepServiceWorkerAlive();
}

browser.commands.onCommand.addListener((command) => {
if (command === 'wxt:reload-extension') {
browser.runtime.reload();
}
});
} else {
console.error('[wxt] HMR Context not found');
}

/**
* https://developer.chrome.com/blog/longer-esw-lifetimes/
*/
function keepServiceWorkerAlive() {
setInterval(async () => {
// Calling an async browser API resets the service worker's timeout
await browser.runtime.getPlatformInfo();
}, 5e3);
}

function reloadContentScript(payload: ReloadContentScriptPayload) {
const manifest = browser.runtime.getManifest();
if (manifest.manifest_version == 2) {
void reloadContentScriptMv2(payload);
Expand All @@ -12,7 +51,7 @@ export function reloadContentScript(payload: ReloadContentScriptPayload) {
}
}

export async function reloadContentScriptMv3({
async function reloadContentScriptMv3({
registration,
contentScript,
}: ReloadContentScriptPayload) {
Expand All @@ -25,9 +64,7 @@ export async function reloadContentScriptMv3({

type ContentScript = ReloadContentScriptPayload['contentScript'];

export async function reloadManifestContentScriptMv3(
contentScript: ContentScript,
) {
async function reloadManifestContentScriptMv3(contentScript: ContentScript) {
const id = `wxt:${contentScript.js![0]}`;
logger.log('Reloading content script:', contentScript);
const registered = await browser.scripting.getRegisteredContentScripts();
Expand All @@ -46,9 +83,7 @@ export async function reloadManifestContentScriptMv3(
await reloadTabsForContentScript(contentScript);
}

export async function reloadRuntimeContentScriptMv3(
contentScript: ContentScript,
) {
async function reloadRuntimeContentScriptMv3(contentScript: ContentScript) {
logger.log('Reloading content script:', contentScript);
const registered = await browser.scripting.getRegisteredContentScripts();
logger.debug('Existing scripts:', registered);
Expand Down Expand Up @@ -92,8 +127,15 @@ async function reloadTabsForContentScript(contentScript: ContentScript) {
);
}

export async function reloadContentScriptMv2(
_payload: ReloadContentScriptPayload,
) {
async function reloadContentScriptMv2(_payload: ReloadContentScriptPayload) {
throw Error('TODO: reloadContentScriptMv2');
}

interface ReloadContentScriptPayload {
registration?: 'manifest' | 'runtime';
contentScript: {
matches: string[];
js?: string[];
css?: string[];
};
}
85 changes: 0 additions & 85 deletions packages/wxt/src/sandbox/dev-server-websocket.ts

This file was deleted.

41 changes: 9 additions & 32 deletions packages/wxt/src/virtual/background-entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,17 @@
import definition from 'virtual:user-background-entrypoint';
import { initPlugins } from 'virtual:wxt-plugins';
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';
import { reloadContentScript } from './utils/reload-content-scripts';

if (import.meta.env.COMMAND === 'serve') {
try {
const ws = getDevServerWebSocket();
ws.addWxtEventListener('wxt:reload-extension', () => {
browser.runtime.reload();
});
ws.addWxtEventListener('wxt:reload-content-script', (event) => {
reloadContentScript(event.detail);
});
// Works for MV3 + type:module
// /* @vite-ignore */
// import 'http://localhost:3000/@id/wxt/background-client';

if (import.meta.env.MANIFEST_VERSION === 3) {
// Tell the server the background script is loaded and ready to go
ws.addEventListener('open', () =>
ws.sendCustom('wxt:background-initialized'),
);

// Web Socket will disconnect if the service worker is killed
keepServiceWorkerAlive();
}
} catch (err) {
logger.error('Failed to setup web socket connection with dev server', err);
}

browser.commands.onCommand.addListener((command) => {
if (command === 'wxt:reload-extension') {
browser.runtime.reload();
}
});
}
// Works for MV2
// import(
// /* @vite-ignore */
// // @ts-ignore
// 'http://localhost:3000/@id/wxt/background-client'
// );

let result;

Expand Down
18 changes: 5 additions & 13 deletions packages/wxt/src/virtual/reload-html.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import { logger } from '../sandbox/utils/logger';
import { getDevServerWebSocket } from '../sandbox/dev-server-websocket';

if (import.meta.env.COMMAND === 'serve') {
try {
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);
}
if (import.meta.hot) {
import.meta.hot.on('wxt:reload-page', (event) => {
// "popup.html" === "/popup.html".substring(1)
if (event.detail === location.pathname.substring(1)) location.reload();
});
}
Comment on lines +1 to 6
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Test

11 changes: 0 additions & 11 deletions packages/wxt/src/virtual/utils/keep-service-worker-alive.ts

This file was deleted.