VueでChrome拡張作ってみた!
2024-12-17
azblob://2024/12/16/eyecatch/2024-12-17-chrome-extensitons-vue-000.jpg

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拡張を作ってみてください!何か疑問や感想があれば、コメントでお知らせいただけると嬉しいです。

それでは、楽しい開発ライフを!