johncampionjr / vite-plugin-vue-layouts Goto Github PK
View Code? Open in Web Editor NEWVue layout plugin for Vite
License: MIT License
Vue layout plugin for Vite
License: MIT License
This is a really good plugin, but can I use this without vite-plugin-pages?
I have to try some way but doesn't get any conclusion about how to use this plugin without vite-plugin-pages, if you know it please let me know
Most of the cases, we use layout for a group of route placed in same folders. so is it possible to work with them like this to avoid use custom block
the new layout api is similar to dirs api
layouts: [
{ dir: "src/pages", layout: "src/layouts/default.vue" }, // this can be set by defualt .
{ dir: "src/features/**/pages", layout: "src/layouts/feature.vue" },
{ dir: "src/blank/pages", layout: "src/layouts/blank.vue" },
],
I'm running into issues with trying to get build-time router to be able to access the nested meta properties.
Part of that is an issue with vite-ssg
's handling of the router provided in ctx
, but it would be really nice and convenient to be able to elevate things (like in my case, the language for a dynamic route) to the top level so build-time code attaching to or modifying the top-level routes can have easy access to the meta properties.
Hi, would you please consider making vite-plugin-vue-layouts
compatible with vue2 as well?
https://github.com/hannoeru/vite-plugin-pages works fine with vite & vue2.
Adding layouts doesn't work though, as this
results in
The requested module does not provide an export named 'computed'
Any suggestions on how to tackle this?
Thanks for considering!
Since this plugin does support vue2, so maybe we should update peer dependency.
Or it will throw warning like this:
vite-plugin-vue-layouts@0
.3.1" has incorrect peer dependency "
vue@^3.0.11".
Thanks!
[email protected]" has incorrect peer dependency "vite@^2.5.0"
Steps to reproduce
In any project using the project in vite.config.js, set the projects type property to module
Expected Behavior
The default export should be the callable layoutPlugin()
function. Or (like @intlify/vite-plugin-vue-i18n does it) have a named export import {layoutPlugin} from 'vite-plugin-inspect'
Actual Behavior
The default export is
import Layout from 'vite-plugin-inspect';
({
default: [Function: layoutPlugin],
defaultImportMode: [Function: defaultImportMode]
})
Doing an import * as reveals:
import * as Layout from 'vite-plugin-inspect';
({
default: [Function: layoutPlugin],
defaultImportMode: [Function: defaultImportMode]
})
Possible Solutions
As mentioned, add an additional named export. Or, vite-plugin-inspect
fixed it by adding the exports
field to the package.json
{
"exports": {
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./*": "./*"
},
}
It looks like the .mjs
is already shipped, there's just no exports
listing for it.
I'm using pages/[...all].vue
to handle most of my top-level routes including /
by having only this catch-all file and no pages/index.vue
but it seems / will not match when vite-plugin-vue-layouts is enabled (it works just fine when I disable it)
I don't get any error in the console and I don't see any component in vue devtools where I normally see the page components (under RouterView).
Is this normal behaviour or am I missing something in the plugin options (I'm using none actually) ?
Can I use it like this
https://github.com/zhuhaobam/vtdd/blob/main/src/layouts/components/sidebar/index.vue
As mentioned at issue #119 of vitesse, vite-ssg
will generate unnecessary files.
Using path: ''
for children components in a nested router solves this (see docs)
With one caveat: when the router has a nested route before using setupLayouts()
. So we have to traverse the path ourselves.
I have the plugin set up with vite-plugin-pages
. Changing the template will trigger auto reload, but changing the style will not - in fact I must restart the server to see the css changes.
<template>
<div class="wrapper">
<h1>Change me</h1>
<RouterView />
</div>
</template>
<style scoped>
.wrapper {
color: green;
}
</style>
As far as I can tell, nested layouts don't seem to be possible. Is this something that could be possible in the future?
Hi,
I believe I found either a bug – or consider this a feature request. :)
I have an index.vue
page with a different layout than default.vue
. Let's say it uses start-layout.vue
. But, all my other pages in /pages
use default.vue
.
When I visit my entry point index.vue
in the browser, I would expect default.vue
's setup function not to run – alas, it does. That's a problem for side effects.
Avoid having a default.vue
in /layouts
. And configure each page to use a named layout. E.g. not-default.vue
.
Please see here: https://codesandbox.io/s/layout-bug-forked-q02kt. In the console, both layouts fire their respective logs.
A simple repro would be:
~/src/pages/hi
and call it index.vue
<template/>
with some demo contentnpm run dev
Observe how the dynamic route is being used instead of the newly created index route
Issue at vite-plugin-pages: hannoeru/vite-plugin-pages#23
Exemple here witht the bug branch :
see the code here:
https://github.com/riderx/vitesse-ionic/tree/bug
if you go to main branch you can see my work around in the App.vue
file.
i don't understand why it's duplicate the routing with router-view
in index.vue
if i use ion-router-outlet
liuke in hi
page you can see the css is broken
https://github.com/JohnCampionJr/vite-plugin-vue-layouts#getting-started
In the getting started section there is this section:
But it's very different from what is required for vite-plugin-pages
...
Check the readme here:
https://github.com/hannoeru/vite-plugin-pages#vue-1
It says:
Since this plugin is promoted as a companion to vite-plugin-pages
, could you add an example of how to integrate both syntaxes?
In nuxt we use layouts in options API in script block
{
layout: 'name'
}
I have a project migrated from nuxt to vite which contains a lot pages, if this plugin support nuxt like style, it will reduce a lot replace work for me.
Thanks a lot!
I am searching a way to define a layout for a whole group of pages. For example, a part of my site is a blog based en vite-pages and your plugin with pages written in markdown.
Having to put a <router></router>
block on every md file is quite tedious and not very logical.
I feel I am missing some way to define the default layout to be used for a route and its children.
Maybe I missed something in the documentation or maybe there is a simple way to make that happen.
I already tried to change the routes (router.getRoutes()
) on the fly by adding the need meta, but it had no effect. I presume the callback is too late in the chain.
Many thanks !
#9 mentions that vite-plugin-pages
now uses import routes from 'virtual:generated-pages'
Is this something we would want to have ourselves?
I don't know enough about rollup to understand if there is a benefit or if this is simply a convention. In the latter case, I think it looks nicer if we followed their example.
import { seputLayouts } from 'virtual:genreated-layouts'
import routes from 'virtual:generated-pages';
Using vitesse with
vite-plugin-pages: "^0.18.2"
vite-plugin-md: "0.11.4"
vite-plugin-vue-layouts: 0.5.0
When accessing the route inside a markdown file in an index route case (that has children in a folder with the same name), I get a list of two possible matches for said route. On of the matches is the layout file being used.
[
{
"path": "/test",
"meta": {},
"props": {
"default": false
},
"children": [
{
"path": "",
"children": [
{
"name": "test-test1",
"path": "test1",
"props": true
},
{
"name": "test-test2",
"path": "test2",
"props": true
}
],
"props": true
}
],
"instances": {
"default": {}
},
"leaveGuards": {
"Set(0)": []
},
"updateGuards": {
"Set(0)": []
},
"enterCallbacks": {},
"components": {
"default": {
"__hmrId": "39336072",
"__file": "E:/docs/src/layouts/default.vue"
}
}
},
{
"path": "/test",
"meta": {},
"props": {
"default": true
},
"children": [
{
"name": "test-test1",
"path": "test1",
"props": true
},
{
"name": "test-test2",
"path": "test2",
"props": true
}
],
"instances": {
"default": {
"frontmatter": {
"meta": []
}
}
},
"leaveGuards": {
"Set(0)": []
},
"updateGuards": {
"Set(0)": []
},
"enterCallbacks": {},
"components": {
"default": {
"__hmrId": "2ad13f07",
"__file": "E:/docs/src/pages/test.md"
}
}
}
]
In nuxt we use layouts in options API in script block
{
layout: 'name'
}
I have a project migrated from nuxt to vite which contains a lot pages, if this plugin support nuxt like style, it will reduce a lot replace work for me.
Thanks a lot!
If I'm not mistaken -- and maybe I am as I'm just getting to the implementation of this -- this plugin uses the router as the primary source to determine which layout to use and I can understand that this is indeed a useful pattern particularly as the "primary pattern" to manage layouts.
If, however, you want to change this at the individual page though it would be really nice if this were able to interact with the defacto Markdown meta format of Frontmatter. Because I've always paired this plugin with vite-plugin-pages
and vite-plugin-md
I always just assumed this would be there but I believe it is not.
To be clear, what I'd like to see is that when a markdown file has a layout
prop defined in Frontmatter it overrides the route based configuration.
---
title: My Post
layout: special
---
# Hello World
Am I just being a numpty and this is in fact supported? Is this something you've considered before? Would you consider?
Hello,
I installed vite-plugin-pages and vite-plugin-vue-layouts when I open "/" I got the error : Invalid route component
My sc/router/index.js:
import { createRouter, createWebHistory } from 'vue-router'
import { setupLayouts } from 'virtual:generated-layouts'
import generatedRoutes from 'virtual:generated-pages'
const routes = setupLayouts(generatedRoutes)
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
Dependencies:
"vite-plugin-pages": "^0.18.2",
"vite-plugin-vue-layouts": "^0.5.0",
"vue": "^3.2.16",
"vue-router": "^4.0.12",
"vuex": "^4.0.2"
Hey there,
I've just started experimenting with this plugin and was wondering if it's possible to create layouts with named slots rather than just returning a single router view, something like this?
Layout:
<template>
<slot name="header">
<slot name="content">
<slot name="sidebar">
</template>
Then in the actual page:
<template #header>...</template>
<template #content>...</template>
<template #sidebar>...</template>
These would need to be wrapped in a custom element, though.
Thanks!
Using vite-plugin-vue-layouts in the most vanilla way possible (using vite + vue-router v4) generates duplicated routes.
This repo reproduces the bug.
- git clone https://github.com/mzenz/vite-plugin-vue-layouts-duplicated-route-bug
- cd vite-plugin-vue-layouts-duplicated-route-bug
- yarn && yarn dev
Generated routes from setupLayouts()
should match the routes returned by router.getRoutes()
.
router.getRoutes()
shows duplicated routes for each generated route via setupLayouts()
.
Likely related to this issue but with a much more stripped-down reproduction to hopefully help with debugging. =)
I was thinking about issue #12 a bit more and while wondering about how a useLayout
would work best, I came to the conclusion that the minimum we could do, was to offer a section in the readme that tells users how to implement that functionality with common vue patterns.
That doesn't mean that I think useLayout
is a bad idea – It's just not a clear-cut advantage to offer easier APIs in a single plugin if we already have established patterns for the same functionality in the wider ecosystem.
Does #24 help a little to alleviate or is it still a rambling mess?
Looks like
import generatedRoutes from 'pages-generated'
//should be
import routes from 'virtual:generated-pages';
https://github.com/hannoeru/vite-plugin-pages
'virtual:generated-pages'
works fine for me.
Sometimes some pages need no layout ,like /login
+------------------+
| Login |
| |
+------------------+
But now there is always default layout
+------------------+
| Default |
| + -------------+ |
| | Login | |
+------------------+
To fix this, I rebuild it
// src/RouteLayout.ts - getClientCode
export function setupLayouts(routes) {
return routes.map(route => {
const isBoolean = typeof route.meta?.layout === 'boolean'
if(isBoolean && !route.meta?.layout) {
return route
} else {
let componentName = !isBoolean && route.meta?.layout ? route.meta?.layout : '${options.defaultLayout}'
return {
path: route.path,
component: layouts[componentName],
children: [ {...route, path: ''} ],
}
}
})
}
useage
<route lang="yaml">
meta:
layout: false
</route>
if the layout property is a boolean and false, no layout
if the layout property is not a boolean and type inference is true, use layout property as componentName
other, use default layout
On changing routes inside a vite app to a page that has a different layout the following happens:
The layout will change first, while still displaying the old page for a while. Only then the new page is loaded. This is especially apparent if you have a slow internet connection.
Clone this reproduction repo.
Install with: npm install
Run build script: npm run build
Serve preview: npm run serve
Open Chrome/FF devtools and choose throttle network. Open localhost:5000
and click on the link.
Observe how one line will change after the other.
A tentative fix could be this:
In your node_modules/vite-plugin-vue-layouts/dist/index.js
change from Line 72
Edit: this doesn't work for non-SSG content.
- router.beforeEach(async (to, from, next) => {
- await updateLayout(to.meta?.layout)
- next()
+ router.beforeResolve((to, from) => {
+ updateLayout(to.meta?.layout)
})
It'll be more flexible if we can pass any props to the layout component.
For example:
page.vue
<route lang="yaml">
meta:
layout: users
layoutProps:
showMenu: true
hideBreadcrumb: false
</route>
layout.vue
<template>
<div v-if='showMenu'>...</div>
<div v-if='hideBreadcrumb'>...</div>
</template>
<script>
export default {
props: {
showMenu: Boolean,
hideBreadcrumb: Boolean
}
}
</script>
or add a useLayout
api could even get more flexibility.
Hi. These errors only show up on build
.
Is there a way to bypass them?
The project runs fine in dev
node_modules/vite-plugin-vue-layouts/client.d.ts:3:19 - error TS7010: 'setupLayouts', which lacks return-type annotation, implicitly has an 'any' return type.
3 export function setupLayouts(routes: RouteRecordRaw[])
~~~~~~~~~~~~
node_modules/vite-plugin-vue-layouts/client.d.ts:8:19 - error TS7010: 'setupLayouts', which lacks return-type annotation, implicitly has an 'any' return type.
8 export function setupLayouts(routes: RouteRecordRaw[])
~~~~~~~~~~~~
node_modules/vite-plugin-vue-layouts/client.d.ts:9:19 - error TS7010: 'createRouterLayout', which lacks return-type annotation, implicitly has an 'any' return type.
9 export function createRouterLayout(
~~~~~~~~~~~~~~~~~~
node_modules/vite-plugin-vue-layouts/client.d.ts:10:46 - error TS2304: Cannot find name 'Component'.
10 resolve: (layoutName: string) => Promise<Component | { default: Component }>)
~~~~~~~~~
node_modules/vite-plugin-vue-layouts/client.d.ts:10:69 - error TS2304: Cannot find name 'Component'.
10 resolve: (layoutName: string) => Promise<Component | { default: Component }>)
I have been running into this issue while trying to setup vite-ssg
with vite-plugin-vue-layouts
. I have setup every according to the vite-ssg
spec to use with the layouts and pages plugins but have been unable to get a build to work. I am able to run fine in dev but haven't been able to build for production.
vite-plugin-vue-layouts
version: 0.6.0
// app.js
import generatedRoutes from 'virtual:generated-pages'
import { setupLayouts } from 'virtual:generated-layouts'
import { ViteSSG } from 'vite-ssg'
import App from './App.vue'
const routes = setupLayouts(generatedRoutes)
export const createApp = ViteSSG(
// the root component
App,
// vue-router options
{ routes },
// function to have custom setups
() => {
// install plugins etc.
}
)
Any help with this would be much appreciated.
Does anyone have a solution for proper interaction in phpstorm?
When formatting, the following happens:
<route lang="yaml">
meta:
layout: profile
</route>
If you do something like this, then everything is fine, but the functionality of the template does not work:
<route lang="yaml">
meta:
- layout: profile
</route>
Dir tree:
src/pages
├── posts
│ └── list
│ ├── index.vue
│ └── new
│ └── index.vue
The currently generated routes is:
{path: '/posts'},
{path: '/posts/new'}
So when I am on the /posts/new
page, the $route.matched
doesn't includes /posts
route.
Is there a way to have the child pages of a layout (aka the pages actually utilizing the layout) inherit the meta fields of the layout?
Say for example I create an authenticated.vue
layout that is only accessible if a token is present. The actual navigation guard logic is easily handled by vue router middleware, but I'd like to have the auth: true
meta field present in the main authenticated.vue
layout, with all pages utilizing it inheriting that (instead of having to set auth: true
on each page). Is that possible? The way I tried to do it, it doesn't seem like the page gets the layout's meta properties.
This is what I tried:
// layouts/authenticated.vue
<route lang="yaml">
meta:
auth: true
</route>
// pages/dashboard.vue
<route lang="yaml">
meta:
layout: admin
</route>
Thanks for the great plugin, but this commit: 6ddd49c
Seems to cause this error since the src folder is not included when I add vite-plugin-vue-layouts 0.3.0:
node_modules/.pnpm/[email protected][email protected]/node_modules/vite-plugin-vue-layouts: Running postinstall script, failed in 11.6s
.../node_modules/vite-plugin-vue-layouts postinstall$ npm update && npm run build
│ up to date, audited 415 packages in 10s
│ 80 packages are looking for funding
│ run `npm fund` for details
│ found 0 vulnerabilities
│ > [email protected] build
│ > tsup src/index.ts --dts --format cjs,esm
│ CLI tsup v4.10.1
│ Cannot find src/index.ts
The build output is in the npm package dist folder anyways, so I'm able to use the library despite this error
The layout doesn't render when I put top-level await inside <script setup>, is there an existing fix for this?
<script setup>
import { useStore } from 'vuex'
const store = useStore()
await store.dispatch('usercount')
</script>
<template>
<div>
<h1>Default Layout</h1>
<router-link to="/">index</router-link>|
<router-link to="/login">login</router-link>|
<router-link to="/register">register</router-link> |
<router-link to="/logout">logout</router-link>
<router-view></router-view>
</div>
</template>
I use prettier on the project, once it's applied content inside tag is getting destroyed.
<route lang="yaml">
meta:
layout: test
</route>
turns into
<route lang="yaml">
ium
lead
</route>
Could you help me understand how this can be mitigated? Should this part of the code always be put under prettier ignore?
After some investigation I found out that it's caused by the prettier plugin prettier-plugin-tailwind-css
, will also create an issue in their repo
Following the readme and adding this plugin results in an error when trying to start the vite dev server. Simply removing that last plugin call, and of course all code added to use it in other files and the server starts up fine again.
╰─ yarn vite-tauri dev ─╯
yarn run v1.22.11
$ vite-tauri dev
23:22:04 PM [vite-plugin-tauri] Starting Vite dev server...
failed to load config from /vite.config.ts
file:///vite.config.ts.js?t=1630466524160:15
Layouts({
^
TypeError: Layouts is not a function
at file:///vite.config.ts.js?t=1630466524160:15:5
at ModuleJob.run (node:internal/modules/esm/module_job:183:25)
at async Loader.import (node:internal/modules/esm/loader:178:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
at async loadConfigFromFile (/node_modules/vite/dist/node/chunks/dep-972722fa.js:75819:31)
at async resolveConfig (node_modules/vite/dist/node/chunks/dep-972722fa.js:75434:28)
at async createServer (node_modules/vite/dist/node/chunks/dep-972722fa.js:73957:20)
at async dev (node_modules/vite-plugin-tauri/bin/index.js:156:18)
at async node_modules/vite-plugin-tauri/bin/index.js:184:7
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
And for reference here are some files:
vite.config.ts
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import Pages from 'vite-plugin-pages'
import Layouts from 'vite-plugin-vue-layouts'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
plugins: [
Vue(),
Layouts({
layoutsDir: 'src/layouts'
}),
Pages({
exclude: ['**/components/*.vue'],
pagesDir: [
{ dir: 'src/pages', baseRoute: '' },
{ dir: 'src/features/**/pages', baseRoute: 'features' },
{ dir: 'src/admin/pages', baseRoute: 'admin' }
]
})
]
})
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"importHelpers": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"pretty": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom", "DOM.Iterable", "ScriptHost"],
"types": ["vite/client", "vite-plugin-vue-layouts/client", "vite-plugin-pages/client"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
Why i need this
export default defineConfig({
plugins: [
// https://github.com/hannoeru/vite-plugin-pages
Pages({
pagesDir: [
{ dir: 'src/pages', baseRoute: '' },
{ dir: 'src/dev/pages', baseRoute: 'dev' },
],
extendRoute(route) {
if (route.path.startsWith('/dev')) {
return {
...route,
meta: {
...route.meta,
layout: 'dev',
},
}
}
return {
...route,
meta: {
...route.meta,
layout: 'private',
},
}
},
}),
// https://github.com/JohnCampionJr/vite-plugin-vue-layouts
Layouts({
defaultLayout: 'public',
layoutsDir: 'src/{layouts,dev/layouts}',
}),
]
})
My teste using Glob Tester
<route lang="yaml">
meta:
layout: layout_name
</route>
console.log('Hi! Render Page!!')
in setup method of componentThis also heppen in the vitasse starter template
Posible related to #4
When using v0.6.0, layouts auto-refresh via HMR. When using v0.7.0 layouts only update after running "vite dev"
If I change any Tailwind classes such as "bg-yellow-500"; Tailwind does not update as it did in v0.6.0.
<template> <main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200"> <div class="mt-5 mx-auto text-center bg-yellow-500 text-white py-4"> [Home Layouts] </div> <RouterView /> <Footer /> </main> </template>
routes: setupLayouts(generatedRoutes),
scrollBehavior(to, from, savedPosition) {
return savedPosition;
}
browser back to previous page, scroll position not working
and console.log savedPosition is { top: 0, left: 0}
routes: generatedRoutes,
scrollBehavior(to, from, savedPosition) {
return savedPosition;
}
get savedPosition top, when back to previous page
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.