feat(DX): Add ctrl+E/cmd+E shortcut to reload extension during development (#322)

This commit is contained in:
Aaron
2024-01-02 12:06:22 -06:00
committed by GitHub
parent 1af64aa02f
commit 4f649fc872
5 changed files with 119 additions and 0 deletions
+10
View File
@@ -57,3 +57,13 @@ export default defineRunnerConfig({
:::tip
When configuring browser binaries, it's helpful to put them in `~/web-ext.config.ts` instead of the project directory's `web-ext.config.ts` file. When placed in your home directory (`~/`), this config will be used by all WXT projects, so you only need to configure the binaries once.
:::
## Reload the Extension
Normally, to manually reload an extension, you have to visit `chrome://extensions` and click the reload button for your extension.
When running `wxt` command to start the dev server, WXT adds a keyboard shortcut, `ctrl+E` for Windows/Linux and `cmd+E` for Mac, that reloads the extension when pressed, without visiting `chrome://extensions`.
:::note
This shortcut is only available during development, and is not be added to your extension when running `wxt build` or `wxt-zip`.
:::
+70
View File
@@ -0,0 +1,70 @@
import { describe, expect, it } from 'vitest';
import { generateMainfest } from '../manifest';
import {
fakeArray,
fakeBuildOutput,
fakeEntrypoint,
fakeInternalConfig,
} from '../testing/fake-objects';
describe('Manifest Utils', () => {
describe('generateManifest', () => {
describe('Development reload command', () => {
const reloadCommandName = 'wxt:reload-extension';
const reloadCommand = {
suggested_key: {
default: 'Ctrl+E',
},
};
it('should include a command for reloading the extension', async () => {
const config = fakeInternalConfig({ command: 'serve' });
const output = fakeBuildOutput();
const entrypoints = fakeArray(fakeEntrypoint);
const actual = await generateMainfest(entrypoints, output, config);
expect(actual.commands).toMatchObject({
[reloadCommandName]: reloadCommand,
});
});
it('should not override any existing commands when adding the one to reload the extension', async () => {
const customCommandName = 'custom-command';
const customCommand = {
description: 'Some other command',
suggested_key: {
default: 'Ctrl+H',
},
};
const config = fakeInternalConfig({
command: 'serve',
manifest: {
commands: {
[customCommandName]: customCommand,
},
},
});
const output = fakeBuildOutput();
const entrypoints = fakeArray(fakeEntrypoint);
const actual = await generateMainfest(entrypoints, output, config);
expect(actual.commands).toMatchObject({
[reloadCommandName]: reloadCommand,
[customCommandName]: customCommand,
});
});
it('should not include the command when building an extension', async () => {
const config = fakeInternalConfig({ command: 'build' });
const output = fakeBuildOutput();
const entrypoints = fakeArray(fakeEntrypoint);
const actual = await generateMainfest(entrypoints, output, config);
expect(actual.commands).toBeUndefined();
});
});
});
});
+10
View File
@@ -73,6 +73,16 @@ export async function generateMainfest(
short_name: pkg?.shortName,
icons: discoverIcons(buildOutput),
};
if (config.command === 'serve') {
baseManifest.commands = {
'wxt:reload-extension': {
description: 'Reload the extension during development',
suggested_key: {
default: 'Ctrl+E',
},
},
};
}
const userManifest = config.manifest;
const manifest = defu(
+23
View File
@@ -17,6 +17,8 @@ import {
OutputChunk,
OutputFile,
OutputAsset,
BuildOutput,
BuildStepOutput,
} from '~/types';
import { mock } from 'vitest-mock-extended';
@@ -39,6 +41,16 @@ export function fakeDir(root = process.cwd()): string {
return resolve(root, faker.string.alphanumeric());
}
export const fakeEntrypoint = () =>
faker.helpers.arrayElement([
fakePopupEntrypoint,
fakeGenericEntrypoint,
fakeOptionsEntrypoint,
fakeBackgroundEntrypoint,
fakeContentScriptEntrypoint,
fakeUnlistedScriptEntrypoint,
])();
export const fakeContentScriptEntrypoint =
fakeObjectCreator<ContentScriptEntrypoint>(() => ({
type: 'content-script',
@@ -222,3 +234,14 @@ export const fakeInternalConfig = fakeObjectCreator<InternalConfig>(() => {
builder: mock(),
};
});
export const fakeBuildOutput = fakeObjectCreator<BuildOutput>(() => ({
manifest: fakeManifest(),
publicAssets: fakeArray(fakeOutputAsset),
steps: fakeArray(fakeBuildStepOutput),
}));
export const fakeBuildStepOutput = fakeObjectCreator<BuildStepOutput>(() => ({
chunks: fakeArray(fakeOutputChunk),
entrypoints: fakeArray(fakeEntrypoint),
}));
+6
View File
@@ -26,6 +26,12 @@ if (__COMMAND__ === 'serve') {
} 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();
}
});
}
try {