npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

viewlogic

v1.2.10

Published

A lightweight, file-based routing system for Vue 3 applications with zero build configuration

Readme

ViewLogic Router

AI-First Vue 3 Framework: The future of web development in the age of artificial intelligence

🎯 Core Philosophy

ViewLogic Router revolutionizes Vue development with three fundamental principles:

🎭 View-Logic Separation

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 Development

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.

🤖 AI-First Architecture

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.

✨ What Makes ViewLogic Special

All-in-One Solution - Replace multiple libraries with one unified framework:

  • 🔀 Routing - File-based routing with zero configuration
  • 📦 State Management - Built-in reactive state without external dependencies
  • 🔐 Authentication - JWT auth with multiple storage options
  • 🌐 Internationalization - Multi-language support with lazy loading
  • 💾 Caching - Smart caching with TTL and LRU eviction
  • 🌐 API Client - HTTP client with automatic token injection
  • 📝 Form Handling - Revolutionary form processing with parameter substitution

Tiny Bundle Size - Complete framework in just 52KB minified / 18KB gzipped!

Easy Integration - Drop-in UMD build available for instant usage without build tools.

🏗️ Project Structure

ViewLogic Router follows a clean, intuitive folder structure:

project/
├── src/
│   ├── views/              # HTML templates (pure presentation)
│   │   ├── home.html
│   │   ├── user-profile.html
│   │   └── dashboard.html
│   ├── logic/              # Vue component logic (pure JavaScript)
│   │   ├── home.js
│   │   ├── user-profile.js
│   │   └── dashboard.js
│   ├── components/         # Reusable UI components
│   │   ├── UserCard.vue
│   │   └── NavigationMenu.vue
│   ├── layouts/            # Layout templates
│   │   ├── default.html
│   │   └── admin.html
│   └── styles/             # Page-specific CSS files
│       ├── home.css
│       └── user-profile.css
├── css/                    # Global CSS files
│   └── 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

🚀 Quick Start

Method 1: Create New Project (Recommended)

npm create viewlogic myapp
cd myapp
npm run dev

This creates a complete project with examples and starts the development server.

Method 2: UMD Build (No Build Tools)

<!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>

Method 3: ES6 Modules

npm install viewlogic

Option A: Using bundler (Vite, Webpack, etc.)

import { ViewLogicRouter } from 'viewlogic';

const router = new ViewLogicRouter({
    environment: 'production',
    authEnabled: 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',
            authEnabled: true,
            useI18n: true
        });
    </script>
</body>
</html>

Create Your First Route

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 layouts/default.html
    // layout: 'admin',       // Use layouts/admin.html
    // layout: null,          // No layout (page-only content)

    data() {
        return {
            message: 'Welcome to ViewLogic!',
            count: 0
        };
    },
    methods: {
        increment() {
            this.count++;
        }
    }
};

src/styles/home.css (optional)

.home {
    padding: 2rem;
    text-align: center;
}

.home h1 {
    color: #2c3e50;
    margin-bottom: 1rem;
}

src/layouts/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>&copy; 2024 My ViewLogic App</p>
</footer>

Query Parameter Example

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

Reusable Components

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:

  • Just add .js files to src/components/ folder
  • Components are automatically discovered and loaded
  • No import statements needed - ViewLogic handles everything
  • Components are available instantly in all views

🎯 Core APIs

State Management

Built-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');

Authentication System

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();

API Management

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: '[email protected]'
});

// 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
        }
    }
};

Internationalization

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');

Logging & Error Handling

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 information
  • info - General information and success messages
  • warn - Warning messages for recoverable issues
  • error - Error messages for failures

All logs include the component name automatically: [routeName] Your message

Navigation & Routing

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' }
});

Form Handling

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: '[email protected]' },
            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;
        }
    }
};

⚙️ Configuration

Basic Configuration

const router = new ViewLogicRouter({
    // Core routing settings
    basePath: '/',                      // Base path for the application
    mode: 'hash',                       // 'hash' or 'history'

    // Authentication settings
    authEnabled: true,                  // Enable authentication system
    loginRoute: 'login',                // Route name for login page
    protectedRoutes: ['dashboard', 'profile', 'admin'],
    protectedPrefixes: ['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)

    // Development settings
    environment: 'development',         // 'development' or 'production'
    logLevel: 'info'                    // 'error', 'warn', 'info', 'debug'
});

Advanced Configuration

const router = new ViewLogicRouter({
    // Custom authentication function
    authEnabled: true,
    checkAuthFunction: 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;
        }
    }
});

🔧 Production Build

# Development mode (zero build)
npm run dev

# Production build with optimization
npm run build

# Preview production build
npm run serve

Production Optimizations

ViewLogic Router automatically optimizes for production:

  • Code splitting: Each route becomes a separate bundle
  • Tree shaking: Unused features are eliminated
  • Minification: Code is compressed and optimized
  • Caching: Aggressive caching for static assets
  • Lazy loading: Routes and components load on demand

📦 Build Output

ViewLogic Router provides two optimized build outputs:

ESM Module (viewlogic-router.esm.js)

  • Format: ES6 modules
  • Size: ~52KB minified
  • Usage: Modern bundlers (Vite, Webpack, Rollup)
  • Import: import { ViewLogicRouter } from 'viewlogic'

UMD Bundle (viewlogic-router.min.js)

  • Format: UMD (Universal Module Definition)
  • Size: ~52KB minified
  • Usage: Direct browser usage, CDN
  • Global: window.ViewLogicRouter

Both builds are fully minified and production-ready with source maps included.

🤝 Contributing

We welcome contributions! Please read our Contributing Guide for details on:

  • Code style and conventions
  • Testing requirements
  • Pull request process
  • Issue reporting guidelines

📄 License

MIT License - see LICENSE file for details.

🙏 Acknowledgments

Built with ❤️ for the Vue.js community. Special thanks to:

  • Vue.js team for the amazing framework
  • The open-source community for inspiration and feedback
  • All contributors who helped shape ViewLogic Router

ViewLogic Router - One framework to rule them all! 🚀

Simplify your Vue development with the power of unified architecture.