Claude Skills Guide

Building Chrome extensions with Svelte gives you a powerful combination: Svelte’s reactive framework for creating responsive UI, and Chrome’s extension APIs for browser functionality. This guide walks you through setting up a Chrome extension with Svelte and using devtools effectively during development.

Why Svelte for Chrome Extensions?

Svelte compiles your components to vanilla JavaScript, which means smaller bundle sizes and faster execution—critical when Chrome enforces strict limits on extension package sizes. Unlike React or Vue, Svelte doesn’t require a runtime, reducing memory overhead in the browser context.

The reactive nature of Svelte works naturally with Chrome’s event-driven API model. When you listen to browser events like chrome.tabs.onUpdated or chrome.runtime.onMessage, Svelte stores can immediately reflect those changes in your popup or options page UI.

Setting Up Your Project

Create a new Svelte project using Vite, then configure it for Chrome extension development:

npm create vite@latest my-extension -- --template svelte
cd my-extension
npm install

Modify your vite.config.js to output to a Chrome-compatible format:

import { defineConfig } from 'vite';
import svelte from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte()],
  build: {
    outDir: 'dist',
    rollupOptions: {
      output: {
        entryFileNames: 'src/[name].js',
        chunkFileNames: 'src/[name].js',
        assetFileNames: 'src/[name].[ext]'
      }
    }
  },
  base: '.'
});

Create your manifest.json in the public folder:

{
  "manifest_version": 3,
  "name": "My Svelte Extension",
  "version": "1.0.0",
  "description": "A Chrome extension built with Svelte",
  "action": {
    "default_popup": "index.html",
    "default_title": "Open Extension"
  },
  "permissions": ["tabs", "storage"],
  "host_permissions": ["<all_urls>"]
}

Build your project with npm run build, then load the dist folder as an unpacked extension in Chrome’s chrome://extensions page.

Connecting DevTools to Your Extension

Chrome provides several devtools pages for debugging extensions. Access them through View > Developer > Developer Tools, then select your extension context from the dropdown.

When your popup is open, right-click and select Inspect to open DevTools specifically for the popup context. This is where you’ll debug your Svelte components, inspect reactive state, and trace event handlers.

Background Script Debugging

Navigate to chrome://extensions and click the “service worker” link under your extension. This opens DevTools for the background context where chrome.runtime listeners operate. Your Svelte app’s initialization logic runs here if you’re building a full-page extension.

Content Script Debugging

Content scripts run in the context of web pages. Set breakpoints in DevTools by navigating to the Sources panel and expanding the “Content Scripts” section. You’ll see your bundled content script there alongside the page’s own scripts.

Using Svelte Stores with Chrome APIs

Svelte stores provide an elegant way to bridge Chrome’s asynchronous APIs with reactive UI. Here’s a pattern for managing tab state:

// stores/tabs.js
import { writable } from 'svelte/store';

export const currentTab = writable(null);
export const tabHistory = writable([]);

export function initTabListener() {
  chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    if (changeInfo.status === 'complete' && tab.active) {
      currentTab.set(tab);
      tabHistory.update(history => [...history.slice(-9), tab]);
    }
  });
}

In your Svelte component, use the store to automatically reflect Chrome state:

<script>
  import { currentTab, tabHistory } from '../stores/tabs.js';
  import { onMount } from 'svelte';

  onMount(() => {
    initTabListener();
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      currentTab.set(tabs[0]);
    });
  });
</script>

<div class="tab-info">
  <h3>Current Tab</h3>
  <p>{$currentTab?.title || 'No active tab'}</p>
  <p class="url">{$currentTab?.url || ''}</p>
</div>

<style>
  .url {
    font-size: 0.8em;
    color: #666;
    word-break: break-all;
  }
</style>

Debugging Common Issues

Hot Reload Problems

During development, Chrome caches your extension files. After making changes:

  1. Click the reload icon in chrome://extensions
  2. Close and reopen your popup
  3. Check “Allow in incognito” if testing there

For faster iteration, use Chrome’s Watch mode in DevTools or configure Vite’s server to proxy requests.

Message Passing Failures

When communication between content scripts and background scripts fails, verify your message structure:

// Content script sends message
chrome.runtime.sendMessage({
  type: 'FETCH_DATA',
  payload: { url: window.location.href }
});

// Background script receives
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'FETCH_DATA') {
    // Handle the message
    fetchData(message.payload.url).then(sendResponse);
    return true; // Keep message channel open for async response
  }
});

The return true is critical for asynchronous responses. Without it, Chrome closes the channel before your async operation completes.

State Not Updating

If your Svelte store updates but the UI doesn’t reflect changes, verify you’re accessing the store with the $ prefix in your template. This triggers Svelte’s subscription mechanism.

Performance Optimization

Chrome extensions have resource limits. Svelte helps by producing minimal JavaScript, but follow these practices:

Building for Production

When ready to publish, create a production build that minimizes bundle size:

npm run build -- --minify

This produces optimized output in your dist folder. Test the unpacked version thoroughly before packaging with Chrome’s “Pack extension” button or using npm run build with a packaging tool.

Your extension is now ready for the Chrome Web Store. The combination of Svelte’s developer experience and Chrome’s powerful APIs enables you to build sophisticated browser tools with minimal overhead.

Built by theluckystrike — More at zovo.one