VueでChrome拡張作ってみた!
こんにちは!皆さん、Vue.jsでChrome拡張を作れるってご存知でしたか?「VueでGoogle拡張ってできるんだ・・・」と驚かれる方もいるかもしれません。今回は、そんなVue.jsを使ってChrome拡張を作ってみたので、その体験をシェアしたいと思います。
はじめに
Chrome拡張は、ブラウザの機能を拡張する便利なツールです。通常、JavaScriptやHTML、CSSを使って作成しますが、Vue.jsを使うとコンポーネントベースで効率的に開発できます。特に、既にVue.jsに慣れている方にとっては、馴染みのある環境で開発が進められるのでおすすめです。
開発環境の準備
まず、Vueプロジェクトを作成します。今回はViteを使ってTypeScript対応のプロジェクトを作成しました。
```bash
npm init vite@latest my-chrome-extension -- --template vue-ts
cd my-chrome-extension
npm install
```
ストレージ操作の実装
拡張機能では、ユーザーの設定や一時的なデータを保存するために、ChromeのストレージAPIを使用します。storage.tsファイルを作成し、ストレージ操作の関数をまとめました。
// storage.ts
const getStorageArea = () => {
return chrome.storage.local;
};
type StorageArea = ReturnType<typeof getStorageArea>;
export const setStorage = async (key: string, value: any) => {
return errorHandling((storage) => {
storage.set({
[key]: value,
});
});
};
type SearchKeys = Parameters<StorageArea['get']>[0];
export const getStorage = async (keys: SearchKeys) => {
return errorHandling((storage) => {
return storage.get(keys);
});
};
export const removeStorage = async (keys: string | string[]) => {
return errorHandling((storage) => {
storage.remove(keys);
});
};
type ErrorHandlingCallback<T> = (storage: StorageArea) => T;
const errorHandling = <T>(callback: ErrorHandlingCallback<T>) => {
try {
const storage = getStorageArea();
return callback(storage);
} catch (e: unknown) {
throw e;
}
};
```
このコードでは、ストレージのset、get、remove操作を関数化し、エラーハンドリングを一元化しています。
index.tsファイルでエクスポートします。
// index.ts
export * from './storage';
クリップボードへのコピー機能
次に、現在表示しているページのURLをクリップボードにコピーする機能を実装します。clipboard.vueというコンポーネントを作成しました。
<template>
<div class="copy-url-container">
<button @click="OncopyToClipboardHandler">URLをコピー</button>
<div v-if="successMessage" class="success-message">{{ successMessage }}</div>
<div v-if="errorMessage" class="error-message">{{ errorMessage }}</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const successMessage = ref<string>('');
const errorMessage = ref<string>('');
// クリップボードにURLをコピーするハンドラー
const OncopyToClipboardHandler = async () => {
try {
const queryOptions = { active: true, currentWindow: true };
const [tab] = await chrome.tabs.query(queryOptions);
if (tab.url) {
await navigator.clipboard.writeText(tab.url);
successMessage.value = 'URLをクリップボードにコピーしました!';
}
} catch (error) {
errorMessage.value = 'URLのコピーに失敗しました。';
console.error('Error copying URL to clipboard:', error);
}
};
</script>
<style scoped>
.copy-url-container {
text-align: center;
}
.success-message {
color: green;
}
.error-message {
color: red;
}
</style>
ボタンをクリックすると、現在のタブのURLをクリップボードにコピーし、成功または失敗のメッセージを表示します。
ページ情報の取得
拡張機能から現在のページの情報を取得するために、Content Scriptを使用します。
// Content Script
chrome.runtime.onMessage.addListener((_m: any, _s: any, sendResponse: any) => {
const title = document.title;
const description = document.querySelector('meta[name="description"]')?.getAttribute('content');
const h1 = Array.from(document.querySelectorAll('h1')).map((h1) => h1.textContent);
const h2 = Array.from(document.querySelectorAll('h2')).map((h2) => h2.textContent);
const h3 = Array.from(document.querySelectorAll('h3')).map((h3) => h3.textContent);
const p = Array.from(document.querySelectorAll('p')).map((p) => p.textContent);
const response = [
{ label: 'ページタイトル', value: title },
{ label: 'ページ説明', value: description },
{ label: 'h1', value: h1 },
{ label: 'h2', value: h2 },
{ label: 'h3', value: h3 },
{ label: 'p', value: p },
{ label: 'span', value: Array.from(document.querySelectorAll('span')).map((span) => span.textContent) },
];
sendResponse(response);
});
メッセージを受信すると、ページ内のタイトルや見出し、段落などの情報を収集してレスポンスします。
メインコンポーネントとの連携
最後に、これらの機能をメインのVueコンポーネントで組み合わせます。
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import ClipBoard from '../../helper/clipBoard.vue';
const responseData = ref<any>(null);
const onClick = () => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs: any) => {
chrome.tabs.sendMessage(tabs[0].id!, {}, (response: any) => {
console.log(response);
responseData.value = response;
});
});
};
// クリップボードリスナーのセットアップ
const setupClipboardListener = () => {
chrome.runtime.onMessage.addListener(function (message) {
if (message.command === 'copy') {
navigator.clipboard
.writeText(message.text)
.then(() => {
console.log('Copied to clipboard');
})
.catch((err) => {
console.error('Failed to copy: ', err);
});
}
});
};
onMounted(() => {
setupClipboardListener();
});
</script>
<template>
<div>
<button @click="onClick">ページ情報を取得</button>
</div>
<div v-if="responseData">
<span>{{ responseData }}</span>
</div>
<div v-else>データがありません</div>
<ClipBoard />
</template>
<style scoped>
/* 必要に応じてスタイルを追加 */
</style>
このコンポーネントでは、ページ情報を取得するボタンと、先ほどのクリップボードコピー機能を組み合わせています。
おわりに
今回は、Vue.jsを使ってChrome拡張を作成する方法をご紹介しました。普段Vue.jsで開発している方なら、拡張機能も同じ感覚で作れるのでとても便利ですよね。
皆さんもぜひ、Vue.jsを使ってオリジナルのChrome拡張を作ってみてください!何か疑問や感想があれば、コメントでお知らせいただけると嬉しいです。
それでは、楽しい開発ライフを!