frappe-frontend-development について
Frappe Frontend Developmentは、Frappe UIやポータルページでFrappeアプリのフロントエンドを構築するスキルです。Vue 3とTailwindCSSのSPA、データリソース、コンポーネント、本番環境の設定を扱います。
主な機能
- 01Frappe UIのSPAフロントエンド構築
- 02JinjaとHTMLによるポータルページ作成
- 03Resource APIによるデータ取得
- 04Frappe UIコンポーネントとユーティリティの利用
- 05TailwindCSSと本番ビルドの設定
活用シーン
- 01FrappeアプリのカスタムSPA作成
- 02一般公開向けポータルページの構築
- 03ページ分割されたDocType一覧と文書操作の追加
- 04フロントエンドの認証とAPIアクセス設定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ lubusin/ frappe-skills --skill frappe-frontend-developmentインストール後、Claude Code で/frappe-frontend-developmentを入力して読み込まれたか確認します。
同梱ファイルreferences/frappe-ui.mdreferences/portal-development.md
詳細
Frappe フロントエンド開発
Frappe UI(Vue 3 + TailwindCSS)とポータルページを使用して、モダンなフロントエンドアプリケーションを構築します。
使用する場面
- Frappe アプリ向けのカスタム SPA フロントエンドを構築する場合
- Frappe UI コンポーネント(Button、Dialog、ListView など)を使用する場合
- Resource、ListResource、DocumentResource を使用してデータ取得を実装する場合
- ポータル/一般公開ページを作成する場合
- Frappe アプリ内に Vue 3 フロントエンドのツールをセットアップする場合
必要な入力
- アプリ名と、フロントエンドがすでにあるかどうか
- フロントエンドの種類(Frappe UI を使ったフル SPA、またはポータルページ)
- 認証要件(ログインユーザー、ゲストアクセス)
- 必要な主要コンポーネントとデータリソース
手順
0) フロントエンドのアプローチを選択する
| アプローチ | 使用する場面 | スタック |
|---|---|---|
| Frappe UI SPA | カスタムアプリのフロントエンド | Vue 3、TailwindCSS、Vite |
| ポータルページ | シンプルな公開ページ | Jinja + HTML、最小限の JS |
| Desk 拡張 | 管理 UI の拡張 | Form/List スクリプト(frappe-desk-customization を参照) |
1) Frappe UI フロントエンドのひな形を作成する
# Inside your Frappe app directory
cd apps/my_app
npx degit frappe/frappe-ui-starter frontend
# Install dependencies
cd frontend
yarn
# Start dev server
yarn dev
2) main.js を設定する
import { createApp } from 'vue'
import {
FrappeUI,
setConfig,
frappeRequest,
resourcesPlugin,
pageMetaPlugin
} from 'frappe-ui'
import App from './App.vue'
import './index.css'
let app = createApp(App)
// Register FrappeUI plugin (components + directives)
app.use(FrappeUI)
// Enable Frappe response parsing
setConfig('resourceFetcher', frappeRequest)
// Optional: Options API resource support
app.use(resourcesPlugin)
// Optional: Reactive page titles
app.use(pageMetaPlugin)
app.mount('#app')
3) Resource でデータを取得する
汎用 Resource — カスタム API 呼び出しに使用します。
import { createResource } from 'frappe-ui'
let stats = createResource({
url: 'my_app.api.get_dashboard_stats',
params: { period: 'monthly' },
auto: true,
cache: 'dashboard-stats',
transform(data) {
return { ...data, formatted_total: format_currency(data.total) }
},
onSuccess(data) { console.log('Loaded:', data) },
onError(error) { console.error('Failed:', error) }
})
// Properties
stats.data // Response data
stats.loading // Boolean: request in progress
stats.error // Error object if failed
stats.fetched // Boolean: data fetched at least once
// Methods
stats.fetch() // Trigger request
stats.reload() // Re-fetch
stats.submit({ period: 'weekly' }) // Fetch with new params
stats.reset() // Reset state
List Resource — ページネーション付きの DocType リストに使用します。
import { createListResource } from 'frappe-ui'
let todos = createListResource({
doctype: 'ToDo',
fields: ['name', 'description', 'status'],
filters: { status: 'Open' },
orderBy: 'creation desc',
pageLength: 20,
auto: true,
cache: 'open-todos'
})
// List-specific API
todos.data // Array of records
todos.hasNextPage // Boolean: more pages
todos.next() // Load next page
todos.reload() // Refresh list
// CRUD operations
todos.insert.submit({ description: 'New task' })
todos.setValue.submit({ name: 'TODO-001', status: 'Closed' })
todos.delete.submit('TODO-001')
todos.runDocMethod.submit({ method: 'send_email', name: 'TODO-001' })
Document Resource — 単一ドキュメントの操作に使用します。
import { createDocumentResource } from 'frappe-ui'
let todo = createDocumentResource({
doctype: 'ToDo',
name: 'TODO-001',
whitelistedMethods: {
sendEmail: 'send_email',
markComplete: 'mark_complete'
},
onSuccess(doc) { console.log('Loaded:', doc.name) }
})
// Document API
todo.doc // Full document object
todo.reload() // Refresh document
// Update fields
todo.setValue.submit({ status: 'Closed' })
// Debounced update (coalesces rapid changes)
todo.setValueDebounced.submit({ description: 'Updated' })
// Call whitelisted methods
todo.sendEmail.submit({ email: '[email protected]' })
// Delete
todo.delete.submit()
4) Frappe UI コンポーネントを使用する
<template>
<div class="p-4">
<Button variant="solid" theme="blue" @click="showDialog = true">
Add Todo
</Button>
<ListView :columns="columns" :rows="todos.data">
<template #cell="{ column, row, value }">
<Badge v-if="column.key === 'status'" :theme="value === 'Open' ? 'orange' : 'green'">
{{ value }}
</Badge>
<span v-else>{{ value }}</span>
</template>
</ListView>
<Dialog v-model="showDialog" :options="{ title: 'New Todo' }">
<template #body-content>
<TextInput v-model="newDescription" placeholder="Description" />
</template>
<template #actions>
<Button variant="solid" @click="addTodo">Save</Button>
</template>
</Dialog>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Button, ListView, Badge, Dialog, TextInput, createListResource } from 'frappe-ui'
const showDialog = ref(false)
const newDescription = ref('')
const todos = createListResource({
doctype: 'ToDo',
fields: ['name', 'description', 'status'],
auto: true
})
const columns = [
{ label: 'Description', key: 'description' },
{ label: 'Status', key: 'status', width: 100 }
]
function addTodo() {
todos.insert.submit(
{ description: newDescription.value },
{ onSuccess() { showDialog.value = false; newDescription.value = '' } }
)
}
</script>
利用可能なコンポーネントのカテゴリ:
| カテゴリ | コンポーネント |
|---|---|
| 入力 | TextInput、Textarea、Select、Combobox、MultiSelect、Checkbox、Switch、DatePicker、TimePicker、Slider、Password、Rating |
| 表示 | Alert、Avatar、Badge、Breadcrumbs、Progress、Tooltip、ErrorMessage、LoadingText |
| ナビゲーション | Button、Dropdown、Tabs、Sidebar、Popover |
| レイアウト | Dialog、ListView、Calendar、Tree |
| リッチコンテンツ | TextEditor(TipTap)、Charts、FileUploader |
5) ディレクティブとユーティリティを追加する
<script setup>
import { onOutsideClickDirective, visibilityDirective, debounce } from 'frappe-ui'
const vOnOutsideClick = onOutsideClickDirective
const vVisibility = visibilityDirective
const debouncedSearch = debounce((query) => {
// Search logic
}, 500)
</script>
<template>
<div v-on-outside-click="closeDropdown">...</div>
<div v-visibility="onVisible">Lazy loaded content</div>
</template>
6) TailwindCSS を設定する
// tailwind.config.js
module.exports = {
presets: [
require('frappe-ui/src/utils/tailwind.config')
],
content: [
'./index.html',
'./src/**/*.{vue,js,ts}',
'./node_modules/frappe-ui/src/components/**/*.{vue,js,ts}'
]
}
7) 本番環境向けにビルドする
# Build frontend assets
cd frontend && yarn build
# Assets are served at /frontend by Frappe
8) ポータルページ(別のアプローチ)
フル SPA を使わずにシンプルな公開ページを作成する場合:
# In your app's website/ or www/ directory
# my_app/www/my_page.html
{% extends "templates/web.html" %}
{% block page_content %}
<h1>{{ title }}</h1>
<p>Welcome, {{ frappe.session.user }}</p>
{% endblock %}
# my_app/www/my_page.py
def get_context(context):
context.title = "My Page"
context.data = frappe.get_all("ToDo", filters={"owner": frappe.session.user})
検証
-
yarn devがエラーなく起動する - コンポーネントが正しくレンダリングされる
- データリソースがデータを取得して表示する
- CRUD 操作(挿入、更新、削除)が機能する
- 認証が機能する(ログインリダイレクト、セッション処理)
-
yarn buildが正常に完了する - 本番用アセットが Frappe から正しく配信される
失敗時の問題解決/デバッグ
- CORS エラー:ローカル開発では
ignore_csrfを設定し、本番環境では適切な CSRF トークンが設定されていることを確認します - API 呼び出しで 404 が発生する:メソッドのパスを確認し、
@frappe.whitelist()デコレーターを検証します - コンポーネントが見つからない:インポートパスが正しいことを確認し、
frappe-uiのバージョンを確認します - スタイルが崩れている:TailwindCSS の設定に
frappe-uiコンポーネントのパスが含まれていることを確認します - 認証の問題:セッション Cookie を確認し、開発用プロキシ設定のサイト URL が一致していることを確認します
エスカレーション
- Desk UI のスクリプト作成について →
frappe-desk-customization - API エンドポイントの実装について →
frappe-api-development - アプリのアーキテクチャについて →
frappe-app-development - 公式アプリの UI/UX パターンについて →
frappe-ui-patterns
参考資料
- references/frappe-ui.md — Frappe UI フレームワークのリファレンス
- references/portal-development.md — ポータルページの概要
ガードレール
- カスタムフロントエンドには必ず Frappe UI を使用してください:アプリのフロントエンドに vanilla JS、jQuery、カスタムフレームワークを使用しないでください。Frappe UI(Vue 3 + TailwindCSS)が標準です。これにより、CRM、Helpdesk、その他の公式 Frappe アプリとの一貫性が保たれます。
- FrappeUI コンポーネントを使用してください:一貫性を保つため、カスタム HTML よりも
<Button>、<Input>、<FormControl>を優先してください。 - CRM/Helpdesk アプリのシェルパターンに従ってください:CRUD アプリでは、公式 Frappe アプリのサイドバーナビゲーション、リストビュー、フォームレイアウト、ルーティングパターンを説明する
frappe-ui-patternsスキルに従ってください。 - 読み込み状態を処理してください:API 呼び出し中は必ず読み込みインジケーターを表示してください。
resource.loadingを使用してください。 - API レスポンスを検証してください:データにアクセスする前にエラーを確認し、
excレスポンスを処理してください。 - プロキシを正しく設定してください:開発サーバーで API 呼び出しを Frappe バックエンドにプロキシする必要があります。
- 認証を処理してください:
$session.userを確認し、必要に応じてログインページにリダイレクトしてください。
よくある間違い
| 間違い | 失敗する理由 | 修正方法 |
|---|---|---|
| CORS/プロキシの設定漏れ | 開発環境で API 呼び出しが失敗します | /api を Frappe サイトに転送するよう Vite プロキシを設定します |
| 認証状態を処理しない | ログアウト中のユーザーでアプリがクラッシュします | マウント時に call('frappe.auth.get_logged_user') を確認します |
| リソース URL の誤り | API 呼び出しで 404 エラーが発生します | 正しいメソッドパスで createResource を使用します |
| サイト URL のハードコード | 環境間で動作しなくなります | 相対 URL または環境変数を使用します |
| CSRF トークンを含めない | POST リクエストが失敗します | frappe.csrf_token を使用するか、セッションを適切に設定します |
| TailwindCSS 設定の漏れ | Frappe UI のスタイルが崩れます | Tailwind のコンテンツパスに frappe-ui を含めます |
| vanilla JS/jQuery の使用 | UX に一貫性がなく、保守の負担が増します | カスタムフロントエンドには必ず Frappe UI を使用してください |
| 独自のアプリシェルデザイン | エコシステムとの一貫性がなくなります | ナビゲーション、リスト、フォームには CRM/Helpdesk のパターンに従ってください |
コメント
Markdown 対応