Router-based layout plugin for Vite 7 and Vue 3.
npm install vite-plugin-vue-layouts-next
> Router based layout for Vue 3 applications using Vite
A fork of vite-plugin-vue-layouts with some improvements and fixes, supports Vite 7 and Vue 3.
This works best along with the vite-plugin-pages.
Layouts are stored in the /src/layouts folder by default and are standard Vue components with a in the template.
Pages without a layout specified use default.vue for their layout.
You can use route blocks to allow each page to determine its layout. The block below in a page will look for /src/layouts/users.vue for its layout.
``html`
meta:
layout: users
Install Layouts:
`bashnpm
npm install -D vite-plugin-vue-layouts-next
Add to your
vite.config.ts:`js
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import Pages from 'vite-plugin-pages'
import Layouts from 'vite-plugin-vue-layouts-next'export default defineConfig({
plugins: [Vue(), Pages(), Layouts()],
})
`In main.ts, you need to add a few lines to import the generated code and setup the layouts.
vue-router
`js
import { setupLayouts } from 'virtual:generated-layouts'
import { createRouter } from 'vue-router'
import generatedRoutes from '~pages'const routes = setupLayouts(generatedRoutes)
const router = createRouter({
// ...
routes,
})
`unplugin-vue-router
`js
import { setupLayouts } from 'virtual:generated-layouts'
import { createRouter } from 'vue-router'
import { routes } from 'vue-router/auto-routes'const router = createRouter({
// ...
routes: setupLayouts(routes),
})
`Client Types
If you want type definition of
virtual:generated-layouts, add vite-plugin-vue-layouts-next/client to compilerOptions.types of your tsconfig:`json
{
"compilerOptions": {
"types": ["vite-plugin-vue-layouts-next/client"]
}
}
`Configuration
`ts
interface UserOptions {
layoutsDirs?: string | string[]
pagesDirs?: string | string[] | null
extensions?: string[]
exclude?: string[]
defaultLayout?: string
importMode?: (name: string) => 'sync' | 'async'
inheritDefaultLayout?: boolean
}
`$3
To use custom configuration, pass your options to Layouts when instantiating the plugin:
`js
// vite.config.ts
import { defineConfig } from 'vite'
import Layouts from 'vite-plugin-vue-layouts-next'export default defineConfig({
plugins: [
Layouts({
layoutsDirs: 'src/mylayouts',
pagesDirs: 'src/pages',
defaultLayout: 'myDefault'
}),
],
})
`$3
Relative path to the layouts directory. Supports globs.
All .vue files in this folder are imported async into the generated code.
Can also be an array of layout dirs
Can use
to support scenarios like module1/layouts and modules2/layouts with a setting of src//layoutsAny files named
__*__.vue will be excluded, and you can specify any additional exclusions with the exclude optionDefault:
'src/layouts'$3
Defines the pages dir to avoid HMR reloading for all added or deleted files anywhere in the project.
Relative path to the pages directory. If you want it to watch for all files, like in v0.8.0 or earlier, set to null.
Can also be an array of layout dirs or use
** glob patternsDefault:
'src/pages'$3
Valid file extensions for page components.
Default:
['vue']$3
List of path globs to exclude when resolving pages.
$3
Filename of default layout (".vue" is not needed).
Default:
'default'$3
Mode for importing layouts.
Default: ssg is
'sync', other is 'async'$3
Whether nested routes should inherit the default layout from parent routes. When
false, if a child route has its own layout, the parent route won't use the default layout. This prevents double-wrapping layouts when child routes specify their own layout. This option only works with unplugin-vue-router. It has no effect when using vite-plugin-pages because vite-plugin-pages generates flat route structures without nested parent-child relationships, while unplugin-vue-router generates nested route structures with children arrays. This option can only be set globally in the plugin configuration.Default:
trueHow it works
setupLayouts transforms the original router by1. Replacing every page with its specified layout
2. Appending the original page in the
children property.Simply put, layouts are nested routes with the same path.
Before:
`text
router: [ page1, page2, page3 ]
`After
setupLayouts():`text
router: [
layoutA: page1,
layoutB: page2,
layoutA: page3,
]
`That means you have the full flexibility of the vue-router API at your disposal.
Common patterns
$3
Layouts and Transitions work as expected and explained in the vue-router docs only as long as
Component changes on each route. So if you want a transition between pages with the same layout and a different layout, you have to mutate :key on (for a detailed example, see the vue docs about transitions between elements).App.vue`html
`Now Vue will always trigger a transition if you change the route.
$3
If you want to send data down from the layout to the page, use props
`html
`$3
If you want to set state in your page and do something with it in your layout, add additional properties to a route's
meta property. Doing so only works if you know the state at build-time.You can use the
block if you work with vite-plugin-pages.In
page.vue:`html
Content
meta:
layout: default
bgColor: yellow
`Now you can read
bgColor in layout.vue:`html
">
`$3
If you need to set
bgColor dynamically at run-time, you can use custom events.Emit the event in
page.vue:`html
`Listen for
setColor custom-event in layout.vue:`html
">
`ClientSideLayout
The clientSideLayout uses a simpler virtual file + glob import scheme, This means that its hmr is faster and more accurate, but also more limited
$3
`js
// vite.config.ts
import { defineConfig } from 'vite'
import { ClientSideLayout } from 'vite-plugin-vue-layouts-next'export default defineConfig({
plugins: [
ClientSideLayout({
layoutsDir: 'src/mylayouts', // default to 'src/layouts'
defaultLayout: 'myDefault', // default to 'default', no need '.vue'
importMode: 'sync' // The default will automatically detect -> ssg is sync,other is async
}),
],
})
``