feat: Setup GraphQL with dynamic node routing logic
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"recommendations": ["oxc.oxc-vscode"]
|
"recommendations": ["graphql.vscode-graphql", "oxc.oxc-vscode"],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fragment NodePage on Page {
|
||||||
|
title @nonNull
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { NodePageFragment } from "#graphql/types";
|
||||||
|
defineProps<{ node: NodePageFragment }>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="node-page">{{ node.title }}</div>
|
||||||
|
</template>
|
||||||
8
wp-content/themes/headless/app/pages/[...uri].gql
Normal file
8
wp-content/themes/headless/app/pages/[...uri].gql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
query NodeByUri($uri: String!) {
|
||||||
|
nodeByUri(uri: $uri) @nonNull {
|
||||||
|
__typename
|
||||||
|
... on Page {
|
||||||
|
...NodePage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,39 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Fetch node by URI and handle query errors
|
||||||
|
const { path: uri } = useRoute();
|
||||||
|
const { data: node, error } = await useAsyncGraphQLQuery(
|
||||||
|
"NodeByUri",
|
||||||
|
{ uri },
|
||||||
|
{
|
||||||
|
transform: ({ nodeByUri }) => nodeByUri,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Handle errors and missing nodes
|
||||||
|
if (!node.value) {
|
||||||
|
console.error("NodeByUri query error:", error.value);
|
||||||
|
throw createError({
|
||||||
|
statusCode: 404,
|
||||||
|
message: `La page demandée est introuvable: ${uri}`,
|
||||||
|
fatal: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dynamically resolve component based on node type
|
||||||
|
const componentName = `Node${node.value.__typename}`;
|
||||||
|
if (!useNuxtApp().vueApp.component(componentName)) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 404,
|
||||||
|
message: `La page demandée ne peut pas être affichée correctement: ${componentName}`,
|
||||||
|
fatal: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="page-node-from-uri">
|
<div id="page-node-from-uri">
|
||||||
<PageHeader title="TODO" />
|
<Component :is="componentName" :node="node" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
17
wp-content/themes/headless/graphql.config.json
Normal file
17
wp-content/themes/headless/graphql.config.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"schema": "./.nuxt/graphql/schema.graphql",
|
||||||
|
"documents": [
|
||||||
|
"./app/**/*.{gql,ts,vue}",
|
||||||
|
"./server/**/*.{gql,ts}",
|
||||||
|
"./shared/**/*.{gql,ts}"
|
||||||
|
],
|
||||||
|
"extensions": {
|
||||||
|
"codegen": {
|
||||||
|
"config": {
|
||||||
|
"scalars": {
|
||||||
|
"ZodValue": "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,36 @@
|
|||||||
|
// WordPress backend URL (required)
|
||||||
|
const wpUrl = process.env.NUXT_WP_URL;
|
||||||
|
if (!wpUrl) {
|
||||||
|
throw new Error("NUXT_WP_URL environment variable is not set");
|
||||||
|
}
|
||||||
|
console.log(`${wpUrl}/graphql`);
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
modules: ["@nuxt/ui", "nuxt-svgo"],
|
modules: ["@lewebsimple/nuxt-graphql", "@nuxt/ui", "nuxt-svgo"],
|
||||||
|
|
||||||
compatibilityDate: "2026-03-18",
|
compatibilityDate: "2026-03-18",
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
|
vite: {
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ["@vue/devtools-core", "@vue/devtools-kit", "zod"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
graphql: {
|
||||||
|
server: {
|
||||||
|
schema: [{ type: "remote", endpoint: `${wpUrl}/graphql` }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
ui: { colorMode: false },
|
ui: { colorMode: false },
|
||||||
css: ["~/assets/css/_main.css"],
|
css: ["~/assets/css/_main.css"],
|
||||||
components: { dirs: [{ path: "~/components", pathPrefix: false }] },
|
components: {
|
||||||
|
dirs: [
|
||||||
|
{ path: "~/components/nodes", global: true },
|
||||||
|
{ path: "~/components", pathPrefix: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
svgo: {
|
svgo: {
|
||||||
autoImportPath: "~/assets/svg/",
|
autoImportPath: "~/assets/svg/",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"release": "oxlint . && oxfmt --check . && nuxt typecheck && changelogen --noAuthors --release --push"
|
"release": "oxlint . && oxfmt --check . && nuxt typecheck && changelogen --noAuthors --release --push"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@lewebsimple/nuxt-graphql": "^0.7.5",
|
||||||
"@nuxt/ui": "^4.5.1",
|
"@nuxt/ui": "^4.5.1",
|
||||||
"nuxt": "^4.4.2",
|
"nuxt": "^4.4.2",
|
||||||
"nuxt-svgo": "^4.2.6",
|
"nuxt-svgo": "^4.2.6",
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
"vue-router": "^5.0.3"
|
"vue-router": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.5.0",
|
||||||
"changelogen": "^0.6.2",
|
"changelogen": "^0.6.2",
|
||||||
"oxfmt": "^0.41.0",
|
"oxfmt": "^0.41.0",
|
||||||
"oxlint": "^1.56.0",
|
"oxlint": "^1.56.0",
|
||||||
|
|||||||
1261
wp-content/themes/headless/pnpm-lock.yaml
generated
1261
wp-content/themes/headless/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user