Vite Plugin
The vueWswgEditorPlugin is a Vite plugin that automatically discovers blocks, layouts, and fields from your project structure. It creates virtual modules that the library uses internally to load your components.
Overview
The plugin scans your project directory structure and creates virtual modules that expose:
- Layout components - All
.vuefiles inlayout/ - Block components - All
.vuefiles inblocks/ - Field definitions - All
fields.tsfiles inblocks/ - Block thumbnails - All
thumbnail.pngfiles inblocks/
These virtual modules are automatically populated based on your file structure, eliminating the need for manual registration.
Installation
The plugin is included with vue-wswg-editor. Import it from the package:
import { vueWswgEditorPlugin } from "vue-wswg-editor/vite-plugin";Configuration
Add the plugin to your vite.config.ts:
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { fileURLToPath } from "url";
import { vueWswgEditorPlugin } from "vue-wswg-editor/vite-plugin";
export default defineConfig({
plugins: [
vue(),
vueWswgEditorPlugin({
rootDir: "@page-builder", // Path alias to your page-builder directory
}),
],
resolve: {
alias: {
"@page-builder": fileURLToPath(new URL("./src/page-builder", import.meta.url)),
},
},
});Plugin Options
The plugin accepts the following options:
interface VueWswgEditorPluginOptions {
/**
* Root directory path (can use Vite aliases like "@page-builder")
* Example: "@/features/homepage" or "@page-builder"
*/
rootDir: string;
/**
* Array of module types to skip loading.
* Skipped modules will return an empty object, preventing Vite from scanning those files.
* This can improve build performance when certain features are not needed.
*/
skipModules?: SkipableModule[];
}
type SkipableModule = "fields" | "thumbnails";Using Path Aliases
The rootDir option supports Vite path aliases. This is recommended as it makes your configuration more maintainable:
// vite.config.ts
export default defineConfig({
plugins: [
vueWswgEditorPlugin({
rootDir: "@page-builder", // Use alias
}),
],
resolve: {
alias: {
"@page-builder": fileURLToPath(new URL("./src/page-builder", import.meta.url)),
},
},
});Using Relative Paths
You can also use relative paths, though aliases are preferred:
// vite.config.ts
export default defineConfig({
plugins: [
vueWswgEditorPlugin({
rootDir: "./src/page-builder", // Relative path
}),
],
});Using Absolute Paths
Absolute paths work as well:
import path from "path";
export default defineConfig({
plugins: [
vueWswgEditorPlugin({
rootDir: path.resolve(__dirname, "./src/page-builder"), // Absolute path
}),
],
});Skipping Modules
The skipModules option allows you to skip loading specific module types, which prevents Vite from scanning files that don't exist or aren't needed in your project. Currently, you can skip:
"fields"- Skip loading field definition files (fields.ts)"thumbnails"- Skip loading block thumbnail images
When a module is skipped, it returns an empty object instead of scanning files with import.meta.glob, preventing Vite from processing those files during the build.
Separate Editor and PageRenderer Projects
If you have separate projects where the editor (admin/client portal) and the pageRenderer (front-facing website) are in different codebases, you should skip fields and thumbnails in your pageRenderer project.
Why? Field definitions and thumbnails are only needed in the editor for configuration and UI purposes. The pageRenderer only needs blocks and layouts to render pages - it doesn't need field definitions or thumbnails. By skipping these modules, you avoid import errors when these project-specific dependencies don't exist in the pageRenderer project.
Project Structure:
monorepo/
├── admin/ # Editor project (admin/client portal)
│ └── Uses: blocks, layouts, fields, thumbnails
└── website/ # PageRenderer project (front-facing site)
└── Uses: blocks, layouts only
└── Should skip: fields, thumbnailsExample for PageRenderer Project:
// vite.config.ts (in your pageRenderer/website project)
export default defineConfig({
plugins: [
vue(),
vueWswgEditorPlugin({
rootDir: "@page-builder",
skipModules: ["fields", "thumbnails"], // Skip editor-only modules
}),
],
resolve: {
alias: {
"@page-builder": fileURLToPath(new URL("./src/page-builder", import.meta.url)),
},
},
});Other Use Cases:
- Skip fields: If your blocks don't use field definitions or you're loading them dynamically
- Skip thumbnails: If you don't need thumbnail images in the editor UI
Note: Skipping modules means those features won't be available at runtime. For example, if you skip "fields", the editor won't be able to load field configurations for blocks. Only skip modules if you're certain they're not needed.
How It Works
The plugin creates four virtual modules that are automatically populated:
Virtual Modules
vue-wswg-editor:blocks- All block components- Scans:
{rootDir}/blocks/**/*.vue - Used by the library to discover and load block components
- Scans:
vue-wswg-editor:layouts- All layout components- Scans:
{rootDir}/layout/**/*.vue - Used by the library to discover and load layout components
- Scans:
vue-wswg-editor:fields- All field definition files- Scans:
{rootDir}/blocks/**/fields.ts - Used by the library to load field configurations for blocks
- Scans:
vue-wswg-editor:thumbnails- Block thumbnail images- Scans:
{rootDir}/blocks/**/thumbnail.png - Used by the library to display block thumbnails in the editor
- Scans:
Internal Implementation
The plugin uses Vite's import.meta.glob to scan your directory structure:
// Generated virtual module code (simplified)
export const modules = import.meta.glob("@page-builder/blocks/**/*.vue", { eager: true });The library then processes these modules to build the registry of available blocks, layouts, and fields.
Directory Structure Requirements
The plugin expects a specific directory structure. The blocks/ and layout/ subdirectories are required and cannot be changed:
{rootDir}/
blocks/ # Block components (required - cannot be renamed)
{blockName}/ # Block directory (kebab-case)
{BlockName}.vue # Block component (PascalCase)
fields.ts # Field definitions (optional)
thumbnail.png # Block thumbnail (optional)
layout/ # Layout components (required - cannot be renamed)
{layoutName}.vue # Layout component (kebab-case)Important: While you can change the location of rootDir (the page-builder directory), the internal structure with blocks/ and layout/ subdirectories is fixed and cannot be customized.
Example Structure
src/
page-builder/
blocks/
hero-section/
HeroSection.vue
fields.ts
thumbnail.png
divider/
Divider.vue
layout/
default.vue
marketing.vuePlugin Behavior
Execution Order
The plugin runs with enforce: "pre", meaning it executes before other Vite plugins. This ensures:
- Virtual modules are resolved before other plugins try to process them
import.meta.globis processed correctly- The library's dependency optimization works correctly
Dependency Optimization
The plugin automatically configures Vite's dependency optimization to:
- Exclude
vue-wswg-editorfrom optimization - Mark virtual modules as external during esbuild optimization
- Prevent esbuild from trying to resolve virtual modules prematurely
This ensures the plugin works correctly with Vite's build system.
Examples
Basic Setup
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { fileURLToPath } from "url";
import { vueWswgEditorPlugin } from "vue-wswg-editor/vite-plugin";
export default defineConfig({
plugins: [
vue(),
vueWswgEditorPlugin({
rootDir: "@page-builder",
}),
],
resolve: {
alias: {
"@page-builder": fileURLToPath(new URL("./src/page-builder", import.meta.url)),
},
},
});Monorepo Setup
In a monorepo, you might have multiple page builders:
// vite.config.ts
export default defineConfig({
plugins: [
vue(),
vueWswgEditorPlugin({
rootDir: "@features/homepage/page-builder",
}),
],
resolve: {
alias: {
"@features": fileURLToPath(new URL("./src/features", import.meta.url)),
},
},
});Custom Page-Builder Location
Experimental
Using a custom location for the page-builder directory (different from the standard ./src/page-builder/) is supported but experimental. The internal structure (blocks/ and layout/ subdirectories) cannot be changed.
If your page-builder directory is in a different location:
// vite.config.ts
export default defineConfig({
plugins: [
vue(),
vueWswgEditorPlugin({
rootDir: "@/app/example-directory", // Custom page-builder location
}),
],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});Important: The rootDir must still contain blocks/ and layout/ subdirectories. For example:
@/app/example-directory/blocks/✅@/app/example-directory/layout/✅@/app/example-directory/components/❌ (not supported)
Troubleshooting
Blocks or Layouts Not Found
If blocks or layouts aren't being discovered:
- Check the directory structure - Ensure your files match the expected structure
- Verify the
rootDirpath - Make sure it points to the correct directory - Check file naming - Block components should match directory names (e.g.,
hero-section/HeroSection.vue) - Restart the dev server - Vite may need a restart to pick up plugin changes
Virtual Module Errors
If you see errors about virtual modules:
- Ensure the plugin is configured - The plugin must be added to your Vite config
- Check plugin order - The plugin should run before other plugins (it uses
enforce: "pre") - Verify path aliases - If using aliases, ensure they're configured in
resolve.alias
Build Errors
If builds fail:
- Check for missing files - Ensure all referenced files exist
- Verify TypeScript types - Make sure your components have proper type definitions
- Check console output - Look for specific error messages about missing modules
Advanced Usage
Custom File Patterns
The plugin uses fixed glob patterns:
{rootDir}/blocks/**/*.vuefor block components{rootDir}/layout/**/*.vuefor layout components{rootDir}/blocks/**/fields.tsfor field definitions{rootDir}/blocks/**/thumbnail.pngfor thumbnails
These patterns cannot be customized. The blocks/ and layout/ subdirectory names are required and cannot be changed.
Development vs Production
The plugin works identically in development and production builds. Virtual modules are resolved at build time, so there's no runtime overhead.
Hot Module Replacement (HMR)
The plugin supports HMR - when you add, remove, or modify blocks, layouts, or fields, the changes are automatically reflected in the editor without restarting the dev server.
See Also
- Blocks Guide - Learn about creating blocks
- Layouts Guide - Learn about creating layouts
- Fields Guide - Learn about defining fields
- Quick Start Guide - Get started with the library