<style> section { text-align: left; font-size: 22px; } code { font-size: 16px; } </style> # Directus, un CMS Headless > [name=Philippe Depouilly] > Institut de Mathématiques de Bordeaux > Journées Mathrice > XLIM Limoges 2025 --- # En quelques mots - un CMS Headless - découplage backend/frontend - correspondance Modèle de données <-> APIs - modèle relationnel de la forme ManyToOne, OneToMany, ManyToMany (ORM) - bibliothèques Javascript intégrées et riches - fonctionne aussi bien avec Mysql, Postgresql, etc. - un backend complet et fortement customisable --- ## Installer Directus ### Création du projet ``` bash oc login --web https://api.math.cnrs.fr:6443 oc new-project directus-journees ``` --- ### Déploiement de Directus ``` bash helm repo add directus https://directus-labs.github.io/helm-chart/ helm repo update ``` ``` yaml adminEmail: pdepouil@math.u-bordeaux.fr extraVolumeMounts: - mountPath: /.pm2 name: pm2 extraVolumes: - emptyDir: {} name: pm2 # Pour le développement extraEnvVars: - name: CORS_ENABLED value: 'true' - name: CORS_ORIGIN value: 'http://localhost:3000' ingress: enabled: true className: openshift-default annotations: route.openshift.io/termination: edge hosts: - host: directus-journees.apps.math.cnrs.fr paths: - path: / pathType: Prefix ``` ``` bash helm install directus directus/directus -f values.yaml ``` --- ### Directus : tour du propriétaire Récupération du mot de passe ``` bash oc get secret directus-application-secret -o jsonpath="{.data.ADMIN_PASSWORD}"|base64 -d ``` Et hop... https://directus-journees.apps.math.cnrs.fr Créer un premier modèle `global` avec les champs `title` et `description` et le rendre public --- ## NuxtJS ``` bash $ npx nuxt init my-website $ cd my-website $ npm install $ npm install nuxt-directus ``` nuxt.config.ts : ``` javascript // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2025-05-15', devtools: { enabled: true }, + modules: ["nuxt-directus"], + directus: { + url: "https://directus-journees.apps.math.cnrs.fr/" + }, }) ``` --- app.vue : ``` javascript <template> <div> <NuxtRouteAnnouncer /> - <NuxtWelcome /> + <NuxtPage /> </div> </template> ``` --- ### Première page pages/index.vue ``` javascript <template> <h1>{{global.title}}</h1> <p>{{global.description}}</p> </template> <script setup lang="ts"> const { getSingletonItem } = useDirectusItems(); interface Global { title: string; description: string; } const global = await getSingletonItem<Global>({ collection: "global" }); </script> ``` --- ### Test sur le poste de travail ``` bash npm run dev ``` sur http://localhost:3000 --- ### Ajouter des pages sur le Blog Dans Directus ajouter un model pages avec les champs `slug`, `title` et `content`, le rendre public pages/[slug].vue : ``` javascript <template> <h1>{{page.title}}</h1> <div>{{page.content}}</div> </template> <script setup lang="ts"> const { getItemById } = useDirectusItems(); const route = useRoute() interface Page { slug: string; title: string; content: string; } const page = await getItemById <Page>({ collection: "pages", id: route.params.slug }); if (!page.content) throw createError({ statusCode: 404, statusMessage: 'Page Not Found' }) </script> ``` --- Importer les Pages depuis un CSV et tester : http://localhost:3000/about --- ### Ajouter des nouvelles dans le Blog Créer un modèle `authors` public avec un champ `name` Créer un modèle `blogs` public avec les champs `slug`, `title`, `content`, `image`, `publish_date` et une relation one-to-many de `author `vers `authors` --- Dans pages/blog/index.vue ``` ruby <template> <h1>Blog</h1> <ul> <template v-for="post in posts" :key="post.id"> <li> <NuxtLink :href="`/blog/${post.slug}`"> <h2>{{post.title}}</h2> </NuxtLink> <span>{{post.publish_date}} &bull; {{post.author.name}}</span> </li> </template> </ul> </template> <script setup lang="ts"> const { getItems } = useDirectusItems(); interface Post { slug: string; title: string; publish_date: string; name: string; } const fields = [ 'slug', 'title', 'publish_date', 'author.name', ] const posts = await getItems <Post>({ collection: "blogs", params: { fields: fields, sort: ['-publish_date'] } }); </script> ``` --- Puis une affichage par Post dans pages/blog/\[slug\].vue ```javascript= <template> <h1>{{post.title}}</h1> <div>{{post.content}}</div> </template> <script setup lang="ts"> const { getItemById } = useDirectusItems(); const route = useRoute() interface Post { slug: string; title: string; content: string; } const post = await getItemById <Post>({ collection: "blogs", id: route.params.slug }); if (!post.content) throw createError({ statusCode: 404, statusMessage: 'Post Not Found' }) </script> ``` --- Importer les Pages depuis un CSV et tester : http://localhost:3000/blog --- Et enfin un menu dans app.vue ```javascript= <template> <div> <NuxtRouteAnnouncer /> <nav> <NuxtLink to="/">Home </NuxtLink> - <NuxtLink to="/about"> About </NuxtLink> - <NuxtLink to="/conduct"> Code of Conduct </NuxtLink> - <NuxtLink to="/privacy"> Privacy Policy</NuxtLink> - <NuxtLink to="/blog"> Blog</NuxtLink> </nav> <NuxtPage /> </div> </template> ``` --- ## Déploiement de Nuxt sur PLMshift ``` bash git push --set-upstream git@plmlab.math.cnrs.fr:philippe.depouilly/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD) ``` Mettre le dépôt public afin de le déployer sur PLMshift : ``` bash oc new-app nodejs:20-ubi9-minimal -e NPM_RUN=dev -e NUXT_PORT=8080 -e NUXT_HOST=0.0.0.0 https://plmlab.math.cnrs.fr/philippe.depouilly/my-website.git ``` ``` bash oc create route edge --service=my-website --hostname=nuxt-journees.apps.math.cnrs.fr ``` --- ### Modification Directus ``` javascript adminEmail: pdepouil@math.u-bordeaux.fr extraVolumeMounts: - mountPath: /.pm2 name: pm2 extraVolumes: - emptyDir: {} name: pm2 # Pour la prod extraEnvVars: - name: CORS_ENABLED value: 'true' - name: CORS_ORIGIN value: 'https://nuxt-journees.apps.math.cnrs.fr ingress: enabled: true className: openshift-default annotations: route.openshift.io/termination: edge hosts: - host: directus-journees.apps.math.cnrs.fr paths: - path: / pathType: Prefix ``` Puis ajouter un Webhook gitlab Il est maintenant possible de développer depuis le dépôt Git et le site se met à jour... --- Ce qui n'a pas été abordé: - l'authentification - l'écriture createItem, deleteItem, etc. - le stockage de fichiers (upload de medias) - le templating des formulaires Directus - etc. --- Références - https://directus.io - https://directus.io/docs/tutorials/getting-started/fetch-data-from-directus-with-nuxt - https://docs.directus.io/blog/nuxt-directus-getting-started.html
{"type":"slide","slideOptions":{"theme":"solarized","transition":"fade","controls":true}}