diff --git a/docs/guide/essentials/favicon.md b/docs/guide/essentials/favicon.md new file mode 100644 index 000000000..3b509d6f1 --- /dev/null +++ b/docs/guide/essentials/favicon.md @@ -0,0 +1,65 @@ +# Favicons + +[Chrome Docs: How to fetch favicons](https://developer.chrome.com/docs/extensions/how-to/ui/favicons) + +#### What happens when you add favicons permissions in wxt.config.ts? + +WXT automatically adds value in `web_accessible_resources` with default value and updates the types for favicon. + +This is automatically added in manifest.json + +```js +"web_accessible_resources": [ + { + "resources": ["_favicon/*"], + "matches": [], + } + ] + +``` + +#### If you want to add custom values in `matches` parameter you can either add by hook or WXT modules. + +1. Via hook in wxt.config.ts + +```js + +import { defineConfig } from "wxt"; +// See https://wxt.dev/api/config.html +export default defineConfig({ + modules: ["@wxt-dev/module-react"], + hooks: { + "build:manifestGenerated": (_, manifest) => { + const favicon_resource: any = manifest.web_accessible_resources?.find( + (resource: any) => resource.includes("favicon") + ); + favicon_resource.matches?.push(""); + manifest.web_accessible_resources ??= []; + manifest.web_accessible_resources?.push(favicon_resource); + }, + }, +}); + +``` + +2. Via custom module + +- Follow the guide for [creating modules](https://wxt.dev/guide/essentials/wxt-modules.html#writing-modules) and paste this below code. + +```js + +import { defineWxtModule } from "wxt/modules"; + +export default defineWxtModule({ + setup(wxt) { + wxt.hooks.hook("build:manifestGenerated", (_, manifest) => { + const favicon_resource: any = manifest.web_accessible_resources?.find( + (resource: any) => resource.includes("favicon") + ); + favicon_resource.matches?.push(""); + manifest.web_accessible_resources ??= []; + manifest.web_accessible_resources?.push(favicon_resource); + }); + }, +}); +``` diff --git a/packages/wxt/e2e/tests/typescript-project.test.ts b/packages/wxt/e2e/tests/typescript-project.test.ts index 35d35a6aa..c02449b09 100644 --- a/packages/wxt/e2e/tests/typescript-project.test.ts +++ b/packages/wxt/e2e/tests/typescript-project.test.ts @@ -397,6 +397,61 @@ describe('TypeScript Project', () => { expect(output).toContain('./example.ts'); }); + it('should include favicon types in browser.runtime.getURL and in manifest web_accessible_resources ', async () => { + const project = new TestProject(); + project.addFile('entrypoints/popup.html', ''); + project.addFile('entrypoints/options.html', ''); + project.addFile('entrypoints/sandbox.html', ''); + + await project.prepare({ + manifest: { + permissions: ['favicon'], + }, + }); + + await project.build({ + manifest: { + permissions: ['favicon'], + }, + }); + + const output = await project.serializeFile('.wxt/types/paths.d.ts'); + const manifestOutput = await project.getOutputManifest(); + + const expectedWebAccessibleResource = [ + { + resources: ['/_favicon/*'], + matches: [], + }, + ]; + + expect(manifestOutput.web_accessible_resources).toEqual( + expectedWebAccessibleResource, + ); + expect(output).toMatchInlineSnapshot(` + ".wxt/types/paths.d.ts + ---------------------------------------- + // Generated by wxt + import "wxt/browser"; + + declare module "wxt/browser" { + export type PublicPath = + | "" + | "/" + | "/_favicon/?\${string}\" + | "/options.html" + | "/popup.html" + | "/sandbox.html" + type HtmlPublicPath = Extract + export interface WxtRuntime { + getURL(path: PublicPath): string; + getURL(path: \`\${HtmlPublicPath}\${string}\`): string; + } + } + " + `); + }); + it('should set correct import.meta.env.BROWSER type based on targetBrowsers', async () => { const project = new TestProject(); project.addFile('entrypoints/unlisted.html', ''); diff --git a/packages/wxt/src/builtin-modules/favicon-permission.ts b/packages/wxt/src/builtin-modules/favicon-permission.ts new file mode 100644 index 000000000..a9db889fe --- /dev/null +++ b/packages/wxt/src/builtin-modules/favicon-permission.ts @@ -0,0 +1,20 @@ +import { defineWxtModule } from '../modules'; + +export default defineWxtModule({ + name: 'wxt:built-in:favicon-permission', + setup(wxt) { + wxt.hooks.hook('prepare:publicPaths', async (wxt, paths) => { + if (wxt.config.manifest.permissions?.includes('favicon')) { + paths.push('_favicon/?${string}'); + wxt.hooks.hook('build:manifestGenerated', (_, manifest) => { + const favicon_resource: any = { + resources: ['/_favicon/*'], + matches: [], + }; + manifest.web_accessible_resources ??= []; + manifest.web_accessible_resources?.push(favicon_resource); + }); + } + }); + }, +}); diff --git a/packages/wxt/src/builtin-modules/index.ts b/packages/wxt/src/builtin-modules/index.ts index d958b95b4..7f3c032dc 100644 --- a/packages/wxt/src/builtin-modules/index.ts +++ b/packages/wxt/src/builtin-modules/index.ts @@ -1,4 +1,5 @@ import { WxtModule } from '../types'; import unimport from './unimport'; +import faviconPermission from './favicon-permission'; -export const builtinModules: WxtModule[] = [unimport]; +export const builtinModules: WxtModule[] = [unimport, faviconPermission];