From f1468ede1a61d9d421a4f2747324cc1e4d1d31dd Mon Sep 17 00:00:00 2001 From: Daniel Heras Quesada Date: Fri, 24 Oct 2025 12:55:14 +0200 Subject: [PATCH] feat: nuxt basics --- front-nuxt/app/app.config.ts | 2 + front-nuxt/app/app.vue | 7 +- front-nuxt/app/error.vue | 14 +++ front-nuxt/app/layouts/auth.vue | 6 ++ front-nuxt/app/layouts/default.vue | 7 ++ front-nuxt/app/middleware/auth.global.ts | 8 ++ front-nuxt/app/middleware/login.ts | 3 + front-nuxt/app/pages/about.vue | 5 + front-nuxt/app/pages/index.vue | 3 + front-nuxt/app/pages/login.vue | 26 +++++ front-nuxt/app/plugins/log-errors.client.ts | 10 ++ front-nuxt/app/stores/user.ts | 46 +++++++++ front-nuxt/nuxt.config.ts | 12 ++- front-nuxt/package-lock.json | 103 +++++++++++++++++--- front-nuxt/package.json | 2 + front-nuxt/server/api/test.ts | 3 + front-nuxt/server/plugins/define-metas.ts | 7 ++ 17 files changed, 243 insertions(+), 21 deletions(-) create mode 100644 front-nuxt/app/app.config.ts create mode 100644 front-nuxt/app/error.vue create mode 100644 front-nuxt/app/layouts/auth.vue create mode 100644 front-nuxt/app/layouts/default.vue create mode 100644 front-nuxt/app/middleware/auth.global.ts create mode 100644 front-nuxt/app/middleware/login.ts create mode 100644 front-nuxt/app/pages/about.vue create mode 100644 front-nuxt/app/pages/index.vue create mode 100644 front-nuxt/app/pages/login.vue create mode 100644 front-nuxt/app/plugins/log-errors.client.ts create mode 100644 front-nuxt/app/stores/user.ts create mode 100644 front-nuxt/server/api/test.ts create mode 100644 front-nuxt/server/plugins/define-metas.ts diff --git a/front-nuxt/app/app.config.ts b/front-nuxt/app/app.config.ts new file mode 100644 index 0000000..1ab1f2e --- /dev/null +++ b/front-nuxt/app/app.config.ts @@ -0,0 +1,2 @@ +export default defineAppConfig({ +}) diff --git a/front-nuxt/app/app.vue b/front-nuxt/app/app.vue index 09f935b..5e39f2a 100644 --- a/front-nuxt/app/app.vue +++ b/front-nuxt/app/app.vue @@ -1,6 +1,5 @@ diff --git a/front-nuxt/app/error.vue b/front-nuxt/app/error.vue new file mode 100644 index 0000000..b85f93b --- /dev/null +++ b/front-nuxt/app/error.vue @@ -0,0 +1,14 @@ + + + diff --git a/front-nuxt/app/layouts/auth.vue b/front-nuxt/app/layouts/auth.vue new file mode 100644 index 0000000..a1ca963 --- /dev/null +++ b/front-nuxt/app/layouts/auth.vue @@ -0,0 +1,6 @@ + diff --git a/front-nuxt/app/layouts/default.vue b/front-nuxt/app/layouts/default.vue new file mode 100644 index 0000000..e97fa26 --- /dev/null +++ b/front-nuxt/app/layouts/default.vue @@ -0,0 +1,7 @@ + diff --git a/front-nuxt/app/middleware/auth.global.ts b/front-nuxt/app/middleware/auth.global.ts new file mode 100644 index 0000000..164e2c8 --- /dev/null +++ b/front-nuxt/app/middleware/auth.global.ts @@ -0,0 +1,8 @@ +export default defineNuxtRouteMiddleware((to, from) => { + const userStore = useUserStore(); + console.log( + ">> Global Middleware from ", + from.query, + userStore.profile, + ); +}); diff --git a/front-nuxt/app/middleware/login.ts b/front-nuxt/app/middleware/login.ts new file mode 100644 index 0000000..35a8bf2 --- /dev/null +++ b/front-nuxt/app/middleware/login.ts @@ -0,0 +1,3 @@ +export default defineNuxtRouteMiddleware((to, from) => { + console.log(">> Middleware from ", from.query); +}) diff --git a/front-nuxt/app/pages/about.vue b/front-nuxt/app/pages/about.vue new file mode 100644 index 0000000..4a736a4 --- /dev/null +++ b/front-nuxt/app/pages/about.vue @@ -0,0 +1,5 @@ + diff --git a/front-nuxt/app/pages/index.vue b/front-nuxt/app/pages/index.vue new file mode 100644 index 0000000..c0c5498 --- /dev/null +++ b/front-nuxt/app/pages/index.vue @@ -0,0 +1,3 @@ + diff --git a/front-nuxt/app/pages/login.vue b/front-nuxt/app/pages/login.vue new file mode 100644 index 0000000..ee57f37 --- /dev/null +++ b/front-nuxt/app/pages/login.vue @@ -0,0 +1,26 @@ + + + diff --git a/front-nuxt/app/plugins/log-errors.client.ts b/front-nuxt/app/plugins/log-errors.client.ts new file mode 100644 index 0000000..dfc86bf --- /dev/null +++ b/front-nuxt/app/plugins/log-errors.client.ts @@ -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 + }) +}) diff --git a/front-nuxt/app/stores/user.ts b/front-nuxt/app/stores/user.ts new file mode 100644 index 0000000..c522bbe --- /dev/null +++ b/front-nuxt/app/stores/user.ts @@ -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(); + }, + }, +}); diff --git a/front-nuxt/nuxt.config.ts b/front-nuxt/nuxt.config.ts index 53f5289..af0f17c 100644 --- a/front-nuxt/nuxt.config.ts +++ b/front-nuxt/nuxt.config.ts @@ -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, + }, + }, +}) \ No newline at end of file diff --git a/front-nuxt/package-lock.json b/front-nuxt/package-lock.json index a46df0e..0c4e957 100644 --- a/front-nuxt/package-lock.json +++ b/front-nuxt/package-lock.json @@ -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" diff --git a/front-nuxt/package.json b/front-nuxt/package.json index 3b420d8..097204a 100644 --- a/front-nuxt/package.json +++ b/front-nuxt/package.json @@ -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" diff --git a/front-nuxt/server/api/test.ts b/front-nuxt/server/api/test.ts new file mode 100644 index 0000000..1d77611 --- /dev/null +++ b/front-nuxt/server/api/test.ts @@ -0,0 +1,3 @@ +export default defineEventHandler(async (event) => { + // ... Do whatever you want here +}) diff --git a/front-nuxt/server/plugins/define-metas.ts b/front-nuxt/server/plugins/define-metas.ts new file mode 100644 index 0000000..f139675 --- /dev/null +++ b/front-nuxt/server/plugins/define-metas.ts @@ -0,0 +1,7 @@ +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('render:html', (html, { event }) => { + html.head.push(``) + }) + // You can also intercept the response here. + // nitroApp.hooks.hook('render:response', (response, { event }) => { console.log(response) }) +})