🛣️

Predictable path resolution

Write paths the way you naturally author them, and let Extension.js normalize them to runtime-safe output paths.

Keep runtime paths working when files move, entries are renamed, or browser targets change. Extension.js rewrites supported paths consistently across manifest fields and extension API usage so compiled assets resolve correctly inside dist/<browser>.

How it works

Path resolution runs in two places:

  • Manifest compilation pipeline: resolves manifest-declared paths to emitted assets.
  • Resolve plugin for JS/TS: rewrites static path literals passed to supported extension APIs (for example runtime.getURL, tabs.update, scripting.*, action.*, sidePanel.*).

Supported input styles

Common path inputs are normalized as follows:

Input style Example Normalized output
Public root (absolute) /public/icons/icon.png icons/icon.png
Public root (relative) public/icons/icon.png, ./public/icons/icon.png icons/icon.png
Root absolute /foo/bar.js foo/bar.js
Root special folder /pages/popup.njk pages/popup.html
Special folders pages/popup.html, scripts/content.tsx pages/popup.html, scripts/content.js
Parent-relative from author file ../scripts/content.ts scripts/content.js (when resolving to project root special folder)

Extension mapping for pages/ and scripts/ includes:

  • .ts, .tsx, .js, .jsx -> .js
  • .njk, .nunjucks, .html -> .html
  • .scss, .sass, .less, .css -> .css

Video demo soon: path normalization flow

Cases intentionally not rewritten

To avoid false positives, these inputs are intentionally skipped:

  • http:// and https:// URLs
  • data: URLs
  • chrome:// URLs
  • moz-extension:// URLs
  • Glob patterns (*, ?, {}, [])
  • Non-static/dynamic expressions that cannot be safely resolved at build time

Manifest output examples

Assuming target browser chrome:

Manifest field Input Path Output Path
action.default_popup /src/popup.html /pages/popup.html
background.page /src/background.html /pages/background.html
background.service_worker /src/background.js /scripts/background.js
browser_action.default_popup /src/browser_action.html /pages/browser_action.html
chrome_url_overrides.bookmarks /src/bookmarks.html /pages/bookmarks.html
chrome_url_overrides.history /src/history.html /pages/history.html
chrome_url_overrides.newtab /src/newtab.html /pages/newtab.html
content_scripts.js /src/content_script.js /scripts/content_script.js
content_scripts.css /src/content_style.css /pages/content_style.css
declarative_net_request.rule_resources /src/rules.json /pages/rules.json
devtools_page /src/devtools.html /pages/devtools.html
icons /src/icons/icon.png /public/icons/icon.png
options_ui.page /src/options.html /pages/options.html
page_action.default_popup /src/page_action.html /pages/page_action.html
sandbox.pages /src/sandbox.html /pages/sandbox.html
sidepanel /src/sidepanel.html /pages/sidepanel.html
sidebar_action.default_panel /src/sidebar_panel.html /pages/sidebar_panel.html
storage.managed_schema /src/storage_schema.json /pages/storage_schema.json
theme_icons /src/theme_icons/icon.svg /public/theme_icons/icon.svg
user_scripts.api_script /src/user_script.js /scripts/user_script.js
web_accessible_resources /src/resources/* /public/resources/*

All compiled outputs are emitted under dist/<browser>.

Video demo soon: manifest path rewrite example

Referencing output files

For browser APIs like chrome.runtime.getURL(), prefer stable, output-root paths:

const iconUrl = chrome.runtime.getURL("/icons/icon.png");
console.log(iconUrl);

Output: chrome-extension:<extension-id>/icons/icon.png

Video demo soon: runtime getURL path resolution

Diagnostics and safety checks

The resolver emits warnings when a referenced path cannot be resolved to a packaged asset (for example, nested src/pages/... or missing public/ files after rewrite).
Warnings are de-duplicated per file transform pass to reduce noise.

Best practices

  • Keep pages/, scripts/, and public/ at project root for predictable rewrites.
  • Use static literals for extension API paths when possible; dynamic expressions may be skipped.
  • Treat /public/... as output-root assets and avoid source-relative assumptions at runtime.
  • Validate warnings during dev as they usually indicate path mismatches before packaging.

Next steps