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>.
Path resolution runs in two places:
runtime.getURL, tabs.update, scripting.*, action.*, sidePanel.*).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 -> .cssTo avoid false positives, these inputs are intentionally skipped:
http:// and https:// URLsdata: URLschrome:// URLsmoz-extension:// URLs*, ?, {}, [])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>.
For browser APIs like chrome.runtime.getURL(), prefer stable, output-root paths:
Output: chrome-extension:<extension-id>/icons/icon.png
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.
pages/, scripts/, and public/ at project root for predictable rewrites./public/... as output-root assets and avoid source-relative assumptions at runtime.dev as they usually indicate path mismatches before packaging.