#Vue
Addfox は Vue 3 を完全にサポートし、.vue 単一ファイルコンポーネントを使用して拡張機能を開発できます。
#インストール
プロジェクト作成時に Vue テンプレートを選択:
pnpm create addfox-app --framework vueまたは既存のプロジェクトにインストール:
pnpm add @addfox/rsbuild-plugin-vuenpm install @addfox/rsbuild-plugin-vueyarn add @addfox/rsbuild-plugin-vuebun add @addfox/rsbuild-plugin-vue#設定
// addfox.config.ts
import { defineConfig } from "addfox";
import { pluginVue } from "@addfox/rsbuild-plugin-vue";
export default defineConfig({
plugins: [pluginVue()],
});#プロジェクト構造
app/
├── background/
│ └── index.ts
├── content/
│ └── index.ts
├── popup/
│ ├── App.vue
│ ├── index.html
│ └── index.ts
├── options/
│ ├── App.vue
│ ├── index.html
│ └── index.ts
└── manifest.json#サンプルコード
#Popup
<!-- app/popup/App.vue -->
<template>
<div class="popup">
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const title = ref('Hello Vue!');
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
<style scoped>
.popup {
padding: 16px;
min-width: 200px;
}
h1 {
font-size: 18px;
margin-bottom: 12px;
}
button {
padding: 8px 16px;
background: #42b883;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>// app/popup/index.ts
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#root');以下の index.html を省略し、index.ts のみを保持する場合、ビルドは自動的に HTML を生成し、id="root"、manifest.name / manifest.icons と同期する title と favicon を含みます(ファイルベースのエントリー を参照)。以下の例はオプションのカスタムテンプレートです:
<!-- app/popup/index.html(オプション;カスタム時は自分で title / アイコンを記述) -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Popup</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.ts" data-addfox-entry></script>
</body>
</html>#Content Script
// app/content/index.ts
import { createApp } from 'vue';
import ContentApp from './ContentApp.vue';
// マウントポイントを作成
const container = document.createElement('div');
container.id = 'my-extension-root';
document.body.appendChild(container);
createApp(ContentApp).mount(container);<!-- app/content/ContentApp.vue -->
<template>
<div class="content-widget">
<p>Hello from Vue Content Script!</p>
</div>
</template>
<style scoped>
.content-widget {
position: fixed;
bottom: 20px;
right: 20px;
background: white;
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 9999;
}
</style>#状態管理
#Pinia
pnpm add pinia// app/stores/counter.ts
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
},
});// app/popup/index.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
const app = createApp(App);
app.use(createPinia());
app.mount('#root');#VueUse
pnpm add @vueuse/core<script setup>
import { useStorage } from '@vueuse/core';
// chrome.storage に自動的に同期
const count = useStorage('count', 0);
</script>#Chrome API との相互作用
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const tabs = ref<chrome.tabs.Tab[]>([]);
onMounted(async () => {
tabs.value = await chrome.tabs.query({});
});
const activateTab = (tabId: number) => {
chrome.tabs.update(tabId, { active: true });
};
</script>
<template>
<ul>
<li
v-for="tab in tabs"
:key="tab.id"
@click="activateTab(tab.id!)"
>
{{ tab.title }}
</li>
</ul>
</template>#CSS ソリューション
#Tailwind CSS
pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p/* app/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;<template>
<div class="p-4 bg-gray-100">
<h1 class="text-xl font-bold text-blue-600">Hello Tailwind!</h1>
</div>
</template>#Scoped CSS
Vue 単一ファイルコンポーネントはデフォルトで scoped CSS をサポート:
<style scoped>
.button {
background: #42b883;
}
/* 深いセレクター */
:deep(.child) {
color: red;
}
</style>
