xenon-query
v1.0.0
Published
Next-generation Vue 3 server state management library with advanced features
Maintainers
Readme
Xenon Query 🚀
A powerful Vue 3 server state management library with advanced features
✨ Why Xenon Query?
Xenon Query is the next-generation Vue 3 server state management library that goes beyond traditional solutions like TanStack Vue Query. Built from the ground up for modern Vue applications with TypeScript-first design and production-ready features.
🎯 Key Differentiators:
- 🔥 Vue 3 Native: Designed specifically for Composition API
- 🧠 Smart Key Generation: Automatic query keys with scope-based invalidation
- 🔄 Multi-tab Sync: Real-time cache synchronization across browser tabs
- 🛡️ Schema Validation: Runtime data validation with Zod/Yup integration
- 🎛️ Zenon Integration: Unified global and server state management
- ⚡ Optimistic Presets: Pre-built patterns for common operations
- 🔒 TypeScript First: Complete type safety throughout
🚀 Quick Start
Installation
# npm
npm install @xenon/query @xenon/core
# yarn
yarn add @xenon/query @xenon/core
# pnpm
pnpm add @xenon/query @xenon/coreBasic Setup
// main.ts
import { createApp } from "vue";
import { XenonQueryPlugin, QueryClient } from "@xenon/query";
import App from "./App.vue";
const queryClient = new QueryClient({
multiTabSync: true, // Enable cross-tab sync
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes
},
},
});
createApp(App).use(XenonQueryPlugin, { queryClient }).mount("#app");Basic Usage
<template>
<div>
<div v-if="isLoading">Loading...</div>
<div v-else-if="error">Error: {{ error.message }}</div>
<div v-else>
<h1>{{ data.name }}</h1>
<p>{{ data.email }}</p>
<button @click="refetch">Refresh</button>
</div>
</div>
</template>
<script setup lang="ts">
import { useXQuery, keygen } from "@xenon/query";
import { SchemaHelpers } from "@xenon/core";
// Define schema for type safety and validation
const userSchema = SchemaHelpers.zod(
z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
})
);
const userId = ref(1);
const { data, error, isLoading, refetch } = useXQuery({
key: keygen("user", userId), // Smart key generation
fn: () => fetchUser(userId.value),
schema: userSchema, // Runtime validation
enabled: computed(() => userId.value > 0),
});
</script>🛠️ Core Features
1. Smart Key Generation
Automatic query key generation with intelligent scope-based invalidation:
import { keygen, invalidate } from "@xenon/query";
// Auto-generated keys
const userQuery = keygen("users", userId); // ['users', 1]
const postsQuery = keygen("posts", { userId }); // ['posts', { userId: 1 }]
// Scope-based invalidation
invalidate.scope("users"); // Invalidates all user queries
invalidate.scope("posts", userId); // Invalidates posts for specific user2. Multi-tab Synchronization
Real-time cache synchronization across browser tabs:
const queryClient = new QueryClient({
multiTabSync: {
channelName: "my-app-sync",
syncData: true,
syncInvalidations: true,
queryFilter: (queryKey) => !queryKey.includes("private"),
},
});
// Changes in one tab automatically sync to others3. Schema Validation
Runtime data validation with popular schema libraries:
import { SchemaHelpers } from "@xenon/core";
import { z } from "zod";
const todoSchema = SchemaHelpers.zod(
z.object({
id: z.number(),
title: z.string(),
completed: z.boolean(),
})
);
const { data } = useXQuery({
key: ["todos"],
fn: fetchTodos,
schema: todoSchema, // Automatic validation + TypeScript inference
schemaConfig: {
onValidationFailure: "warn", // throw | warn | ignore
},
});4. Optimistic Updates with Presets
Pre-built patterns for common optimistic update scenarios:
import { useXMutation, preset } from "@xenon/query";
const { mutate } = useXMutation({
mutationFn: createTodo,
...preset.optimistic.list({
queryKey: ["todos"],
idField: "id",
updater: (old, newTodo) => [...old, newTodo],
}),
});
// Optimistic update with automatic rollback on error
mutate({ title: "New Todo", completed: false });5. Infinite Queries
Powerful infinite scrolling with Vue 3 integration:
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useXInfiniteQuery({
key: ["posts"],
fn: ({ pageParam = 0 }) => fetchPosts(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor,
select: (data) => data.pages.flatMap((page) => page.posts),
});6. Zenon Integration
Unified global and server state management:
const { data } = useXQuery({
key: ["user-profile", userId],
fn: fetchUserProfile,
mirror: {
mode: "data",
storeName: "user",
key: "profile",
},
});
// Automatically mirrors to Zenon store
// Access via: store.user.profile📚 Advanced Usage
Custom Hooks with Composition
// composables/useUserQueries.ts
export function useUserQueries(userId: Ref<number>) {
const userQuery = useXQuery({
key: keygen("users", userId),
fn: () => fetchUser(userId.value),
enabled: computed(() => userId.value > 0),
});
const postsQuery = useXQuery({
key: keygen("posts", { userId }),
fn: () => fetchUserPosts(userId.value),
enabled: computed(() => userQuery.isSuccess.value),
});
return {
user: userQuery,
posts: postsQuery,
invalidateAll: () => invalidate.scope("users", userId.value),
};
}Error Boundary Integration
<template>
<ErrorBoundary @error="handleError">
<UserProfile :user-id="userId" />
</ErrorBoundary>
</template>
<script setup lang="ts">
const handleError = (error: Error) => {
if (error.name === "ValidationFailureError") {
// Handle schema validation errors
console.error("Data validation failed:", error);
}
};
</script>Custom Schema Validators
// Custom validation function
const customValidator = SchemaHelpers.custom(
(data: unknown): UserData => {
if (!isValidUser(data)) {
throw new Error("Invalid user data");
}
return data as UserData;
},
{ errorCode: "INVALID_USER" }
);
// Type guard validator
const typeGuardValidator = SchemaHelpers.typeGuard(
(data): data is Todo[] => Array.isArray(data) && data.every(isTodo),
"Expected array of todos"
);📦 Package Structure
@xenon/query # Vue 3 composables and plugin
@xenon/core # Core query client and utilitiesCore Exports
// @xenon/core
export {
QueryClient,
QueryCache,
smartKeygen,
invalidate,
MultiTabSync,
SchemaValidator,
SchemaHelpers,
preset,
} from "@xenon/core";
// @xenon/query
export {
useXQuery,
useXMutation,
useXInfiniteQuery,
useQueryClient,
XenonQueryPlugin,
} from "@xenon/query";🔧 Configuration
Global Configuration
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
retry: 3,
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
},
},
multiTabSync: {
channelName: "my-app-cache",
syncData: true,
syncInvalidations: true,
debounceMs: 100,
},
});
// Configure smart keygen
configureKeygen({
hashingAlgorithm: "sha256",
enableScoping: true,
maxKeyLength: 100,
});
// Configure schema validation
SchemaValidator.configure({
validateResponse: true,
onValidationFailure: "throw",
});🚀 Performance
Bundle Size
- @xenon/core: ~52KB (minified)
- @xenon/query: ~12KB (minified)
- Total: ~64KB for full-featured setup
Optimizations
- ✅ Tree-shakable exports
- ✅ Lazy-loaded features
- ✅ Efficient caching algorithms
- ✅ Debounced multi-tab sync
- ✅ Smart garbage collection
🤝 Migration from TanStack Vue Query
Xenon Query provides a familiar API with enhanced features:
// TanStack Vue Query
const { data } = useQuery({
queryKey: ["users", userId],
queryFn: () => fetchUser(userId),
});
// Xenon Query - Enhanced
const { data } = useXQuery({
key: keygen("users", userId), // Smart key generation
fn: () => fetchUser(userId),
schema: userSchema, // Runtime validation
mirror: "data", // Zenon integration
});📖 Documentation
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/xenon-query/xenon-query.git
cd xenon-query
# Install dependencies
pnpm install
# Run tests
pnpm test
# Build packages
pnpm build
# Run examples
pnpm dev📄 License
MIT © Xenon Query Contributors
🌟 Support
If you find Xenon Query helpful, please consider:
- ⭐ Starring the GitHub repository
- 🐦 Following us on Twitter
- 💬 Joining our Discord community
Built with ❤️ for the Vue community
Website • Documentation • Examples • Discord
