A Nuxt module by drunomics for previewing Vue components in external contexts (like iframes or separate HTML pages). Originally developed for use with decoupled Drupal environments like Lupus Decoupled Drupal, but can be used with any backend.
- 🎭 Component Preview Mode: Render components in isolation via Vue Teleport — embed previews in iframes or external pages
- 🚀 Production Safe: Inactive by default, only activates when explicitly enabled
- 📋 Component Index: Auto-generates JSON metadata for global components from TypeScript props and JSDoc annotations
- 🔌 Framework Agnostic: Works with any backend. Built-in support for Drupal Canvas via canvas_extjs
Install the module to your Nuxt application:
npm install nuxt-component-previewAdd it to your nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'nuxt-component-preview',
]
})When embedding component previews on a different domain, disable the app manifest in development mode only:
export default defineNuxtConfig({
modules: [
'nuxt-component-preview',
],
// Disable appManifest in development only
$development: {
experimental: {
appManifest: false
}
}
})Why? In dev mode, Nuxt's appManifest feature (default since v3.8) tries to fetch metadata using relative URLs that fail in cross-domain contexts. Production builds work fine with appManifest enabled. Since component preview doesn't require this feature, it's safe to disable in development.
For cross-origin embedding, configure CORS in your Nuxt app:
export default defineNuxtConfig({
// Development: Vite dev server CORS
vite: {
server: {
cors: {
origin: ['https://your-backend.com'],
},
},
},
// SSR production: Nitro route rules for CORS headers
nitro: {
routeRules: {
'/**': {
headers: {
'Access-Control-Allow-Origin': 'https://your-backend.com',
'Access-Control-Allow-Methods': 'GET',
},
},
},
},
})Note: When using nuxtjs-drupal-ce, CORS is configured automatically based on
drupalCe.drupalBaseUrl— no manual setup needed.
SSG: For static builds, Nitro route rules have no effect since there is no server. CORS headers must be configured on the web server or CDN serving the static files.
When Nuxt runs behind a reverse proxy, be sure to configure the Nuxt CDN URL so component preview generates correct absolute URLs for loading assets:
export NUXT_APP_CDN_URL=https://your-frontend-url.comFor static builds (nuxt generate), configuring app.cdnURL is recommended when assets are served from a different domain than the embedding page.
Add the <ComponentPreviewArea /> to your app.vue so previews render when preview mode is active:
<template>
<ComponentPreviewArea v-if="useRuntimeConfig().public.componentPreview" />
<NuxtPage v-else />
</template>For embedding previews in external pages (e.g., Drupal Canvas editor), see the App Loader documentation.
This module automatically generates a component index JSON file containing metadata for all global components. This is particularly useful for integration with Drupal Canvas External JS module.
Components must be global (registered with global: true in Nuxt — components in components/global/ are automatically global). Use TypeScript with JSDoc annotations for best metadata extraction.
The component index is available at:
http://localhost:3000/nuxt-component-preview/component-index.json
export default defineNuxtConfig({
modules: ['nuxt-component-preview'],
componentPreview: {
componentIndex: {
enabled: true, // default: true
// Category from directory structure (e.g., Canvas/Layout/ → "Layout")
category: { directory: true, fallback: 'Misc' },
// Or use a static string:
// category: 'Nuxt Components',
// Exclude components (overwrites defaults)
exclude: {
components: ['*--default'], // default: excludes *--default pattern
directories: [] // exclude by directory pattern
},
// Package filtering for component index (default: false = exclude all packages)
includePackages: false, // Exclude all package components from node_modules
// includePackages: true, // Include all package components (not recommended)
// includePackages: ['my-package'], // Include only components from specific packages
// Override metadata for specific components
overrides: {
TestButton: { name: 'Custom Button', description: 'A button', category: 'Forms', status: 'experimental' }
}
}
}
})The includePackages option controls which npm package components are included in the component index:
false(default): No components from node_modules packages are processedtrue: All package components are processed (may cause warnings for incompatible packages)['package-name', '@org/package']: Only components from specified packages are processed
Only affects components registered globally by Nuxt from npm packages.
Note: Only globally registered components appear in the component index. Components in
components/global/are automatically global, or register withglobal: trueinnuxt.config.ts.
Define name, description, category, and status for a component via a JSDoc comment at the top of <script setup>:
<script setup lang="ts">
/**
* Hero Billboard
* @description A full-width hero section with background image and overlay.
* @category Hero
* @status stable
*/
withDefaults(defineProps<{
// ... props
}>(), {
// ... defaults
})
</script>- First line → custom display name (optional, falls back to auto-generated from PascalCase)
@description→ component description shown in the editor@category→ category override (alternative to directory-based or config-based)@status→ status override (experimental,stable,deprecated,obsolete)
All fields are optional. Config overrides take priority over JSDoc.
<script setup lang="ts">
withDefaults(defineProps<{
/**
* Button label text
* @example Submit
* @example Cancel
*/
label?: string
/**
* Button variant
* @example primary
* @enumLabels {"large": "Extra Large (XL)"}
*/
variant?: 'primary' | 'secondary' | 'large'
}>(), {
label: 'Click me',
variant: 'primary'
})
</script>Supported prop JSDoc tags:
@title- Explicit prop title override@example- Adds toexamplesfield@enumLabels- Custom labels formeta:enum(full or partial)@contentMediaType text/html- For string props: enables rich text editing in Canvas@formattingContext block|inline- Controls formatting (default:block)@schemaRef- Reference Canvas JSON schema definitions (see below)@format- JSON Schema format for semantic string validation and UI widgets (e.g., date picker). Supported:date,date-time,time,duration,email,idn-email,hostname,idn-hostname,ipv4,ipv6,uuid,uri,uri-reference,iri,iri-reference@pattern- JSON Schema regex pattern for string validation (e.g.,(.|\r?\n)*for multiline/textarea)@allowed-schemes- Allowed URI schemes for Canvas field type determination (e.g.,publicorhttp, https)
Prop titles are auto-generated from the first line of JSDoc or prop name. Use @title to override.
See TestArticle.vue for formatted text examples.
For Drupal Canvas integration, special prop types generate JSON schema matching Canvas JSON-Schema definitions, enabling UI features like media library selection. See Canvas prop types documentation for details.
Available TypeScript types (auto-imported by Nuxt):
CanvasImage- Image with media library integrationCanvasVideo- Video with poster support
@example formats for Canvas types:
- Key-value:
src=https://... alt="text" width=800 height=600 - JS object:
{ src: 'https://...', alt: 'text', width: 800 }
See TestHero.vue and TestBanner.vue for usage examples.
Schema references via @schemaRef allow referencing Canvas JSON schema definitions, useful for stream-wrapper-uri and stream-wrapper-image-uri types. Use shorthand prefix/name notation (e.g., canvas/stream-wrapper-uri expands to json-schema-definitions://canvas.module/stream-wrapper-uri). See TestStreamWrapper.vue for examples.
This module includes comprehensive tests. To run them:
npm run test- Update the version in
package.json - Run
npm run lint && npm run test && npm run prepack - Commit, tag, and push:
git commit -am "release: vX.Y.Z" && git tag vX.Y.Z && git push --follow-tags - Publish:
npm publish --tag beta - Ensure the
latestdist-tag points to the new version:npm dist-tag add nuxt-component-preview@X.Y.Z latest
This module is maintained by drunomics and inspired by the needs of decoupled Drupal projects, such as nuxtjs-drupal-ce.