Intégrer QForm Builder dans une application Nuxt 4 existante
Cette page s’adresse aux applications Nuxt 4 déjà en place : dashboard, portail admin, NFZ Studio, back-office ou extranet.
1. Ajouter le layer
Deux modes sont possibles.
Mode local
my-app/
├── app/
├── layers/
│ └── qform-builder/
└── nuxt.config.ts// nuxt.config.ts
export default defineNuxtConfig({
extends: ['./layers/qform-builder']
})Mode package npm
bun add @vevedh/qform-builder-layer \
nuxt-quasar-ui @pinia/nuxt @formkit/nuxt \
quasar @quasar/extras \
@formkit/core @formkit/i18n @formkit/vue @formkit/utils// nuxt.config.ts
export default defineNuxtConfig({
extends: ['@vevedh/qform-builder-layer']
})2. Vérifier les modules déjà présents
Le layer configure déjà :
nuxt-quasar-ui
@pinia/nuxt
@formkit/nuxtSi ton application utilise déjà Quasar, Pinia ou FormKit, vérifie que les versions sont compatibles et évite les doubles configurations contradictoires.
3. Attention au SSR
Le layer ne force plus ssr: false. Ce choix appartient à l’application hôte.
FormBuilder reste un composant fortement interactif : Quasar, drag and drop, window, document, localStorage, interactions souris/clavier. Dans une application SSR, utilise-le dans ClientOnly :
<ClientOnly>
<FormBuilder builder-id="admin-builder" />
</ClientOnly>FormViewer est plus proche du runtime, mais il faut tout de même valider les composants Quasar/FormKit utilisés selon ta stratégie SSR.
4. Page d’intégration recommandée
<!-- app/pages/admin/forms/[id].vue -->
<script setup lang="ts">
import type { FormKitSchemaDefinition } from '@formkit/core'
type FormBuilderSchema = FormKitSchemaDefinition[]
type FormBuilderValues = Record<string, unknown>
type FormDocument = {
id: string
name: string
schema: FormBuilderSchema
values: FormBuilderValues
updatedAt?: string
}
const route = useRoute()
const formId = computed(() => String(route.params.id || 'new'))
const builderId = computed(() => `admin-form-${formId.value}`)
const document = ref<FormDocument>({
id: formId.value,
name: 'Nouveau formulaire',
schema: [],
values: {}
})
function handleSave(payload: {
builderId: string
schema: FormBuilderSchema
values: FormBuilderValues
settings: Record<string, unknown>
}) {
document.value = {
...document.value,
schema: payload.schema,
values: payload.values,
updatedAt: new Date().toISOString()
}
// Remplacer ensuite par formsStore.save(document.value)
console.log('Document prêt à sauvegarder', document.value)
}
</script>
<template>
<ClientOnly>
<FormBuilder
:builder-id="builderId"
v-model:schema="document.schema"
v-model:values="document.values"
:title="document.name"
subtitle="Édition du formulaire métier"
autosave
@save="handleSave"
/>
</ClientOnly>
</template>5. Pattern conseillé pour une app existante
Évite de connecter directement le composant à l’API. Utilise cette séparation :
Page Nuxt
↓
Store métier Pinia
↓
Repository / composable API
↓
Service Feathers/NFZ ou endpoint existantExemple de découpage :
app/pages/admin/forms/[id].vue
app/stores/formsAdminStore.ts
app/composables/useFormsRepository.tsCe pattern permet de garder FormBuilder portable et de remplacer le backend sans toucher au composant.