Building Cross‑Browser Extensions with Extension Builder: A Step‑by‑Step Tutorial
This tutorial shows a clear, practical path to build a single browser extension that works in Chrome, Firefox, and Edge using Extension Builder. It assumes basic JavaScript/HTML/CSS knowledge and that you have Node.js (v14+) and npm installed.
What you’ll build
A simple extension that adds a toolbar button. When clicked it opens a popup showing the current page’s title and a button to copy the page URL.
Project structure
Code
extension-builder-crossbrowser/ ├─ src/ │├─ popup.html │ ├─ popup.js │ └─ popup.css ├─ manifest.json ├─ extension-builder.config.js └─ package.json
Step 1 — Initialize project
- Create project folder and enter it.
- Run:
bash
npm init -y npm install –save-dev extension-builder
- Add scripts to package.json:
json
“scripts”: { “build”: “extension-builder build”, “watch”: “extension-builder watch” }
Step 2 — Write the manifest (cross-browser)
Create a single manifest.json compatible with Manifest V2 and V3 differences handled by Extension Builder. Use a minimal, cross-browser manifest:
json
{ “manifest_version”: 2, “name”: “CrossBrowser URL Copier”, “version”: “1.0.0”, “description”: “Copies the current page URL from a popup.”, “icons”: { “48”: “icons/icon48.png”, “128”: “icons/icon128.png” }, “browser_action”: { “default_popup”: “src/popup.html”, “default_title”: “URL Copier” }, “permissions”: [“activeTab”, “clipboardWrite”] }
Notes:
- Extension Builder can transform manifests for target browsers (e.g., convert browseraction to action for Manifest V3).
- Keep permissions minimal.
Step 3 — Popup HTML, CSS, and JS
Create src/popup.html:
html
<!doctype html> <html> <head> <meta charset=“utf-8” /> <link rel=“stylesheet” href=“popup.css” /> </head> <body> <h1 id=“title”>Page Title</h1> <button id=“copyBtn”>Copy URL</button> <script src=“popup.js”></script> </body> </html>
Create src/popup.css with simple styling.
Create src/popup.js:
javascript
document.addEventListener(‘DOMContentLoaded’, async () => { const titleEl = document.getElementById(‘title’); const copyBtn = document.getElementById(‘copyBtn’); // Get current tab title and URL const [tab] = await chrome.tabs ? chrome.tabs.query({active: true, currentWindow: true}) : browser.tabs.query({active: true, currentWindow: true}); titleEl.textContent = tab.title || ‘No title’; copyBtn.addEventListener(‘click’, async () => { try { await navigator.clipboard.writeText(tab.url); copyBtn.textContent = ‘Copied!’; setTimeout(() => copyBtn.textContent = ‘Copy URL’, 1400); } catch (err) { console.error(err); copyBtn.textContent = ‘Failed’; } }); });
Compatibility note:
- Use chrome.* APIs in Chrome/Edge and browser.* in Firefox. Extension Builder can polyfill or you can include a tiny wrapper:
javascript
const browserApi = window.browser ?? window.chrome;
Then use browserApi.tabs.query(…).
Step 4 — Extension Builder configuration
Create extension-builder.config.js to define targets and build transforms:
javascript
module.exports = { input: ‘src’, output: ‘dist’, manifest: ‘manifest.json’, targets: { chrome: { manifest_version: 3, convert: true }, firefox: { manifest_version: 2, convert: true }, edge: { manifestversion: 3, convert: true } }, polyfills: [‘webextension-polyfill’] };
Explanation:
- convert: true tells Extension Builder to adapt manifest and APIs.
- polyfills option injects the Mozilla webextension polyfill for Promise-based browser.* in Chrome.
Step 5 — Build and test locally
- Run build:
bash
npm run build
- Load unpacked extension:
- Chrome/Edge: go to chrome://extensions, enable Developer mode, Load unpacked → select dist folder.
- Firefox: go to about:debugging → This Firefox → Load Temporary Add-on → select dist/manifest.json.
- Test the popup on different pages, ensure copy works and title displays.
Step 6 — Handle browser differences & debugging tips
- Permissions: Firefox may require host permissions expressed differently; keep optional_hostpermissions if needed.
- APIs: Use webextension-polyfill to smooth chrome/browser differences.
- Manifest V3: Service workers behave differently; for persistent background tasks prefer event-based patterns.
- Console logs: Use each browser’s extension console (inspect popup or background/service worker) for debugging.
Step 7 — Prepare for publishing
- Create browser-specific builds if required by store policies. Example scripts:
json
“build:chrome”: “extension-builder build –target chrome”, “build:firefox”: “extension-builder build –target firefox”
- Follow store guidelines: icons, privacy statements, screenshots.
Troubleshooting checklist
- Popup not opening: confirm default_popup path in final built manifest.
- API undefined: ensure polyfills included and use browserApi wrapper.
- Clipboard errors: clipboardWrite permission and user gesture required.
Summary
Using Extension Builder, you can maintain a single codebase and generate browser-specific packages by handling manifest transformations, polyfills, and minor API differences. Follow the steps above to build, test, and publish a lightweight cross-browser extension that copies the current page URL.
Leave a Reply