Skip to content

Commit

Permalink
feat: Reload HTML files individually (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
aklinker1 authored Jul 3, 2023
1 parent 684197d commit cd714ea
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 26 deletions.
8 changes: 2 additions & 6 deletions e2e/tests/output-structure.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,12 @@ describe('Output Directory Structure', () => {
================================================================================
.output/chrome-mv3/content-scripts/one.js
----------------------------------------
(function(){\\"use strict\\";function c(n){return n}const e=\\"\\",t={matches:[\\"*://*/*\\"],main:()=>{}};(async()=>{try{await t.main()}catch(n){console.error(\`The content script crashed on startup!
\`,n)}})()})();
(function(){\\"use strict\\";function i(n){return n}const s=\\"\\",o={matches:[\\"*://*/*\\"],main:()=>{}};function t(n,...e){if(typeof e[0]==\\"string\\"){const c=e.shift();n(\`[wxt] \${c}\`,...e)}else n(\\"[wxt]\\",...e)}var r={debug:(...n)=>t(console.debug,...n),log:(...n)=>t(console.log,...n),warn:(...n)=>t(console.warn,...n),error:(...n)=>t(console.error,...n)};(async()=>{try{await o.main()}catch(n){r.error(\\"The content script crashed on startup!\\",n)}})()})();
================================================================================
.output/chrome-mv3/content-scripts/two.js
----------------------------------------
(function(){\\"use strict\\";function c(n){return n}const e=\\"\\",t={matches:[\\"*://*/*\\"],main:()=>{}};(async()=>{try{await t.main()}catch(n){console.error(\`The content script crashed on startup!
\`,n)}})()})();
(function(){\\"use strict\\";function i(n){return n}const s=\\"\\",o={matches:[\\"*://*/*\\"],main:()=>{}};function t(n,...e){if(typeof e[0]==\\"string\\"){const c=e.shift();n(\`[wxt] \${c}\`,...e)}else n(\\"[wxt]\\",...e)}var r={debug:(...n)=>t(console.debug,...n),log:(...n)=>t(console.log,...n),warn:(...n)=>t(console.warn,...n),error:(...n)=>t(console.error,...n)};(async()=>{try{await o.main()}catch(n){r.error(\\"The content script crashed on startup!\\",n)}})()})();
================================================================================
.output/chrome-mv3/manifest.json
Expand Down
16 changes: 12 additions & 4 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,24 @@ await Promise.all([
silent: true,
}),
...clientTemplates.map((templateName) =>
tsup.build({
tsup.build({
entry: {
[`templates/virtual-${templateName}`]: `src/client/templates/virtual-${templateName}.ts`,
},
format: ['esm'],
sourcemap: true,
silent: true,
external: [`virtual:user-${templateName}`],
}),
),
tsup.build({
entry: {
'templates/reload-html': `src/client/templates/reload-html.ts`,
},
format: ['esm'],
sourcemap: true,
silent: true,
external: [`virtual:user-${templateName}`],
}),
),
}),
]).catch((err) => {
spinner.fail();
console.error(err);
Expand Down
20 changes: 20 additions & 0 deletions src/client/templates/reload-html.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// <reference types="vite/client" />

import { logger } from '../utils/logger';
import { setupWebSocket } from '../utils/setupWebSocket';

if (__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();
}
}
});
} catch (err) {
logger.error('Failed to setup web socket connection with dev server', err);
}
}
3 changes: 2 additions & 1 deletion src/client/templates/virtual-content-script.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import definition from 'virtual:user-content-script';
import { logger } from '../utils/logger';

(async () => {
try {
await definition.main();
} catch (err) {
console.error('The content script crashed on startup!\n\n', err);
logger.error('The content script crashed on startup!', err);
}
})();
1 change: 0 additions & 1 deletion src/client/utils/setupWebSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export function setupWebSocket(
try {
const message = JSON.parse(e.data) as WebSocketMessage;
if (message.type === 'custom' && message.event?.startsWith?.('wxt:')) {
logger.debug(`Recieved message: ${message.event}`, message);
onMessage?.(message);
}
} catch (err) {
Expand Down
12 changes: 12 additions & 0 deletions src/core/types/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ export interface WxtDevServer extends vite.ViteDevServer {
* Tell the extension to reload by running `browser.runtime.reload`.
*/
reloadExtension: () => void;
/**
* Tell an extension page to reload.
*
* The path is the bundle path, not the input paths, so if the input paths is
* "src/options/index.html", you would pass "options.html" because that's where it is written to
* in the dist directory, and where it's available at in the actual extension.
*
* @example
* server.reloadPage("popup.html")
* server.reloadPage("sandbox.html")
*/
reloadPage: (path: string) => void;
}

export type TargetBrowser = 'chrome' | 'firefox' | 'safari' | 'edge' | 'opera';
Expand Down
28 changes: 15 additions & 13 deletions src/core/utils/detectDevChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ export function detectDevChanges(
}
}

const isOnlyHtmlChanges = !changedFiles.find(
([_, file]) => !file.endsWith('.html'),
);
if (isOnlyHtmlChanges) {
return {
type: 'html-reload',
cachedOutput: unchangedOutput,
rebuildGroups: changedOutput.steps.map((step) => step.entrypoints),
};
}

return {
type: 'extension-reload',
cachedOutput: unchangedOutput,
Expand Down Expand Up @@ -103,10 +114,7 @@ function findEffectedSteps(
* Contains information about what files changed, what needs rebuilt, and the type of reload that is
* required.
*/
export type DevModeChange =
| NoChange
// | HtmlReload
| ExtensionReload;
export type DevModeChange = NoChange | HtmlReload | ExtensionReload;
// | BrowserRestart
// | ContentScriptReload

Expand All @@ -125,15 +133,9 @@ interface RebuildChange {
cachedOutput: BuildOutput;
}

/**
* This is separate from `ExtensionReload` because if an HTML file changes, for some browsers,
* reloading the current page is enough to pull from the latest change. Simply reloading the page is
* less destructive then reloading the entire extension (content scripts aren't invalidated, tabs to
* extension pages aren't closed, etc).
*/
// interface HtmlReload extends RebuildChange {
// type: 'html-reload';
// }
interface HtmlReload extends RebuildChange {
type: 'html-reload';
}

interface ExtensionReload extends RebuildChange {
type: 'extension-reload';
Expand Down
21 changes: 21 additions & 0 deletions src/core/vite-plugins/devHtmlPrerender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ export function devHtmlPrerender(config: InternalConfig): vite.Plugin {
return {
apply: 'build',
name: 'wxt:dev-html-prerender',
config(userConfig) {
return vite.mergeConfig(
{
resolve: {
alias: {
'@wxt/reload-html': resolve(
config.root,
'node_modules/wxt/dist/templates/reload-html.js',
),
},
},
},
userConfig,
);
},
async transform(html, id) {
const server = config.server;
if (config.command !== 'serve' || server == null || !id.endsWith('.html'))
Expand Down Expand Up @@ -43,6 +58,12 @@ export function devHtmlPrerender(config: InternalConfig): vite.Plugin {
pointToDevServer('script[type=module]', 'src');
pointToDevServer('link[rel=stylesheet]', 'href');

// Add a script to add page reloading
const reloader = document.createElement('script');
reloader.src = '@wxt/reload-html';
reloader.type = 'module';
document.head.appendChild(reloader);

const newHtml = document.toString();
config.logger.debug('Transformed ' + id);
config.logger.debug('Old HTML:\n' + html);
Expand Down
21 changes: 20 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import { detectDevChanges } from './core/utils/detectDevChanges';
import { Mutex } from 'async-mutex';
import { consola } from 'consola';
import { relative } from 'node:path';
import { getEntrypointOutputFile } from './core/utils/entrypoints';
import {
getEntrypointBundlePath,
getEntrypointOutputFile,
} from './core/utils/entrypoints';

export { version } from '../package.json';
export * from './core/types/external';
Expand Down Expand Up @@ -106,6 +109,17 @@ export async function createServer(
server.reloadExtension();
consola.success(`Reloaded extension: ${rebuiltNames}`);
break;
case 'html-reload':
changes.rebuildGroups.flat().forEach((entry) => {
const path = getEntrypointBundlePath(
entry,
internalConfig.outDir,
'.html',
);
server.reloadPage(path);
});
consola.success(`Reloaded pages: ${rebuiltNames}`);
break;
}
});
});
Expand All @@ -130,6 +144,11 @@ export async function createServer(
reloadExtension: () => {
server.ws.send('wxt:reload-extension');
},
reloadPage: (path) => {
// Can't use Vite's built-in "full-reload" event because it doesn't like our paths, it expects
// paths ending in "/index.html"
server.ws.send('wxt:reload-page', path);
},
};
internalConfig.logger.info('Created dev server');

Expand Down

0 comments on commit cd714ea

Please sign in to comment.