import './bootstrap'; import '../css/app.css'; import { createApp, h } from 'vue'; import { createInertiaApp, usePage } from '@inertiajs/vue3'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; import { ZiggyVue } from '../../vendor/tightenco/ziggy'; import { createPinia } from 'pinia'; import type { User } from '@/types/models'; import { QueryClient, VueQueryPlugin } from '@tanstack/vue-query'; import { type DefineComponent } from 'vue'; import { setupPrefetching } from '@/utils/prefetch'; interface ExtensionManifest { name?: string; alias?: string; } const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; const pinia = createPinia(); const queryClient = new QueryClient(); const extensionManifests = import.meta.glob('../../extensions/**/module.json', { eager: true, import: 'default', }) as Record; // BillingPortal is a Vue 2 component and must not be bundled into the Vue 3 app. const extensionPages = import.meta.glob([ '../../extensions/**/resources/js/Pages/**/*.vue', '!**/BillingPortal.vue', ]); const extensionDirectories = Object.entries(extensionManifests).reduce>( (directories, [path, manifest]) => { const match = path.match(/^\.\.\/\.\.\/extensions\/([^/]+)\/module\.json$/); const extensionDirectory = match?.[1]; if (extensionDirectory === undefined) { return directories; } for (const key of [manifest.name, manifest.alias, extensionDirectory]) { if (typeof key !== 'string' || key === '') { continue; } directories[key] = extensionDirectory; directories[key.toLowerCase()] = extensionDirectory; } return directories; }, {} ); function resolveExtensionDirectory(moduleName: string): string { return ( extensionDirectories[moduleName] ?? extensionDirectories[moduleName.toLowerCase()] ?? moduleName ); } createInertiaApp({ title: (title) => `${title} - ${appName}`, resolve: (name) => { // "Module::Page" (both halves present) resolves to that extension's page // directory; everything else is a host page under resources/js/Pages. const [module, ...pageSegments] = name.split('::'); const page = pageSegments.join('::'); if (module && page) { const extensionDirectory = resolveExtensionDirectory(module); const pagePath = `../../extensions/${extensionDirectory}/resources/js/Pages/${page}.vue`; return resolvePageComponent(pagePath, extensionPages); } return resolvePageComponent( `./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue') ); }, setup({ el, App, props, plugin }) { const app = createApp({ render: () => h(App, props) }); // currently only one vue app setup hook is supported if (window.vueAppSetupHook) { window.vueAppSetupHook(app); } window.getWeekStartSetting = function () { const page = usePage<{ auth: { user: User; }; }>(); return page.props.auth.user.week_start ?? 'monday'; }; window.getTimezoneSetting = function () { const page = usePage<{ auth: { user: User; }; }>(); return page.props.auth.user.timezone; }; app.use(plugin).use(pinia).use(ZiggyVue).use(VueQueryPlugin, { queryClient }).mount(el); // Setup Inertia prefetching to warm TanStack Query cache setupPrefetching(queryClient); }, progress: { color: '#4B5563', }, });