Web accessible resources

Expose only the extension assets that web pages or external extension contexts must access.

Extension.js merges user-declared web_accessible_resources with build-discovered requirements and applies target-specific manifest normalization.

WAR capabilities

CapabilityWhat it gives you
MV2/MV3 schema handlingSupport both array and object WAR shapes by manifest version
Build-aware mergingCombine declared resources with required build/runtime entries
Path normalizationResolve manifest WAR paths to target-safe output references
Security control surfaceKeep access rules explicit by resources and matches

Manifest schema

MV3

{
  "web_accessible_resources": [
    {
      "resources": ["images/*.png", "fonts/*.woff2"],
      "matches": ["<all_urls>"]
    }
  ]
}

MV2

{
  "web_accessible_resources": ["images/*.png", "scripts/*.js", "styles/*.css"]
}

Sample manifest.json file

If assets are already imported through supported content-script/build paths, Extension.js can add the required WAR entries automatically. For explicit external access, declare resources manually.

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "web_accessible_resources": [
    {
      "resources": ["images/*.png", "scripts/*.js", "styles/*.css"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_scripts": [
    {
      "matches": ["https://example.com/*"],
      "css": ["styles/content.css"],
      "js": ["scripts/content.js"]
    }
  ]
}

What Extension.js adds automatically

Extension.js can expand WAR entries from build output when the runtime needs those assets to be page-accessible.

Common examples include:

  • assets imported by content scripts
  • content-script CSS outputs
  • emitted fonts or static assets referenced by those entries
  • development-only runtime support needed for reload behavior

Automatic inclusion is convenient, but it is not a substitute for reviewing the final exposure surface.

Development behavior

  • In development, Extension.js patches WAR entries to support reload/HMR-related asset access.
  • Content-script related assets can be auto-included in WAR when needed.
  • Path normalization removes public/ and leading / conventions into extension output-safe paths.

Output and resolution notes

  • Resources in public/ are copied by the public-asset flow and can be declared from extension root paths.
  • Relative WAR resource paths resolve from manifest directory.
  • Globs are supported, but match patterns must be valid for target browser constraints.
  • MV3 entries without resources are dropped during normalization.
  • Globs are preserved as globs; Extension.js does not expand them into explicit file lists for you.

Runtime usage

Use browser runtime URL helpers instead of constructing extension URLs manually:

const logoUrl = chrome.runtime.getURL('/images/logo.png')

If a page or content script cannot read an asset you expected to be accessible, check:

  1. whether the asset is actually present in the output
  2. whether the WAR entry exposes the correct resources
  3. whether the matches scope includes the page that is trying to read it
  4. whether the asset should instead stay private to extension pages only

Best practices

  • Keep WAR entries minimal; expose only what external contexts must read.
  • Prefer explicit resource paths over broad globs for tighter security posture.
  • Validate WAR match patterns and resource paths across Chromium and Firefox targets.
  • Use chrome.runtime.getURL()/browser.runtime.getURL() for runtime-safe URL creation.
  • Re-audit WAR after adding content-script imports, fonts, or page-accessible static assets.

Security checklist

  • Limit matches scope to domains that actually require access.
  • Avoid broad wildcard resource globs when a small explicit list is sufficient.
  • Keep WAR entries focused on non-sensitive assets.
  • Re-audit WAR when adding new content script imports or runtime asset lookups.

Good vs risky examples

{
  "web_accessible_resources": [
    {
      "resources": ["images/logo.png", "fonts/inter.woff2"],
      "matches": ["https://example.com/*"]
    }
  ]
}
{
  "web_accessible_resources": [
    {
      "resources": ["*"],
      "matches": ["<all_urls>"]
    }
  ]
}

Next steps