Advanced Usage
Work in progress
This page is a work in progress. Help complete it by contributing on GitHub!
Ready to level up your asset management skills? This guide covers advanced techniques that will help you build more sophisticated applications. Don't let the word "advanced" intimidate you—we'll explain each concept clearly, and you can adopt these techniques gradually as your needs grow.
TypeScript Support
Vite provides first-class TypeScript support with zero configuration. Simply use .ts files and Vite will compile them automatically.
TypeScript is a strongly typed programming language that builds on JavaScript by adding optional static type definitions. It helps catch errors during development, provides better IDE support with autocomplete and refactoring tools, and makes your code more maintainable and self-documenting.
Type Checking
While Vite compiles TypeScript, it doesn't perform type checking during compilation for performance. Run type checking separately:
npm run typecheck
# or: vue-tsc --noEmit
Include this in your CI/CD pipeline to catch type errors before deployment.
TypeScript Configuration
Configure TypeScript via tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["app/assets/**/*.ts", "app/assets/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
Type Declarations
Create type declarations for global variables or modules:
env.d.ts:
/// <reference types="vite/client" />
/// <reference types="@userfrosting/sprinkle-core" />
// Declare module for .vue files
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// Global properties on Vue instances
declare module 'vue' {
interface ComponentCustomProperties {
$t: (key: string, params?: any) => string
$tdate: (date: Date | string, format?: string) => string
}
}
Vue 3 Integration
UserFrosting uses Vue 3 for interactive components. Vite's official Vue plugin provides optimal Single File Component (SFC) support.
Creating Components
app/assets/components/UserCard.vue:
<script setup lang="ts">
import { ref } from 'vue'
interface Props {
username: string
email: string
}
const props = defineProps<Props>()
const isExpanded = ref(false)
function toggleExpanded() {
isExpanded.value = !isExpanded.value
}
</script>
<template>
<div class="user-card" @click="toggleExpanded">
<h3>{{ username }}</h3>
<p v-if="isExpanded">{{ email }}</p>
</div>
</template>
<style scoped lang="less">
.user-card {
padding: 1rem;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
&:hover {
background: #f5f5f5;
}
h3 {
margin: 0 0 0.5rem 0;
}
}
</style>
Component Registration
Register components globally in your main entry point:
import { createApp } from 'vue'
import App from './App.vue'
import UserCard from './components/UserCard.vue'
const app = createApp(App)
// Global registration
app.component('UserCard', UserCard)
app.mount('#app')
Or use local registration within components:
<script setup lang="ts">
import UserCard from './components/UserCard.vue'
</script>
<template>
<UserCard username="admin" email="[email protected]" />
</template>
Vue Router
Set up routing for single-page applications:
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'home',
component: () => import('./views/HomePage.vue')
},
{
path: '/users',
name: 'users',
component: () => import('./views/UsersPage.vue')
}
]
const router = createRouter({
history: createWebHistory('/'),
routes
})
export default router
Pinia State Management
UserFrosting uses Pinia for state management:
import { defineStore } from 'pinia'
import axios from 'axios'
export const useUserStore = defineStore('user', {
state: () => ({
currentUser: null as User | null,
isLoading: false
}),
getters: {
isAuthenticated: (state) => state.currentUser !== null
},
actions: {
async fetchCurrentUser() {
this.isLoading = true
try {
const response = await axios.get('/api/users/current')
this.currentUser = response.data
} finally {
this.isLoading = false
}
}
}
})
CSS Preprocessors
Vite supports LESS, Sass, and Stylus out of the box. Just import preprocessor files and install the appropriate package.
LESS
UserFrosting uses LESS by default, particularly for UIKit theming.
npm install -D less
app/assets/theme.less:
// Import UIKit
@import 'uikit/src/less/uikit.less';
// Override UIKit variables
@global-primary-background: #0066cc;
@global-font-family: 'Helvetica Neue', sans-serif;
// Custom styles
.custom-container {
padding: @global-margin;
h1 {
color: @global-primary-background;
}
}
Sass/SCSS
If you prefer Sass:
npm install -D sass
app/assets/styles.scss:
$primary-color: #0066cc;
.button {
background: $primary-color;
&:hover {
background: darken($primary-color, 10%);
}
}
Warning
UserFrosting uses Less as its default CSS preprocessor for the default theme. If you choose to use SASS/SCSS instead, you will not be able to easily customize or extend the default theme's styles, as the theme's variables and mixins are written in Less. Consider this trade-off when choosing your preprocessor.
Next Steps
Learn about managing assets across multiple sprinkles or how to migrate from Webpack.