Giter Club home page Giter Club logo

vite-plugin-vue-layouts's Introduction

vite-plugin-vue-layouts

npm version

Router based layout for Vue 3 applications using Vite

Overview

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 <router-view></router-view> 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.

See the Vitesse starter template for a working example.

<route lang="yaml">
meta:
  layout: users
</route>

Getting Started

Install Layouts:

$ npm install -D vite-plugin-vue-layouts

Add to your vite.config.js:

import Vue from '@vitejs/plugin-vue';
import Pages from 'vite-plugin-pages';
import Layouts from 'vite-plugin-vue-layouts';

export default {
  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

import { createRouter } from 'vue-router'
import { setupLayouts } from 'virtual:generated-layouts'
import generatedRoutes from '~pages'

const routes = setupLayouts(generatedRoutes)

const router = createRouter({
  // ...
  routes,
});
import { createRouter } from 'vue-router/auto'
import { setupLayouts } from 'virtual:generated-layouts'

const router = createRouter({
  // ...
  extendRoutes: (routes) => setupLayouts(routes),
})

Client Types

If you want type definition of virtual:generated-layouts, add vite-plugin-vue-layouts/client to compilerOptions.types of your tsconfig:

{
  "compilerOptions": {
    "types": ["vite-plugin-vue-layouts/client"]
  }
}

Configuration

interface UserOptions {
  layoutsDirs?: string | string[]
  pagesDir?: string
  exclude: string[]
  defaultLayout?: string
}

Using configuration

To use custom configuration, pass your options to Layouts when instantiating the plugin:

// vite.config.js
import Layouts from 'vite-plugin-vue-layouts';

export default {
  plugins: [
    Layouts({
      layoutsDirs: 'src/mylayouts',
      pagesDir: 'src/pages',
      defaultLayout: 'myDefault'
    }),
  ],
};

layoutsDirs

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/**/layouts

Any files named __*__.vue will be excluded, and you can specify any additional exclusions with the exclude option

Default: 'src/layouts'

pagesDir

Defines the pages dir to avoid HMR reloading for all added or deleted files anywhere in the projet.

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 patterns

Default: 'src/pages'

How it works

setupLayouts transforms the original router by

  1. 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:

router: [ page1, page2, page3 ]

After setupLayouts():

router: [
  layoutA: page1,
  layoutB: page2,
  layoutA: page3,
]

That means you have the full flexibility of the vue-router API at your disposal.

Common patterns

Transitions

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 <component> (for a detailed example, see the vue docs about transitions between elements).

App.vue

<template>
  <router-view v-slot="{ Component, route }">
    <transition name="slide">
      <component :is="Component" :key="route" />
    </transition>
  </router-view>
</template>

Now Vue will always trigger a transition if you change the route.

Data from layout to page

If you want to send data down from the layout to the page, use props

<router-view foo="bar" />

Set static data at the page

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 <route> block if you work with vite-plugin-pages.

In page.vue:

<template><div>Content</div></template>
<route lang="yaml">
meta:
  layout: default
  bgColor: yellow
</route>

Now you can read bgColor in layout.vue:

<script setup>
import { useRouter } from 'vue-router'
</script>
<template>
  <div :style="`background: ${useRouter().currentRoute.value.meta.bgColor};`">
    <router-view />
  </div>
</template>

Data dynamically from page to layout

If you need to set bgColor dynamically at run-time, you can use custom events.

Emit the event in page.vue:

<script setup>
import { defineEmit } from 'vue'
const emit = defineEmit(['setColor'])

if (2 + 2 === 4)
  emit('setColor', 'green')
else
  emit('setColor', 'red')
</script>

Listen for setColor custom-event in layout.vue:

<script setup>
import { ref } from 'vue'

const bgColor = ref('yellow')
const setBg = (color) => {
  bgColor.value = color
}
</script>

<template>
  <main :style="`background: ${bgColor};`">
    <router-view @set-color="setBg" />
  </main>
</template>

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

Usage

// vite.config.js
import { ClientSideLayout } from 'vite-plugin-vue-layouts'

export default {
  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
    }),
  ],
};

vite-plugin-vue-layouts's People

Contributors

johncampionjr avatar ctholho avatar antfu avatar markthree avatar yunyoujun avatar josh-hemphill avatar deathpresence avatar metanas avatar sougiovn avatar martinma avatar samuelalev avatar starfox64 avatar kingyue737 avatar byoungd avatar kkudr avatar philippethouvenot avatar xbmlz avatar yeli19950109 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.