feat: nuxt basics

This commit is contained in:
2025-10-24 12:55:14 +02:00
parent 51df03a76c
commit f1468ede1a
17 changed files with 243 additions and 21 deletions

View File

@@ -0,0 +1,2 @@
export default defineAppConfig({
})

View File

@@ -1,6 +1,5 @@
<template>
<div>
<NuxtRouteAnnouncer />
<NuxtWelcome />
</div>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>

14
front-nuxt/app/error.vue Normal file
View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
import type { NuxtError } from "#app";
const { error } = defineProps({
error: Object as () => NuxtError,
});
</script>
<template>
<div>
<h1>{{ error?.statusCode }}</h1>
<NuxtLink to="/">Go back home</NuxtLink>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<header>
Loging header actions
</header>
<slot/>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<main>
<header>Header</header>
<slot />
<footer>Footer</footer>
</main>
</template>

View File

@@ -0,0 +1,8 @@
export default defineNuxtRouteMiddleware((to, from) => {
const userStore = useUserStore();
console.log(
">> Global Middleware from ",
from.query,
userStore.profile,
);
});

View File

@@ -0,0 +1,3 @@
export default defineNuxtRouteMiddleware((to, from) => {
console.log(">> Middleware from ", from.query);
})

View File

@@ -0,0 +1,5 @@
<template>
<div>
About
</div>
</template>

View File

@@ -0,0 +1,3 @@
<template>
<div>Main page</div>
</template>

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
definePageMeta({
layout: "auth",
middleware: "login",
});
const userStore = useUserStore();
const setUpUser = () => {
userStore.update({
id: "1",
name: "My name",
roles: ["user", "manager"],
});
};
</script>
<template>
<div>
Login form
<div>
User profile:
{{ userStore.profile }}
</div>
<button @click="setUpUser">Login</button>
</div>
</template>

View File

@@ -0,0 +1,10 @@
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
// handle error, e.g. report to a service
}
// Also possible
nuxtApp.hook('vue:error', (error, instance, info) => {
// handle error, e.g. report to a service
})
})

View File

@@ -0,0 +1,46 @@
type Role = "user" | "manager" | "admin";
interface ApiSession {
exp?: number;
accessToken: string;
refreshToken?: string;
}
interface User {
id: string;
roles: Role[];
image?: string;
name?: string;
apiSession?: ApiSession;
}
export const useUserStore = defineStore("user", {
state: (): User => {
const user = useCookie("userSession", {
default: (): User => ({ id: "-1", roles: [] }),
watch: false,
});
return user.value;
},
getters: {
profile: (state) => ({
id: state.id,
name: state.name,
image: state.image,
roles: state.roles,
}),
},
actions: {
persist() {
const user = useCookie("userSession", {
default: (): User => ({ id: "-1", roles: [] }),
watch: false,
});
user.value ||= this.profile;
},
update(user: User) {
this.$state = user;
this.persist();
},
},
});

View File

@@ -2,5 +2,13 @@
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
modules: ['@nuxt/eslint', '@nuxt/image', '@nuxt/test-utils']
})
modules: ['@nuxt/eslint', '@nuxt/image', '@nuxt/test-utils', '@pinia/nuxt'],
vite: {
vue: {
customElement: true,
},
vueJsx: {
mergeProps: true,
},
},
})

View File

