Chrome ext mv3 programmatic inject
Skill bokuwalily/claude-code-skills/skills/chrome-ext-mv3-programmatic-inject
75 battle-tested Claude Code skills from shipping 20+ apps solo — macOS, Next.js, Vercel, iOS/Expo, Cloudflare, Phaser, local AI media & more
npx -y skills add bokuwalily/claude-code-skills --skill chrome-ext-mv3-programmatic-injectAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Chrome拡張(Manifest V3)で popup から content script にメッセージを送ると "Could not establish connection. Receiving end does not exist." が出るとき。宣言的注入から programmatic 注入に切り替える手順。
SKILL.md
4.0 KB, as published. Nobody here has run it
Procedure
1. manifest.json に scripting 権限を追加する
{
"manifest_version": 3,
"permissions": ["activeTab", "storage", "scripting"]
}
2. content.js の先頭に二重注入ガードを追加する
if (window.__myExtLoaded) return;
window.__myExtLoaded = true;
// 本来のロジックはここから
3. popup.js で「注入してからメッセージ送信」の順序にする
async function injectAndSend(tabId, message) {
// content.js が他スクリプト(設定/ライブラリ)に依存する場合は
// 依存を必ず先に、同じ files 配列で一緒に注入する(順序通りに実行される)。
// ここを content.js 単独にすると「宣言注入が走っていないタブ」で
// ReferenceError: X is not defined になり無言クラッシュする(下記 Pitfalls)。
await chrome.scripting.executeScript({
target: { tabId },
files: ['lib/settings.js', 'lib/license.js', 'lib/quota.js', 'content.js'],
});
// 注入後にメッセージ送信
return chrome.tabs.sendMessage(tabId, message);
}
document.getElementById('startBtn').addEventListener('click', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab?.url?.match(/https:\/\/(x|twitter)\.com/)) return;
await injectAndSend(tab.id, { type: 'START' });
});
4. chrome://extensions で拡張を更新(↻)して動作確認する
Pitfalls
- 宣言的
content_scriptsは「拡張インストール前に開いていたタブ」には自動注入されない。ユーザーにタブリロードを求めるUXは避けられないため、programmatic 注入の方が UX 良好。 - 依存スクリプトの注入漏れ(最頻の罠): manifest の
content_scripts.jsが["lib/a.js","lib/b.js","content.js"]のように複数でも、popup からの programmatic 注入でfiles:["content.js"]だけにすると、宣言注入が一度も走っていないタブではlib/*が未注入。宣言注入と programmatic 注入は同一 isolated world を共有するため通常タブでは生き残って動くが、当該タブだけ content.js が依存グローバル参照で即クラッシュ(loop().catch()等で握り潰すと popup は「実行中」表示のまま無反応)。programmatic 注入の files には宣言注入と同じ全ファイルを同順で入れること。lib 側を IIFE(root.X = ...再代入)にしておけば重複注入は冪等で安全。 activeTabは host_permissions があれば不要: 固定ホスト権限(例https://www.instagram.com/*)を持つ拡張ではactiveTabは何も追加しない。Web Store 審査の最小権限の観点で外してよい(scripting+tabs+host で programmatic 注入も tabs 操作も成立)。chrome.scripting.executeScriptはscripting権限がないとPermission deniedで失敗する。manifest 更新後は必ず拡張を再読み込みする。- 二重注入ガード(
window.__myExtLoaded)がないと、同一タブで複数回注入するとイベントリスナーが重複登録される。 chrome.tabs.sendMessageは非同期なのにtry/catchなしだとコンソール警告が残る。必ずtry { ... } catch {}でラップする。
Verification
- 対象タブのコンソール(DevTools → Console)を開く
- popup の「開始」ボタンを押す
[ExtName] content.js loaded on https://...のログが表示されれば注入成功"Could not establish connection"エラーが消えていることを確認する