VJSP Vue3 Frame - ユーティリティ関数ガイド
概要
VJSP Vue3 Frameは、キャッシュ管理、セキュリティ保護、ルーティングと権限、メッセージ管理など、フロントエンド開発の様々な側面をサポートする包括的なユーティリティ関数ライブラリを提供します。このガイドでは、ユーティリティ関数のアーキテクチャ、使用方法、ベストプラクティスについて詳しく説明します。
アーキテクチャ設計
1. ディレクトリ構造
utils/
├── cache/ # キャッシュ管理層
│ ├── CacheUtil.ts # キャッシュユーティリティクラス
│ ├── MemoryCache.ts # メモリキャッシュ実装
│ └── StorageCache.ts # 永続ストレージキャッシュ
├── security/ # セキュリティ保護層
│ ├── SecurityManager.ts # セキュリティマネージャー
│ ├── RateLimiter.ts # レート制限
│ └── CSRFProtection.ts # CSRF保護
├── router/ # ルーティングと権限
│ ├── RouterHelper.ts # ルーティングヘルパー
│ ├── PermissionUtil.ts # 権限ユーティリティ
│ └── RouteGuard.ts # ルートガード
├── message/ # メッセージ管理
│ ├── MessageManager.ts # メッセージマネージャー
│ └── NotificationUtil.ts # 通知ユーティリティ
├── common/ # 共通ユーティリティ
│ ├── DateUtil.ts # 日付ユーティリティ
│ ├── StringUtil.ts # 文字列ユーティリティ
│ └── ObjectUtil.ts # オブジェクトユーティリティ
└── index.ts # 統一エクスポート2. 設計原則
単一責任の原則: 各ユーティリティ関数は特定の機能に焦点を当てる
モジュール設計: 明確なインターフェースを持つ独立したモジュール
型安全性: 完全なTypeScriptサポートと完全な型定義
パフォーマンス最適化: 最小限のオーバーヘッドで効率的な実装
セキュリティ保護: 組み込みのセキュリティメカニズム
コアユーティリティメカニズム
1. キャッシュ管理
メモリキャッシュ機能:
- メモリ内データストレージ
- 自動有効期限管理
- メモリリーク防止
- パフォーマンス監視
ストレージキャッシュ機能:
- LocalStorage/SessionStorageサポート
- データシリアライズ/デシリアライズ
- ストレージクォータ管理
- クロスタブ同期
2. セキュリティ保護
レート制限メカニズム:
- マルチレベルレート制限(グローバル/ユーザー/エンドポイント)
- スライディングウィンドウアルゴリズム
- 動的設定調整
- リアルタイム監視
CSRF保護:
- トークン生成と検証
- ダブルサブミットクッキーパターン
- 自動トークン更新
- リクエストヘッダー保護
3. ルーティングと権限
ルートガード機能:
- 権限検証
- ルートリダイレクト
- ログイン状態チェック
- ルートキャッシュ管理
権限ユーティリティ機能:
- 権限チェック
- 権限フィルタリング
- 動的権限ロード
- 権限レベル管理
4. メッセージ管理
メッセージタイプ:
- 成功メッセージ
- 警告メッセージ
- エラーメッセージ
- 情報メッセージ
通知機能:
- 自動非表示
- 位置設定
- カスタム期間
- スタック管理
製品モジュール開発例
1. 製品データキャッシュ実装
typescript
// src/views/product/ProductList.vue
<script setup lang="ts">
import { CacheUtil } from '@/utils/cache'
import { message } from '@/utils/messageManager'
// キャッシュ設定
const PRODUCT_CACHE_KEY = 'product_list_cache'
const CACHE_EXPIRY = 5 * 60 * 1000 // 5分
// 製品リストデータ
const productList = ref([])
const loading = ref(false)
// キャッシュを使用した製品データの読み込み
const loadProductList = async () => {
try {
loading.value = true
// まずキャッシュを確認
const cachedData = CacheUtil.get(PRODUCT_CACHE_KEY)
if (cachedData && !CacheUtil.isExpired(PRODUCT_CACHE_KEY)) {
productList.value = cachedData
console.log('キャッシュから読み込み')
return
}
// APIから取得
const response = await productApi.getList()
productList.value = response.data
// キャッシュを更新
CacheUtil.set(PRODUCT_CACHE_KEY, productList.value, CACHE_EXPIRY)
console.log('APIから読み込み、キャッシュに保存')
} catch (error) {
message.error('製品リストの読み込みに失敗しました')
console.error('製品読み込みエラー:', error)
} finally {
loading.value = false
}
}
// 製品キャッシュのクリア
const clearProductCache = () => {
CacheUtil.remove(PRODUCT_CACHE_KEY)
message.success('製品キャッシュをクリアしました')
}
// 製品データの更新
const refreshProductList = () => {
CacheUtil.remove(PRODUCT_CACHE_KEY)
loadProductList()
}
// コンポーネントマウント時に初期化
onMounted(() => {
loadProductList()
})
</script>
<template>
<div class="product-list">
<div class="header">
<h2>製品管理</h2>
<div class="actions">
<el-button @click="refreshProductList" :loading="loading">
更新
</el-button>
<el-button @click="clearProductCache" type="warning">
キャッシュクリア
</el-button>
</div>
</div>
<el-table :data="productList" v-loading="loading">
<!-- テーブル列 -->
</el-table>
</div>
</template>2. 製品権限制御実装
typescript
// src/views/product/components/ProductActions.vue
<script setup lang="ts">
import { hasPermission, filterByPermission } from '@/utils/permission'
// 製品操作権限定義
const PRODUCT_PERMISSIONS = {
CREATE: 'product:create',
EDIT: 'product:edit',
DELETE: 'product:delete',
VIEW: 'product:view'
}
// 現在のユーザー権限を確認
const canCreateProduct = hasPermission(PRODUCT_PERMISSIONS.CREATE)
const canEditProduct = hasPermission(PRODUCT_PERMISSIONS.EDIT)
const canDeleteProduct = hasPermission(PRODUCT_PERMISSIONS.DELETE)
// 製品操作ボタン設定
const actionButtons = [
{
label: '製品作成',
icon: 'plus',
permission: PRODUCT_PERMISSIONS.CREATE,
handler: () => createProduct()
},
{
label: '製品編集',
icon: 'edit',
permission: PRODUCT_PERMISSIONS.EDIT,
handler: () => editProduct()
},
{
label: '製品削除',
icon: 'delete',
permission: PRODUCT_PERMISSIONS.DELETE,
handler: () => deleteProduct()
}
]
// 権限に基づいて操作ボタンをフィルタリング
const visibleButtons = filterByPermission(actionButtons, 'permission')
// 製品操作関数
const createProduct = () => {
if (!hasPermission(PRODUCT_PERMISSIONS.CREATE)) {
message.warning('製品作成の権限がありません')
return
}
// 製品作成ロジック
}
const editProduct = () => {
if (!hasPermission(PRODUCT_PERMISSIONS.EDIT)) {
message.warning('製品編集の権限がありません')
return
}
// 製品編集ロジック
}
const deleteProduct = () => {
if (!hasPermission(PRODUCT_PERMISSIONS.DELETE)) {
message.warning('製品削除の権限がありません')
return
}
// 製品削除ロジック
}
</script>
<template>
<div class="product-actions">
<el-button
v-for="button in visibleButtons"
:key="button.label"
:icon="button.icon"
@click="button.handler"
>
{{ button.label }}
</el-button>
</div>
</template>3. 製品ルート設定とキャッシュ
typescript
// src/router/modules/product.ts
import { Layout } from '@/utils/routerHelper'
import type { AppRouteRecordRaw } from '@/types/router'
const ProductRoute: AppRouteRecordRaw = {
path: '/product',
component: Layout,
redirect: '/product/list',
name: 'Product',
meta: {
title: '製品管理',
icon: 'shopping',
permission: 'product',
keepAliveName: 'ProductLayout',
},
children: [
{
path: 'list',
component: () => import('@/views/product/ProductList.vue'),
name: 'ProductList',
meta: {
title: '製品リスト',
icon: 'list',
permission: 'product:view',
keepAliveName: 'ProductList',
noCache: false, // キャッシュを有効化
},
},
{
path: 'detail/:id',
component: () => import('@/views/product/ProductDetail.vue'),
name: 'ProductDetail',
meta: {
title: '製品詳細',
icon: 'detail',
permission: 'product:view',
keepAliveName: 'ProductDetail',
noCache: true, // キャッシュを無効化(詳細ページは通常キャッシュ不要)
},
props: true,
},
{
path: 'create',
component: () => import('@/views/product/ProductCreate.vue'),
name: 'ProductCreate',
meta: {
title: '製品作成',
icon: 'plus',
permission: 'product:create',
noCache: true, // 作成ページはキャッシュ不要
},
},
],
}
export default ProductRoute4. 製品APIセキュリティ保護
typescript
// src/api/product.ts
import { securityManager } from '@/utils/securityManager'
import { message } from '@/utils/messageManager'
class ProductApi {
private baseURL = '/api/product'
// 製品リストの取得(レート制限付き)
async getList(params?: any) {
// レート制限を確認
const userId = this.getCurrentUserId()
const endpoint = `${this.baseURL}/list`
if (!securityManager.isRequestAllowed(userId, endpoint)) {
message.warning('リクエストが頻繁すぎます。しばらくしてから再試行してください')
throw new Error('レート制限超過')
}
// CSRF保護ヘッダーを追加
const headers = securityManager.getCSRFHeaders('GET')
return await axios.get(endpoint, {
params,
headers,
})
}
// 製品作成(セキュリティ検証付き)
async create(productData: any) {
const userId = this.getCurrentUserId()
const endpoint = `${this.baseURL}/create`
// レート制限を確認
if (!securityManager.isRequestAllowed(userId, endpoint)) {
message.warning('操作が頻繁すぎます。しばらくしてから再試行してください')
throw new Error('レート制限超過')
}
// CSRF保護ヘッダーを追加
const headers = securityManager.getCSRFHeaders('POST')
return await axios.post(endpoint, productData, { headers })
}
// 製品削除(権限検証付き)
async delete(productId: string) {
const userId = this.getCurrentUserId()
const endpoint = `${this.baseURL}/delete/${productId}`
// レート制限を確認
if (!securityManager.isRequestAllowed(userId, endpoint)) {
message.warning('操作が頻繁すぎます。しばらくしてから再試行してください')
throw new Error('レート制限超過')
}
// CSRF保護ヘッダーを追加
const headers = securityManager.getCSRFHeaders('DELETE')
return await axios.delete(endpoint, { headers })
}
private getCurrentUserId(): string {
// 現在のユーザーIDを取得するロジック
const userStore = useUserStore()
return userStore.getUserInfo?.id || 'anonymous'
}
}
export const productApi = new ProductApi()パフォーマンス最適化実践
1. キャッシュ戦略の最適化
製品リストキャッシュの最適化:
- メモリキャッシュ+永続キャッシュの二重メカニズムを使用
- データ更新頻度に基づいて適切な有効期限を設定
- キャッシュプリロードメカニズムを実装し、ユーザーエクスペリエンスを向上
2. コンポーネントキャッシュ設定
keep-aliveキャッシュ戦略:
vue
<!-- src/layout/components/AppMain.vue -->
<template>
<section class="app-main">
<router-view v-slot="{ Component }">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<component :is="Component" :key="route.path" />
</keep-alive>
</transition>
</router-view>
</section>
</template>
<script setup lang="ts">
import { useTagsViewStore } from '@/layout/stores/tagsView'
const route = useRoute()
const tagsViewStore = useTagsViewStore()
// キャッシュされたビューリストを取得
const cachedViews = computed(() => tagsViewStore.getCachedViews)
</script>3. リクエスト最適化戦略
製品APIリクエストの最適化:
- リクエストの重複排除を実装し、重複リクエストを回避
- リクエストキャッシュを使用してサーバー負荷を軽減
- リクエスト優先度管理を実装し、重要なリクエストを優先処理
ベストプラクティスガイド
1. ユーティリティ関数使用基準
インポート基準:
typescript
// 推奨:必要に応じてインポート
import { CacheUtil } from '@/utils/cache'
import { hasPermission } from '@/utils/permission'
// 非推奨:グローバルインポート(バンドルサイズが増加)
import * as utils from '@/utils'エラーハンドリング基準:
typescript
// try-catchを使用してユーティリティ関数の例外を処理
try {
const userInfo = SecurityStorage.getUserInfo()
} catch (error) {
console.error('ユーザー情報の取得に失敗しました:', error)
// フォールバック処理またはユーザー通知
}2. キャッシュ使用推奨事項
キャッシュに適したデータ:
- 静的設定データ
- 基本ユーザー情報
- 製品カテゴリデータ
- 権限メニューデータ
キャッシュに適さないデータ:
- リアルタイム性が要求されるデータ
- 頻繁に更新されるビジネスデータ
- 機密性の高い取引データ
3. セキュリティ保護設定
本番環境設定:
typescript
// 厳格なセキュリティ保護を有効化
const securityConfig = {
rateLimit: {
enabled: true,
global: { maxRequests: 100, timeWindow: 60000 },
user: { maxRequests: 10, timeWindow: 60000 },
endpoint: { maxRequests: 5, timeWindow: 60000 },
},
csrf: {
enabled: true,
tokenExpiry: 30 * 60 * 1000, // 30分
doubleSubmit: true,
},
}まとめ
VJSP Vue3 Frameのユーティリティ関数ライブラリは、プロジェクト開発に強力な基盤サポートを提供します。合理的なモジュール分割、包括的なメカニズム設計、パフォーマンス最適化戦略を通じて、ユーティリティ関数ライブラリは開発効率とコード品質を効果的に向上させることができます。実際の開発では、特定のビジネス要件に基づいて適切なユーティリティ関数を選択し、ベストプラクティス基準に従うことを推奨します。