@@ -10,9 +10,11 @@
"@nuxt/eslint": "^1.9.0",
"@nuxt/image": "^1.11.0",
"@nuxt/test-utils": "^3.19.2",
"@pinia/nuxt": "^0.11.2",
"@xstate/vue": "^5.0.0",
"eslint": "^9.36.0",
"nuxt": "^4.1.2",
"pinia": "^3.0.3",
"vue": "^3.5.21",
"vue-router": "^4.5.1",
"xstate": "^5.22.0"
@@ -3192,6 +3194,53 @@
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@pinia/nuxt": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.11.2.tgz",
"integrity": "sha512-CgvSWpbktxxWBV7ModhAcsExsQZqpPq6vMYEe9DexmmY6959ev8ukL4iFhr/qov2Nb9cQAWd7niFDnaWkN+FHg==",
"dependencies": {
"@nuxt/kit": "^3.9.0"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"pinia": "^3.0.3"
}
},
"node_modules/@pinia/nuxt/node_modules/@nuxt/kit": {
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.19.3.tgz",
"integrity": "sha512-ze46EW5xW+UxDvinvPkYt2MzR355Az1lA3bpX8KDialgnCwr+IbkBij/udbUEC6ZFbidPkfK1eKl4ESN7gMY+w==",
"dependencies": {
"c12": "^3.3.0",
"consola": "^3.4.2",
"defu": "^6.1.4",
"destr": "^2.0.5",
"errx": "^0.1.0",
"exsolve": "^1.0.7",
"ignore": "^7.0.5",
"jiti": "^2.6.1",
"klona": "^2.0.6",
"knitwork": "^1.2.0",
"mlly": "^1.8.0",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"pkg-types": "^2.3.0",
"rc9": "^2.1.2",
"scule": "^1.3.0",
"semver": "^7.7.2",
"std-env": "^3.9.0",
"tinyglobby": "^0.2.15",
"ufo": "^1.6.1",
"unctx": "^2.4.1",
"unimport": "^5.4.1",
"untyped": "^2.0.0"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -8224,10 +8273,9 @@
}
},
"node_modules/jiti": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz",
"integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==",
"license": "MIT",
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
@@ -9657,6 +9705,34 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pinia": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz",
"integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==",
"dependencies": {
"@vue/devtools-api": "^7.7.2"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.4.4",
"vue": "^2.7.0 || ^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/@vue/devtools-api": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz",
"integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==",
"dependencies": {
"@vue/devtools-kit": "^7.7.7"
}
},
"node_modules/pkg-types": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
@@ -11284,10 +11360,9 @@
}
},
"node_modules/strip-literal": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
"integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
"license": "MIT",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
"dependencies": {
"js-tokens": "^9.0.1"
},
@@ -11298,8 +11373,7 @@
"node_modules/strip-literal/node_modules/js-tokens": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
"license": "MIT"
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="
},
"node_modules/structured-clone-es": {
"version": "1.0.0",
@@ -11688,10 +11762,9 @@
}
},
"node_modules/unimport": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/unimport/-/unimport-5.4.0.tgz",
"integrity": "sha512-g/OLFZR2mEfqbC6NC9b2225eCJGvufxq34mj6kM3OmI5gdSL0qyqtnv+9qmsGpAmnzSl6x0IWZj4W+8j2hLkMA==",
"license": "MIT",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/unimport/-/unimport-5.4.1.tgz",
"integrity": "sha512-wMZ2JKUCleCK2zfRHeWcbrUHKXOC3SVBYkyn/wTGzh0THX6sT4hSjuKXxKANN4/WMbT6ZPM4JzcDcnhD2x9Bpg==",
"dependencies": {
"acorn": "^8.15.0",
"escape-string-regexp": "^5.0.0",
@@ -11703,7 +11776,7 @@
"picomatch": "^4.0.3",
"pkg-types": "^2.3.0",
"scule": "^1.3.0",
"strip-literal": "^3.0.0",
"strip-literal": "^3.1.0",
"tinyglobby": "^0.2.15",
"unplugin": "^2.3.10",
"unplugin-utils": "^0.3.0"

View File

@@ -13,9 +13,11 @@
"@nuxt/eslint": "^1.9.0",
"@nuxt/image": "^1.11.0",
"@nuxt/test-utils": "^3.19.2",
"@pinia/nuxt": "^0.11.2",
"@xstate/vue": "^5.0.0",
"eslint": "^9.36.0",
"nuxt": "^4.1.2",
"pinia": "^3.0.3",
"vue": "^3.5.21",
"vue-router": "^4.5.1",
"xstate": "^5.22.0"

View File

@@ -0,0 +1,3 @@
export default defineEventHandler(async (event) => {
// ... Do whatever you want here
})

View File

@@ -0,0 +1,7 @@
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('render:html', (html, { event }) => {
html.head.push(`<meta name="description" content="This is an example description." />`)
})
// You can also intercept the response here.
// nitroApp.hooks.hook('render:response', (response, { event }) => { console.log(response) })
})