Skip to content

Future evolution toward a Nuxt 4 module

The current phase publishes QForm Builder as a Nuxt Layer npm package.

The next natural step is to create a real Nuxt 4 module:

txt
@vevedh/nuxt-qform-builder

Difference between layer and module

TopicNuxt LayerNuxt Module
Fast publicationexcellentmedium
Explicit optionslimitedexcellent
Runtime registrationimplicitcontrolled
Host app pollution riskmediumlow
Long-term product packaginggoodexcellent

Why not convert immediately?

The current project already works as a layer. Converting too early would add complexity before the public component contract is fully stabilized.

Target module structure

txt
nuxt-qform-builder/
├── src/
│   ├── module.ts
│   └── runtime/
│       ├── components/
│       ├── composables/
│       ├── constants/
│       ├── stores/
│       ├── types/
│       └── utils/
├── playground/
├── docs/
└── package.json

Target options

ts
export default defineNuxtConfig({
  modules: ['@vevedh/nuxt-qform-builder'],

  qformBuilder: {
    prefix: '',
    installPinia: true,
    installFormKit: true,
    installQuasar: true,
    injectCss: true,
  },
})

Target module.ts example

ts
import {
  addComponentsDir,
  addImportsDir,
  createResolver,
  defineNuxtModule,
  installModule,
} from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    name: '@vevedh/nuxt-qform-builder',
    configKey: 'qformBuilder',
  },
  defaults: {
    prefix: '',
    installPinia: true,
    installFormKit: true,
    installQuasar: true,
    injectCss: true,
  },
  async setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    if (options.installPinia) await installModule('@pinia/nuxt')
    if (options.installFormKit) await installModule('@formkit/nuxt')
    if (options.installQuasar) await installModule('nuxt-quasar-ui')

    addComponentsDir({
      path: resolver.resolve('./runtime/components'),
      prefix: options.prefix,
      pathPrefix: false,
      global: true,
    })

    addImportsDir(resolver.resolve('./runtime/composables'))
    addImportsDir(resolver.resolve('./runtime/stores'))

    if (options.injectCss) {
      nuxt.options.css.push(resolver.resolve('./runtime/assets/scss/index.scss'))
    }
  },
})

Refactors required before the module

1. Stabilize internal imports

Avoid host-app aliases such as ~/... in published runtime code. Prefer relative imports or module-specific aliases.

Potential future aliases:

txt
#qform-builder/types
#qform-builder/runtime

2. Export public types

The public type contract must remain stable:

ts
import type { FormBuilderSchema } from '@vevedh/qform-builder-layer/types'

3. Make the catalog extensible

The future module should allow custom fields, panels and groups.

4. Separate builder and viewer

A future host app should be able to install only the viewer if it does not need the visual builder.

Module roadmap

Phase M1 — minimal module packaging

Move runtime code under src/runtime and register components with Nuxt Kit.

Phase M2 — configurable options

Add options for prefix, Quasar installation, FormKit installation, CSS injection and component groups.

Phase M3 — Vueform Builder parity

Add advanced conditions, validation, templates, theme builder and extensibility points.

Convention to keep

The Community layer remains the stable base. Pro and Studio features should be delivered as separate packages.

QForm Builder — reusable Nuxt 4 / Quasar / FormKit layer.