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, but can be used with any backend.
- π Component Preview Mode: Conditionally render components for previewing in isolation
- π Production Safe: Inactive by default, only activates when explicitly enabled
- π― Target Rendering: Render components to specific DOM elements using CSS selectors
- π§ͺ Testing Ready: Comprehensive test coverage and playground setup
Install the module to your Nuxt application:
npm install nuxt-component-preview
Add 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 server CORS
vite: {
server: {
cors: {
origin: ['https://your-backend.com'],
},
},
},
// Production: Nitro route rules
nitro: {
routeRules: {
'/nuxt-component-preview/*.js': {
cors: true,
headers: {
'Access-Control-Allow-Origin': 'https://your-backend.com',
},
},
'/_nuxt/**': {
cors: true,
headers: {
'Access-Control-Allow-Origin': 'https://your-backend.com',
},
},
},
},
})
To render a component preview, use the <ComponentPreviewArea />
component in your app.
Example app.vue
<template>
<ComponentPreviewArea v-if="useRuntimeConfig().public.componentPreview" />
<NuxtPage v-else />
</template>
The app-loader script automatically sets up everything needed for component preview:
<!DOCTYPE html>
<html>
<head>
<title>Component Preview</title>
<script src="http://localhost:3000/nuxt-component-preview/app-loader.js"></script>
</head>
<body>
<h1>Component Preview Page</h1>
<!-- Preview targets where components will render -->
<div id="preview-target-1"></div>
<div id="preview-target-2"></div>
<script>
// Helper function that handles both sync and async cases:
const onNuxtComponentPreviewReady = (callback) =>
window.__nuxtComponentPreviewApp
? callback(window.__nuxtComponentPreviewApp)
: window.addEventListener('nuxt-component-preview:ready', event => callback(event.detail.nuxtApp), { once: true })
// Example usage of the helper:
onNuxtComponentPreviewReady((nuxtApp) => {
nuxtApp.$previewComponent('MyComponent', { prop: 'value' }, {}, '#preview-target-1');
nuxtApp.$previewComponent('OtherComponent', { data: 123 }, {}, '#preview-target-2');
nuxtApp.$previewComponent('LayoutComponent', {}, { slot_name: '<p>HTML content for slot</p>' }, '#preview-target-3');
});
</script>
</body>
</html>
See playground/public/preview-test-loader.html for a working example.
Fired when the Nuxt app is ready for component preview:
window.addEventListener('nuxt-component-preview:ready', (event) => {
const { nuxtApp } = event.detail;
// Use nuxtApp.$previewComponent() here
});
For convenience, you can use this helper that works whether Nuxt is already ready or still loading:
const onNuxtComponentPreviewReady = (callback) =>
window.__nuxtComponentPreviewApp
? callback(window.__nuxtComponentPreviewApp)
: window.addEventListener('nuxt-component-preview:ready', event => callback(event.detail.nuxtApp), { once: true })
// Usage
onNuxtComponentPreviewReady((nuxtApp) => {
nuxtApp.$previewComponent('MyComponent', props, slots, '#target');
});
Renders a Vue component to a target element. Returns a Promise that resolves when rendering completes.
Parameters (in order):
- componentName (string): Name of the registered Vue component
- props (object, optional): Props to pass to the component (default:
{}
) - slots (object, optional): Slot content as HTML strings, keyed by slot name (default:
{}
) - targetSelector (string | Element): CSS selector or DOM element where component will be rendered
Returns: Promise<{unmount: Function}>
// Simple component
await nuxtApp.$previewComponent('TestCard', { title: 'My Card' }, {}, '#preview-target');
// Component with slots
await nuxtApp.$previewComponent(
'TwoColumnLayout',
{ width: 33 },
{
'column-one': '<h3>First Column</h3><p>Content</p>',
'column-two': '<h3>Second Column</h3><p>Content</p>'
},
'#preview-target'
);
Nested Components: Slots can contain additional preview containers. An example implementing rendering with an
arbitrary depth can be found at the example, which can be tested via npm run dev
.
This module includes comprehensive tests. To run them:
npm run test
Run command
npm run release -- --release-as 1.0.0-alpha.1
This module is maintained by drunomics and inspired by the needs of decoupled Drupal projects, such as nuxtjs-drupal-ce.