
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A lightweight, file-based routing system for Vue 3 applications with zero build configuration
AI-First Vue 3 Framework: The future of web development in the age of artificial intelligence
ViewLogic Router revolutionizes Vue development with three fundamental principles:
Complete separation between View (presentation) and Logic (business logic). Views are pure HTML templates, logic is pure JavaScript components. This separation makes your code more maintainable, testable, and scalable.
Zero build step required in development mode. Work directly with source files, see changes instantly without any compilation, bundling, or build processes. True real-time development experience.
Built from the ground up for the AI coding era. Clear conventions, predictable patterns, and separated concerns make ViewLogic the perfect framework for AI-assisted development. Generate pages, components, and logic with AI tools seamlessly.
All-in-One Solution - Replace multiple libraries with one unified framework:
Tiny Bundle Size - Complete framework in just 52KB minified / 18KB gzipped!
Easy Integration - Drop-in UMD build available for instant usage without build tools.
ViewLogic Router follows a clean, intuitive folder structure:
project/
├── src/
│ ├── views/ # HTML templates (pure presentation)
│ │ ├── home.html
│ │ ├── user-profile.html
│ │ ├── dashboard.html
│ │ └── layout/ # Layout HTML templates
│ │ ├── default.html
│ │ └── admin.html
│ ├── logic/ # Vue component logic (pure JavaScript)
│ │ ├── home.js
│ │ ├── user-profile.js
│ │ ├── dashboard.js
│ │ └── layout/ # Layout JS logic
│ │ ├── default.js
│ │ └── admin.js
│ └── components/ # Reusable UI components
│ ├── UserCard.js
│ └── NavigationMenu.js
├── css/ # Global CSS files (Bootstrap 5 etc.)
│ └── base.css # Base styles
├── js/ # JavaScript library files
│ ├── viewlogic-router.esm.js # ESM module (minified)
│ └── viewlogic-router.min.js # UMD bundle (minified)
├── i18n/ # Internationalization files
│ ├── en.json # English translations
│ ├── ko.json # Korean translations
│ └── ja.json # Japanese translations
├── routes/ # Auto-generated after building
│ ├── home.js # Built route bundles
│ ├── user-profile.js
│ └── dashboard.js
├── index.html # Main entry point
└── package.json
npm create viewlogic myapp
cd myapp
npm run dev
This creates a complete project with examples and starts the development server.
<!DOCTYPE html>
<html>
<head>
<title>My ViewLogic App</title>
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/viewlogic/dist/viewlogic-router.min.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const router = new ViewLogicRouter({
environment: 'development'
});
</script>
</body>
</html>
npm install viewlogic
Option A: Using bundler (Vite, Webpack, etc.)
import { ViewLogicRouter } from 'viewlogic';
const router = new ViewLogicRouter({
environment: 'production',
auth: true,
useI18n: true
});
Option B: Direct ESM import
<!DOCTYPE html>
<html>
<head>
<title>My ViewLogic App</title>
</head>
<body>
<div id="app"></div>
<script type="module">
import { ViewLogicRouter } from 'https://cdn.jsdelivr.net/npm/viewlogic/dist/viewlogic-router.esm.js';
const router = new ViewLogicRouter({
environment: 'production',
auth: true,
useI18n: true
});
</script>
</body>
</html>
src/views/home.html
<div class="home">
<h1>{{ message }}</h1>
<button @click="increment">Click me: {{ count }}</button>
</div>
src/logic/home.js
export default {
// Optional: specify layout (defaults to 'default')
layout: 'default', // Use views/layout/default.html
// layout: 'admin', // Use views/layout/admin.html
// layout: null, // No layout (page-only content)
data() {
return {
message: 'Welcome to ViewLogic!',
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
};
src/views/layout/default.html (optional)
<header class="navbar">
<h1>My App</h1>
<nav>
<a href="#/home">Home</a>
<a href="#/about">About</a>
</nav>
</header>
<main class="main-content">
<div class="container">
{{ content }}
</div>
</main>
<footer>
<p>© 2024 My ViewLogic App</p>
</footer>
src/views/user-profile.html
<div class="user-profile">
<h1>User Profile</h1>
<p>User ID: {{ userId }}</p>
<p>Tab: {{ activeTab }}</p>
<button @click="switchTab('settings')">Settings</button>
<button @click="switchTab('posts')">Posts</button>
</div>
src/logic/user-profile.js
export default {
computed: {
userId() {
return this.getParam('userId', 'No ID');
},
activeTab() {
return this.getParam('tab', 'profile');
}
},
methods: {
switchTab(tab) {
// Navigate with query parameters
this.navigateTo('user-profile', {
userId: this.userId,
tab: tab
});
}
}
};
Usage: Navigate to /user-profile?userId=123&tab=settings or #/user-profile?userId=123&tab=settings (hash mode)
Multiple ways to access parameters:
// Direct parameter access
const userId = this.$params.userId; // Route parameter (direct access)
const tab = this.$query.tab; // Query parameter (direct access)
const search = this.getParam('search'); // Either route or query param
const allParams = this.getParams(); // Get all parameters
// With default values
const page = this.getParam('page', 1); // Default to 1 if not found
const sort = this.$query.sort || 'asc'; // Manual default for query params
ViewLogic automatically loads components from the components/ folder:
src/components/UserCard.js
export default {
name: 'UserCard',
template: `
<div class="user-card">
<img :src="user.avatar" :alt="user.name" class="avatar">
<div class="info">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<button @click="$emit('edit', user)" class="btn-edit">
Edit User
</button>
</div>
</div>
`,
emits: ['edit'],
props: {
user: {
type: Object,
required: true
}
}
};
Using components in views:
src/views/users.html
<div class="users-page">
<h1>Users</h1>
<UserCard
v-for="user in users"
:key="user.id"
:user="user"
@edit="editUser"
/>
</div>
src/logic/users.js
export default {
data() {
return {
users: []
};
},
methods: {
editUser(user) {
this.navigateTo('user-edit', { userId: user.id });
}
}
};
Dynamic Component Loading:
.js files to src/components/ folderBuilt-in reactive state management system:
// Set state (any component can access)
this.$state.set('user', { name: 'John', age: 30 });
this.$state.set('theme', 'dark');
// Get state with optional default
const user = this.$state.get('user');
const theme = this.$state.get('theme', 'light');
// Check if state exists
if (this.$state.has('user')) {
console.log('User is logged in');
}
// Watch for changes (reactive)
this.$state.watch('user', (newValue, oldValue) => {
console.log('User changed:', newValue);
// Update component data to trigger reactivity
this.currentUser = newValue;
});
// Bulk updates
this.$state.update({
theme: 'dark',
language: 'ko',
sidebar: 'collapsed'
});
// Get all state
const allState = this.$state.getAll();
// Clear specific state
this.$state.delete('temporaryData');
Complete authentication management:
// Check authentication status
if (this.isAuth()) {
console.log('User is logged in');
}
// Login with token
this.setToken('jwt-token-here');
// Login with options
this.setToken('jwt-token', {
storage: 'localStorage' // 'localStorage', 'sessionStorage', 'cookie'
});
// Get current token
const token = this.getToken();
// Logout (clears token and redirects to login)
this.logout();
Built-in HTTP client with automatic token injection:
// GET request
const users = await this.$api.get('/api/users');
// GET with query parameters
const filteredUsers = await this.$api.get('/api/users', {
params: { role: 'admin', active: true }
});
// POST with data
const newUser = await this.$api.post('/api/users', {
name: 'John',
email: 'john@example.com'
});
// PUT/PATCH/DELETE
await this.$api.put('/api/users/{userId}', userData);
await this.$api.patch('/api/users/{userId}', partialData);
await this.$api.delete('/api/users/{userId}');
// Parameter substitution (automatically uses route/query params)
// If current route is /users?userId=123, this becomes /api/users/123
const user = await this.$api.get('/api/users/{userId}');
// Automatic data loading in components
export default {
// Single API endpoint
dataURL: '/api/user/profile',
// Multiple endpoints
dataURL: {
profile: '/api/user/profile',
posts: '/api/posts?userId={userId}',
notifications: '/api/notifications'
},
mounted() {
// Data automatically loaded and available as:
// this.profile, this.posts, this.notifications
},
methods: {
// Manual data refresh - reuses dataURL configuration
async refreshData() {
await this.fetchData();
// All dataURL endpoints are called again
},
// Refresh when filters change
async applyFilter(filterType) {
this.$query.filter = filterType;
await this.fetchData(); // Refetch with new filter parameter
},
// Refresh when user changes
async switchUser(newUserId) {
this.$params.userId = newUserId;
await this.fetchData(); // Refetch with new userId parameter
},
// Pagination
async changePage(page) {
this.$query.page = page;
await this.fetchData(); // Load new page data
},
// Custom data loading
async loadSpecificData() {
const customData = await this.fetchData({
profile: '/api/admin/profile',
stats: '/api/stats?period={period}'
});
// Override default dataURL temporarily
}
}
};
Comprehensive i18n system:
// Simple translation
const message = this.$t('welcome.message');
// With parameters
const greeting = this.$t('hello.user', { name: 'John', role: 'admin' });
// Nested keys
const errorMsg = this.$t('errors.validation.email.required');
// Check current language
const currentLang = this.getLanguage();
// Change language (automatically reloads interface)
await this.setLanguage('ko');
Built-in logging system for debugging and error tracking:
export default {
async mounted() {
this.log('info', 'Component mounted successfully');
},
methods: {
async handleUserAction() {
this.log('debug', 'User action started', { action: 'submit' });
try {
const result = await this.$api.post('/api/users', userData);
this.log('info', 'User created successfully', result);
} catch (error) {
this.log('error', 'Failed to create user:', error);
}
},
async loadData() {
this.log('debug', 'Loading user data...');
try {
const data = await this.fetchData();
this.log('info', 'Data loaded', { count: data.length });
} catch (error) {
this.log('warn', 'Data loading failed, using cache', error);
}
}
}
};
Log Levels:
debug - Development debugging informationinfo - General information and success messageswarn - Warning messages for recoverable issueserror - Error messages for failuresAll logs include the component name automatically: [routeName] Your message
Simple yet powerful routing system:
// Navigate to route
this.navigateTo('user-profile');
// With query parameters
this.navigateTo('user-profile', { userId: 123, tab: 'settings' });
// Object syntax
this.navigateTo({
route: 'search-results',
params: { query: 'vue', category: 'tutorials' }
});
Revolutionary automatic form processing with parameter substitution:
<!-- Basic form - automatically handled on submit -->
<form action="/api/users" method="POST"
data-success="onUserCreated"
data-error="onUserError"
data-loading="setLoading">
<input name="name" v-model="userData.name" required>
<input name="email" v-model="userData.email" type="email" required>
<button type="submit">Create User</button>
</form>
<!-- Form with parameter substitution -->
<form action="/api/users/{userId}" method="PUT"
data-success="onUserUpdated"
data-redirect="user-profile">
<input name="name" v-model="user.name">
<input name="email" v-model="user.email">
<button type="submit">Update User</button>
</form>
<!-- File upload form -->
<form action="/api/upload" method="POST" enctype="multipart/form-data"
data-success="onFileUploaded">
<input name="avatar" type="file" accept="image/*">
<input name="description" v-model="description">
<button type="submit">Upload</button>
</form>
<!-- Form with custom validation -->
<form action="/api/contact" method="POST">
<input name="email" type="email" data-validation="validateEmail" required>
<textarea name="message" data-validation="validateMessage" required></textarea>
<button type="submit">Send Message</button>
</form>
// Component logic with form handlers
export default {
data() {
return {
userData: { name: '', email: '' },
user: { name: 'John', email: 'john@example.com' },
loading: false
};
},
methods: {
// Success handlers
onUserCreated(response, form) {
this.$state.set('newUser', response);
this.navigateTo('user-profile', { userId: response.id });
},
onUserUpdated(response, form) {
this.$state.set('currentUser', response);
// Auto redirect via data-redirect="user-profile"
},
onFileUploaded(response, form) {
this.$state.set('uploadedFile', response.file);
},
// Error handler
onUserError(error, form) {
console.error('User operation failed:', error);
},
// Loading handler
setLoading(isLoading, form) {
this.loading = isLoading;
},
// Custom validation functions
validateEmail(value, input) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(value);
},
validateMessage(value, input) {
return value.length >= 10;
}
}
};
const router = new ViewLogicRouter({
// Core routing settings
basePath: '/', // Base path for the application
mode: 'hash', // 'hash' or 'history'
// Authentication settings
auth: true, // Enable authentication system
loginRoute: 'login', // Route name for login page
protectedRoutes: ['dashboard', 'profile', 'admin/*', 'secure/*'],
publicRoutes: ['login', 'register', 'home', 'about'],
authStorage: 'localStorage', // 'localStorage', 'sessionStorage', 'cookie'
// Internationalization
useI18n: true, // Enable i18n system
defaultLanguage: 'en', // Default language
i18nPath: '/i18n', // Path to language files
// Caching system
cacheMode: 'memory', // Memory caching only
cacheTTL: 300000, // Cache TTL in milliseconds (5 minutes)
maxCacheSize: 100, // Maximum number of cached items
// API settings
apiBaseURL: 'https://api.example.com/v1', // Base URL for API requests
requestTimeout: 30000, // Form submission timeout in milliseconds (30 seconds)
uploadTimeout: 300000, // File upload timeout in milliseconds (5 minutes)
apiInterceptors: null, // API response/error interceptors ({ response?, error? })
// Development settings
environment: 'development', // 'development' or 'production'
logLevel: 'info' // 'error', 'warn', 'info', 'debug'
});
const router = new ViewLogicRouter({
// API Interceptors — global response/error hooks
apiInterceptors: {
// Transform or validate every API response
response(data, { url, method, status }) {
if (!data.success) console.warn(`[API] ${url}: unexpected format`);
return data;
},
// Global error handler (return a value to suppress the error)
error(error, { url, method }) {
console.error(`[API] ${url} failed:`, error.message);
// return { data: [] }; // return fallback to suppress error
}
},
// Custom authentication function
auth: true,
authFunction: async (route) => {
try {
// Use ViewLogic APIs like in components
const userData = await route.$api.get('/api/auth/verify');
route.$state.set('currentUser', userData);
return true;
} catch (error) {
console.error('Auth verification failed:', error);
return false;
}
}
});
# Development mode (zero build)
npm run dev
# Production build with optimization
npm run build
# Preview production build
npm run serve
ViewLogic Router automatically optimizes for production:
ViewLogic Router provides two optimized build outputs:
viewlogic-router.esm.js)import { ViewLogicRouter } from 'viewlogic'viewlogic-router.min.js)window.ViewLogicRouterBoth builds are fully minified and production-ready with source maps included.
We welcome contributions! Please read our Contributing Guide for details on:
MIT License - see LICENSE file for details.
Built with ❤️ for the Vue.js community. Special thanks to:
ViewLogic Router - One framework to rule them all! 🚀
Simplify your Vue development with the power of unified architecture.
FAQs
A lightweight, file-based routing system for Vue 3 applications with zero build configuration
We found that viewlogic demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.