Skip to content

Fix TypeScript errors in ssr.ts & when using vue-tsc #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions resources/js/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@ import { createApp, h } from 'vue';
import { ZiggyVue } from 'ziggy-js';
import { initializeTheme } from './composables/useAppearance';

// Extend ImportMeta interface for Vite...
declare module 'vite/client' {
interface ImportMetaEnv {
readonly VITE_APP_NAME: string;
[key: string]: string | boolean | undefined;
}

interface ImportMeta {
readonly env: ImportMetaEnv;
readonly glob: <T>(pattern: string) => Record<string, () => Promise<T>>;
}
}

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

createInertiaApp({
Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@ const rightNavItems: NavItem[] = [
class="relative size-10 w-auto rounded-full p-1 focus-within:ring-2 focus-within:ring-primary"
>
<Avatar class="size-8 overflow-hidden rounded-full">
<AvatarImage v-if="auth.user.avatar" :src="auth.user.avatar" :alt="auth.user.name" />
<AvatarImage v-if="auth.user?.avatar" :src="auth.user.avatar" :alt="auth.user.name" />
<AvatarFallback class="rounded-lg bg-neutral-200 font-semibold text-black dark:bg-neutral-700 dark:text-white">
{{ getInitials(auth.user?.name) }}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-56">
<UserMenuContent :user="auth.user" />
<UserMenuContent :user="auth.user!" />
</DropdownMenuContent>
</DropdownMenu>
</div>
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/AppSidebarHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defineProps<{
>
<div class="flex items-center gap-2">
<SidebarTrigger class="-ml-1" />
<template v-if="breadcrumbs.length > 0">
<template v-if="breadcrumbs?.length">
<Breadcrumbs :breadcrumbs="breadcrumbs" />
</template>
</div>
Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/NavMain.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script setup lang="ts">
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar';
import { type NavItem, type SharedData } from '@/types';
import { type NavItem} from '@/types';
import { Link, usePage } from '@inertiajs/vue3';

defineProps<{
items: NavItem[];
}>();

const page = usePage<SharedData>();
const page = usePage();
</script>

<template>
Expand Down
10 changes: 5 additions & 5 deletions resources/js/components/NavUser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
import UserInfo from '@/components/UserInfo.vue';
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, useSidebar } from '@/components/ui/sidebar';
import { type SharedData, type User } from '@/types';
import { type User } from '@/types';
import { usePage } from '@inertiajs/vue3';
import { ChevronsUpDown } from 'lucide-vue-next';
import UserMenuContent from './UserMenuContent.vue';

const page = usePage<SharedData>();
const page = usePage();
const user = page.props.auth.user as User;
const { isMobile, state } = useSidebar();
</script>
Expand All @@ -22,10 +22,10 @@ const { isMobile, state } = useSidebar();
<ChevronsUpDown class="ml-auto size-4" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
class="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
<DropdownMenuContent
class="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
:side="isMobile ? 'bottom' : state === 'collapsed' ? 'left' : 'bottom'"
align="end"
align="end"
:side-offset="4"
>
<UserMenuContent :user="user" />
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/TextLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Link } from '@inertiajs/vue3';
interface Props {
href: string;
tabindex?: number;
method?: string;
method?: 'get' | 'post' | 'put' | 'patch' | 'delete';
as?: string;
}

Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/UserInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const showAvatar = computed(() => props.user.avatar && props.user.avatar !== '')

<template>
<Avatar class="h-8 w-8 overflow-hidden rounded-lg">
<AvatarImage v-if="showAvatar" :src="user.avatar" :alt="user.name" />
<AvatarImage v-if="showAvatar" :src="user.avatar!" :alt="user.name" />
<AvatarFallback class="rounded-lg text-black dark:text-white">
{{ getInitials(user.name) }}
</AvatarFallback>
Expand Down
2 changes: 1 addition & 1 deletion resources/js/pages/Welcome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ import { Head, Link } from '@inertiajs/vue3';
/>
</g>
<g
:style="{ mixBlendMode: 'plus-darker' }"
:style="`mixBlendMode: 'plus-darker'`"
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
>
<path
Expand Down
4 changes: 2 additions & 2 deletions resources/js/pages/settings/Profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AppLayout from '@/layouts/AppLayout.vue';
import SettingsLayout from '@/layouts/settings/Layout.vue';
import { type BreadcrumbItem, type SharedData, type User } from '@/types';
import { type BreadcrumbItem, type User } from '@/types';

interface Props {
mustVerifyEmail: boolean;
Expand All @@ -25,7 +25,7 @@ const breadcrumbs: BreadcrumbItem[] = [
},
];

const page = usePage<SharedData>();
const page = usePage();
const user = page.props.auth.user as User;

const form = useForm({
Expand Down
28 changes: 21 additions & 7 deletions resources/js/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { createInertiaApp } from '@inertiajs/vue3';
import createServer from '@inertiajs/vue3/server';
import { renderToString } from '@vue/server-renderer';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createSSRApp, h } from 'vue';
import { route as ziggyRoute } from 'ziggy-js';
import { createSSRApp, DefineComponent, h } from 'vue';
import { route, RouteParams, Router } from 'ziggy-js';

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

Expand All @@ -12,7 +12,7 @@ createServer((page) =>
page,
render: renderToString,
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./pages/${name}.vue`, import.meta.glob('./pages/**/*.vue')),
resolve: resolvePage,
setup({ App, props, plugin }) {
const app = createSSRApp({ render: () => h(App, props) });

Expand All @@ -22,15 +22,23 @@ createServer((page) =>
location: new URL(page.props.ziggy.location),
};

// Create route function...
const route = (name: string, params?: any, absolute?: boolean) => ziggyRoute(name, params, absolute, ziggyConfig);
// bind config to ziggyRoute function
function appRoute(): Router;
function appRoute(name: string, params?: RouteParams<typeof name>, absolute?: boolean): string;
function appRoute(name?: string, params?: RouteParams<string>, absolute?: boolean): Router | string {
if (name === undefined) {
return route();
}

return route(name, params, absolute, ziggyConfig);
}

// Make route function available globally...
app.config.globalProperties.route = route;
app.config.globalProperties.route = appRoute;

// Make route function available globally for SSR...
if (typeof window === 'undefined') {
global.route = route;
global.route = appRoute;
}

app.use(plugin);
Expand All @@ -39,3 +47,9 @@ createServer((page) =>
},
}),
);

function resolvePage(name: string) {
const pages = import.meta.glob<DefineComponent>('./Pages/**/*.vue');

return resolvePageComponent<DefineComponent>(`./Pages/${name}.vue`, pages);
}
32 changes: 29 additions & 3 deletions resources/js/types/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import type { route as routeFn } from 'ziggy-js';
import { AppPageProps } from '@/types/index';
import { createHeadManager, Page, Router } from '@inertiajs/core';

declare global {
const route: typeof routeFn;
// Extend ImportMeta interface for Vite...
declare module 'vite/client' {
interface ImportMetaEnv {
readonly VITE_APP_NAME: string;

[key: string]: string | boolean | undefined;
}

interface ImportMeta {
readonly env: ImportMetaEnv;
readonly glob: <T>(pattern: string) => Record<string, () => Promise<T>>;
}
}

// Declare shared props for Inertia and App pages...
declare module '@inertiajs/core' {
interface PageProps extends InertiaPageProps, AppPageProps {}
}

// Add typings for Inertia's $page and $headManager properties...
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$inertia: typeof Router;
$page: Page;
$headManager: ReturnType<typeof createHeadManager>;
route: AppRouter;
}
}
17 changes: 6 additions & 11 deletions resources/js/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { PageProps } from '@inertiajs/core';
import type { LucideIcon } from 'lucide-vue-next';
import type { Config } from 'ziggy-js';

export interface Auth {
user: User;
}
export type AppPageProps = {
name: string;
quote: { message: string; author: string };
auth: { user: User | null };
ziggy: Config & { location: string };
};

export interface BreadcrumbItem {
title: string;
Expand All @@ -18,13 +20,6 @@ export interface NavItem {
isActive?: boolean;
}

export interface SharedData extends PageProps {
name: string;
quote: { message: string; author: string };
auth: Auth;
ziggy: Config & { location: string };
}

export interface User {
id: number;
name: string;
Expand Down
10 changes: 2 additions & 8 deletions resources/js/types/ziggy.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { Config, RouteParams } from 'ziggy-js';
import { RouteParams, Router } from 'ziggy-js';

declare global {
function route(): Config;
function route(): Router;
function route(name: string, params?: RouteParams<typeof name> | undefined, absolute?: boolean): string;
}

declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
route: typeof route;
}
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"vite/client",
"vue/tsx",
"node",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain to me what this is doing here?

Everything else is looking really good. Thanks for the PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not find any source for the vue/tsx types within the installed packages, nor any reference in the official Vue docs recommending setting this as a value See TS docs for Vue. I assume this value was set by mistake or might be a remnant from an outdated Vue version.

The addition of the node types is simply there to make the compiler aware of the global object in ssr.ts.

"./resources/js/types"
] /* Specify type package names to be included without being referenced in a source file. */,
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
Expand Down