GithubHelp home page GithubHelp logo

hannoeru / vite-plugin-pages Goto Github PK

View Code? Open in Web Editor NEW
1.7K 7.0 123.0 2.55 MB

File system based route generator for ⚡️Vite

License: MIT License

TypeScript 98.15% Dockerfile 1.65% Vue 0.07% JavaScript 0.12%

vite-plugin-pages's Introduction

vite-plugin-pages

npm version monthly downloads types license

Open in Visual Studio Code

File system based routing for Vue 3 / React / Solid applications using Vite

Getting Started

Vue

🚨Important Notes🚨

We recommend Vue user using unplugin-vue-router instead of this plugin.

unplugin-vue-router is a unplugin library created by @posva, same auther as vue-router. It provide almost same feature as vite-plugin-pages but better intergration with vue-router, include some cool feature like auto generate route types base on your route files to provide autocomplete for vue-router.

Install:

npm install -D vite-plugin-pages
npm install vue-router

React

since v0.19.0 we only support react-router v6, if you are using react-router v5 use v0.18.2.

Install:

npm install -D vite-plugin-pages
npm install react-router react-router-dom

Solid

Install:

npm install -D vite-plugin-pages
npm install @solidjs/router

Vite config

Add to your vite.config.js:

import Pages from 'vite-plugin-pages'

export default {
  plugins: [
    // ...
    Pages(),
  ],
}

Overview

By default a page is a Vue component exported from a .vue or .js file in the src/pages directory.

You can access the generated routes by importing the ~pages module in your application.

Vue

import { createRouter } from 'vue-router'
import routes from '~pages'

const router = createRouter({
  // ...
  routes,
})

Type

// vite-env.d.ts
/// <reference types="vite-plugin-pages/client" />

React

experimental

import { StrictMode, Suspense } from 'react'
import { createRoot } from 'react-dom/client'
import {
  BrowserRouter,
  useRoutes,
} from 'react-router-dom'

import routes from '~react-pages'

function App() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      {useRoutes(routes)}
    </Suspense>
  )
}

const app = createRoot(document.getElementById('root')!)

app.render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>,
)

Type

// vite-env.d.ts
/// <reference types="vite-plugin-pages/client-react" />

Solid

experimental

import { render } from 'solid-js/web'
import { Router, useRoutes } from '@solidjs/router'
import routes from '~solid-pages'

render(
  () => {
    const Routes = useRoutes(routes)
    return (
      <Router>
        <Routes />
      </Router>
    )
  },
  document.getElementById('root') as HTMLElement,
)

Type

// vite-env.d.ts
/// <reference types="vite-plugin-pages/client-solid" />

Configuration

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

// vite.config.js
import Pages from 'vite-plugin-pages'

export default {
  plugins: [
    Pages({
      dirs: 'src/views',
    }),
  ],
}

dirs

  • Type: string | (string | PageOptions)[]
  • Default: 'src/pages'

Paths to the pages directory. Supports globs.

Can be:

  • single path: routes point to /
  • array of paths: all routes in the paths point to /
  • array of PageOptions, Check below 👇
interface PageOptions {
  /**
   * Page base directory.
   * @default 'src/pages'
   */
  dir: string
  /**
   * Page base route.
   */
  baseRoute: string
  /**
   * Page file pattern.
   * @example `**\/*.page.vue`
   */
  filePattern?: string
}

Specifying a glob or an array of PageOptions allow you to use multiple pages folder, and specify the base route to append to the path and the route name.

Additionally, you can specify a filePattern to filter the files that will be used as pages.

Example

Folder structure

src/
  ├── features/
  │  └── dashboard/
  │     ├── code/
  │     ├── components/
  │     └── pages/
  ├── admin/
  │   ├── code/
  │   ├── components/
  │   └── pages/
  └── pages/

Config

// vite.config.js
export default {
  plugins: [
    Pages({
      dirs: [
        // basic
        { dir: 'src/pages', baseRoute: '' },
        // features dir for pages
        { dir: 'src/features/**/pages', baseRoute: 'features' },
        // with custom file pattern
        { dir: 'src/admin/pages', baseRoute: 'admin', filePattern: '**/*.page.*' },
      ],
    }),
  ],
}

extensions

  • Type: string[]
  • Default:
    • Vue: ['vue', 'ts', 'js']
    • React: ['tsx', 'jsx', 'ts', 'js']
    • Solid: ['tsx', 'jsx', 'ts', 'js']

An array of valid file extensions for pages. If multiple extensions match for a file, the first one is used.

exclude

  • Type: string[]
  • Default: []

An array of glob patterns to exclude matches.

# folder structure
src/pages/
  ├── users/
  │  ├── components
  │  │  └── form.vue
  │  ├── [id].vue
  │  └── index.vue
  └── home.vue
// vite.config.js
export default {
  plugins: [
    Pages({
      exclude: ['**/components/*.vue'],
    }),
  ],
}

importMode

  • Type: 'sync' | 'async' | (filepath: string, pluginOptions: ResolvedOptions) => 'sync' | 'async')
  • Default:
    • Top level index file: 'sync', others: async.

Import mode can be set to either async, sync, or a function which returns one of those values.

To get more fine-grained control over which routes are loaded sync/async, you can use a function to resolve the value based on the route path. For example:

// vite.config.js
export default {
  plugins: [
    Pages({
      importMode(filepath, options) {
        // default resolver
        // for (const page of options.dirs) {
        //   if (page.baseRoute === '' && filepath.startsWith(`/${page.dir}/index`))
        //     return 'sync'
        // }
        // return 'async'

        // Load about page synchronously, all other pages are async.
        return filepath.includes('about') ? 'sync' : 'async'
      },
    }),
  ],
}

If you are using async mode with react-router, you will need to wrap your route components with Suspense:

function App() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      {useRoutes(routes)}
    </Suspense>
  )
}

routeBlockLang

  • Type: string
  • Default: 'json5'

Default SFC route block parser.

routeStyle

  • Type: 'next' | 'nuxt' | 'remix'
  • Default: next

Use file system dynamic routing supporting:

routeNameSeparator

  • Type: string
  • Default: -

Separator for generated route names.

resolver

  • Type: 'vue' | 'react' | 'solid' | PageResolver
  • Default: 'auto detect'

Route resolver, support vue, react, solid or custom PageResolver.

moduleId

  • Type: string
  • Default:
    • Vue: '~pages'
    • React: '~react-pages'
    • Solid: '~solid-pages'

Module id for routes import, useful when you what to use multiple pages plugin in one project.

extendRoute

  • Type: (route: any, parent: any | undefined) => any | void

A function that takes a route and optionally returns a modified route. This is useful for augmenting your routes with extra data (e.g. route metadata).

// vite.config.js
export default {
  // ...
  plugins: [
    Pages({
      extendRoute(route, parent) {
        if (route.path === '/') {
          // Index is unauthenticated.
          return route
        }

        // Augment the route with meta that indicates that the route requires authentication.
        return {
          ...route,
          meta: { auth: true },
        }
      },
    }),
  ],
}

onRoutesGenerated

  • Type: (routes: any[]) => Awaitable<any[] | void>

A function that takes a generated routes and optionally returns a modified generated routes.

onClientGenerated

  • Type: (clientCode: string) => Awaitable<string | void>

A function that takes a generated client code and optionally returns a modified generated client code.

SFC custom block for Route Data

Add route meta to the route by adding a <route> block to the SFC. This will be directly added to the route after it is generated, and will override it.

You can specific a parser to use using <route lang="yaml">, or set a default parser using routeBlockLang option.

  • Supported parser: JSON, JSON5, YAML
  • Default: JSON5

JSON/JSON5:

<route>
{
  name: "name-override",
  meta: {
    requiresAuth: false
  }
}
</route>

YAML:

<route lang="yaml">
name: name-override
meta:
  requiresAuth: true
</route>

Syntax Highlighting <route>

To enable syntax highlighting <route> in VS Code using Vetur's Custom Code Blocks add the following snippet to your preferences...

  1. update setting
"vetur.grammar.customBlocks": {
   "route": "json"
 }
  1. Run the command in vscode

Vetur: Generate grammar from vetur.grammar.customBlocks

  1. Restart VS Code to get syntax highlighting for custom blocks.

JSX/TSX YAML format comments for Route Data(In Vue)

Add route meta to the route by adding a comment block starts with route to the JSX or TSX file(In Vue). This will be directly added to the route after it is generated, and will override it.

This feature only support JSX/TSX in vue, and will parse only the first block of comments which should also start with route.

Now only yaml parser supported.

  • Type: 'vue'
  • Supported parser: YAML
/*
route

name: name-override
meta:
  requiresAuth: false
  id: 1234
  string: "1234"
*/

File System Routing

Inspired by the routing from NuxtJS 💚

Pages automatically generates an array of routes for you to plug-in to your instance of Vue Router. These routes are determined by the structure of the files in your pages directory. Simply create .vue files in your pages directory and routes will automatically be created for you, no additional configuration required!

For more advanced use cases, you can tailor Pages to fit the needs of your app through configuration.

Basic Routing

Pages will automatically map files from your pages directory to a route with the same name:

  • src/pages/users.vue -> /users
  • src/pages/users/profile.vue -> /users/profile
  • src/pages/settings.vue -> /settings

Index Routes

Files with the name index are treated as the index page of a route:

  • src/pages/index.vue -> /
  • src/pages/users/index.vue -> /users

Dynamic Routes

Dynamic routes are denoted using square brackets. Both directories and pages can be dynamic:

  • src/pages/users/[id].vue -> /users/:id (/users/one)
  • src/pages/[user]/settings.vue -> /:user/settings (/one/settings)

Any dynamic parameters will be passed to the page as props. For example, given the file src/pages/users/[id].vue, the route /users/abc will be passed the following props:

{ "id": "abc" }

Nested Routes

We can make use of Vue Routers child routes to create nested layouts. The parent component can be defined by giving it the same name as the directory that contains your child routes.

For example, this directory structure:

src/pages/
  ├── users/
  │  ├── [id].vue
  │  └── index.vue
  └── users.vue

will result in this routes configuration:

[
  {
    "path": "/users",
    "component": "/src/pages/users.vue",
    "children": [
      {
        "path": "",
        "component": "/src/pages/users/index.vue",
        "name": "users"
      },
      {
        "path": ":id",
        "component": "/src/pages/users/[id].vue",
        "name": "users-id"
      }
    ]
  }
]

Catch-all Routes

Catch-all routes are denoted with square brackets containing an ellipsis:

  • src/pages/[...all].vue -> /* (/non-existent-page)

The text after the ellipsis will be used both to name the route, and as the name of the prop in which the route parameters are passed.

Sitemap generation

If you need to generate a sitemap from generated routes, you can use vite-plugin-pages-sitemap. This plugin allow you to automatically generate sitemap.xml and robots.xml files with customization.

License

MIT License © 2021-PRESENT hannoeru

vite-plugin-pages's People

Contributors

antfu avatar benjivm avatar bob0911 avatar callqh avatar charlesokwuagwu avatar climba03003 avatar fyeeme avatar hannoeru avatar homyeeking avatar hyoban avatar jbaubree avatar johncampionjr avatar junaga avatar klarkc avatar kota65535 avatar liho98 avatar lotwt avatar mariusa avatar martinma avatar metanas avatar peter50216 avatar peterhewat avatar posva avatar rebeccastevens avatar renovate[bot] avatar ricardo-valero avatar romanlamsal avatar shkreios avatar simon-he95 avatar victorgarciaesgi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

vite-plugin-pages's Issues

About the [...all].vue , get the wrong visit result.

Hi, this problem has bothered me for a while.

When the blog https://chengpeiquan.com/ has been visited, then, visit these static pages:

They will enter the 404 page. (In other words, it is the [...all].vue component)

But I use curl to check these file, they are OK.

# e.g.
curl https://chengpeiquan.com/feed.xml

They are also possible to use Ctrl + F5 to visit the correct result.

In the dist folder, these files are existed.

I don't quite understand why this happens.

Routing fails if we set **`base:`**

Routing fails if we set base:

import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import WindiCSS from 'vite-plugin-windicss'
import Pages from 'vite-plugin-pages'
import Layouts from 'vite-plugin-vue-layouts'

export default defineConfig({
  // base: '/gateway/',
  plugins: [
    Vue(),
    Pages({
      // pagesDir: [{ dir: 'src/pages', baseRoute: 'gateway' }],
      extensions: ['vue'],
      syncIndex: false
    }),
    ...WindiCSS(),
    Layouts()
  ]
})

without base:
https://localhost:3000 --.> 200 OK

0: {name: "chat", path: "/chat", props: true, component: ƒ}
1: {name: "contacts", path: "/contacts", props: true, component: ƒ}
2: {name: "dashboard", path: "/dashboard", props: true, component: ƒ}
3: {name: "index", path: "/", props: true, meta: {…}, component: ƒ}
4: {name: "self-service", path: "/self-service", props: true, component: ƒ}
5: {name: "settings", path: "/settings", props: true, component: ƒ}
6: {name: "users", path: "/users", props: true, component: ƒ}
7: {name: "all", path: "/:all(.*)", props: true, component: ƒ}
8: {name: "reports-agent-performance", path: "/reports/agent-performance", props: true, component: ƒ}
9: {name: "reports-session-summary", path: "/reports/session-summary", props: true, component: ƒ}
10: {name: "reports-traffic", path: "/reports/traffic", props: true, component: ƒ}

with base: '/gateway/' and pagesDir: [{ dir: 'src/pages', baseRoute: 'gateway' }],
https://localhost:3000/gateway/ --> 404
https://localhost:3000/gateway --> The server is configured with a public base URL of /gateway/ - did you mean to visit /gateway/gateway instead?

0: {name: "gateway-chat", path: "/gateway/chat", props: true, component: ƒ}
1: {name: "gateway-contacts", path: "/gateway/contacts", props: true, component: ƒ}
2: {name: "gateway-dashboard", path: "/gateway/dashboard", props: true, component: ƒ}
3: {name: "gateway-index", path: "/gateway", props: true, meta: {…}, component: ƒ}
4: {name: "gateway-self-service", path: "/gateway/self-service", props: true, component: ƒ}
5: {name: "gateway-settings", path: "/gateway/settings", props: true, component: ƒ}
6: {name: "gateway-users", path: "/gateway/users", props: true, component: ƒ}
7: {name: "gateway-all", path: "/gateway/:all(.*)", props: true, component: ƒ}
8: {name: "gateway-reports-agent-performance", path: "/gateway/reports/agent-performance", props: true, component: ƒ}
9: {name: "gateway-reports-session-summary", path: "/gateway/reports/session-summary", props: true, component: ƒ}
10: {name: "gateway-reports-traffic", path: "/gateway/reports/traffic", props: true, component: ƒ}

When using plugin with React, peer dependencies related with Vue maybe not needed?

Hi, I'm using this awesome plugin for a while in my React project. That's great!

When deploying to vercel.com, the missing peerDependencies (vue & @vue/compiler-sfc) will cause build errors. But I'm actually not using Vue stack at all. 😂 Now I add them to my devDenpendencies and everything works fine.

So I think we should cancel these two peer dependencies in package.json, or after the experimental?

Regression: Square brackets in filename

Hi! I'm having an error related to #16 using 0.4.7. I'm trying to deploy to Cloudflare Workers and it works in 0.4.6 (it seems CF workers allow brackets in the filenames), so I guess this is a regression issue.

I have a route /hi/:name (like in Vitesse) and the build outputs a file dist/client/assets/_name_.0441a72a.js for that one. There's no file with brackets. However, another JS file is trying to import the following:

component:()=>Mt((()=>__import__("./[name].0441a72a.js")),["/assets/_name_.0441a72a.js","/assets/vendor.2de24244.js"])

It is trying to request both, brackets and underscored versions:

image

I'll downgrade to 0.4.6 for now, which outputs the file with brackets only.

Thanks!

An example with authentication

I'd love to have an example with authentication, where the routes are accessible only with a particular variable being set to true.

I've added requiresAuth: true as meta, however I still can't force redirection from an unauthenticated route or apply my route guards based on a variable.

POST请求带query参数时,拦截不到请求

当post请求的url中带有query参数时,无法拦截请求,比如:

POST请求地址:/api/files?lang=zh-CN

mock文件:

export default {
  url: '/api/files',
  response: {},    
}

结果并不能拦截到请求。如果去掉query部分就能拦截到,get请求无此问题。

No routes are matched

Issue

I'm getting an error in browser suggesting that Vite is trying to handle pages like a regular asset:

Uncaught SyntaxError: The requested module '/@fs/Users/.../node_modules/voie-pages/index.js?v=b5ed82d3' does not provide an export named 'default'

I can see from brattonross/vite-plugin-voie#21 that adding enforce: 'pre' here should have fixed this without updates needed here. I'm, comparing to antfu/vitesse's package.json and everything checks out with my setup

The above was resolved with [email protected], leading to:

No routes are being matched:

[Vue Router warn]: No match found for location with path "/"

Environment

vite.config.ts

import Vue from '@vitejs/plugin-vue'
import path from 'path'
import type { UserConfig } from 'vite'
import Components from 'vite-plugin-components'
import Icons, { ViteIconsResolver } from 'vite-plugin-icons'
import Pages from 'vite-plugin-pages'

const config: UserConfig = {
  alias: {
    '/@/': `${path.resolve(__dirname, 'src')}/`
  },
  plugins: [
    Vue(),
    Pages(),
    Components({
      customComponentResolvers: ViteIconsResolver({
        componentPrefix: '',
        enabledCollections: ['mdi']
      }),
    }),
    Icons()
  ]
}

export default config

package.json

{
  ...
  "scripts": {
    "dev": "vite --port 3333",
    "build": "cross-env NODE_ENV=production vite build"
  },
  "dependencies": {
    "@vueuse/core": "^3.0.35",
    "vue": "^3.0.5",
    "vue-router": "^4.0.3"
  },
  "devDependencies": {
    "@antfu/eslint-config": "^0.4.3",
    "@iconify/json": "^1.1.292",
    "@types/node": "^14.14.22",
    "@typescript-eslint/eslint-plugin": "^4.14.1",
    "@vitejs/plugin-vue": "^1.1.2",
    "@vue/compiler-sfc": "^3.0.5",
    "cross-env": "^7.0.2",
    "eslint": "^7.18.0",
    "prettier": "^2.1.2",
    "tailwindcss": "^2.0.1-compat",
    "typescript": "^4.1.3",
    "vite": "^2.0.0-beta.50",
    "vite-plugin-components": "^0.6.6",
    "vite-plugin-icons": "^0.2.1",
    "vite-plugin-pages": "^0.1.7",
    "voie-pages": "^0.4.0"
  },
  ...
}

with eslint

When I use eslint to check my code , this code will throw an eslint error。

import routes from 'virtual:generated-pages';

Unable to resolve path to module 'virtual:generated-pages' import/no-unresolved

Do you have any good suggestions

Router-link issues

I don't know if this is a pages-problem or if I'm doing something wrong, but this basic link doesn't work:

<router-link to="foo/bar">

Instead of linking to "foo/bar" it only links to "bar" and ignores the "foo".

I'm using the current version of the vitesse template and I've got these pages folders:

src/
├─ pages/
│ ├─ foo.vue
│ ├─ foo/
│ │ ├─ bar.vue

And I use this layout:

<template>
  <div class="flex h-full content-center justify-center p-3">
    <div class="border-2 border-black p-10 w-full flex flex-col justify-between size">
      <div class="text-center">
        <h1 class="text-xl font-semibold mb-4">Ankauf von Schweißtechnik</h1>
        <div class="flex justify-around mb-8">
          <router-link to="/" class="inline-block text-xl cursor-pointer font-semibold">Allgemein</router-link>
          <router-link>
            <!-- problem here -->
            to="foo/bar"
            class="inline-block text-xl cursor-pointer font-semibold"
            >Verkaufs-Formular
          </router-link>
        </div>
      </div>
      <main class="overflow-auto flex-grow">
        <router-view />
      </main>
      <footer class="flex justify-around mt-8">
        <router-link to="datenschutz" class="cursor-pointer">Datenschutz</router-link>
        <router-link to="impressum" class="cursor-pointer">Impressum</router-link>
        <router-link to="kontakt" class="cursor-pointer">Kontakt</router-link>
      </footer>
    </div>
  </div>
</template>

VueRouter 3.0 Support?

Can I use Vue2.x + VueRouter3.x + vite-plugin-pages ?
Actually, I have tried it and it looks ok, but I don’t know if there are unpredictable bugs ^-^

No way to generate routes for testing

I've been trying for a while to create a router in a test context with the generated routes from the plugin but everything I have tried has failed.

I tried to use the generateRoutes in generate.ts but it seems that the function is not exported in the global module so no luck there.
Next I initialized the vite plugin as the normal build process would, thinking that somewhere a routes variable would be available, but after playing with it for a while I only ended up with a string containing the javascript definition of the routes (which I am assuming vite injects somewhere in the final bundle).
I tried using eval with the string but as there are imports for the components it wouldn't work with a "Cannot use import statement outside a module" error. I tried using node modules and compiling the source code, but I'm getting a bunch of other errors.

At this point I feel I'm fighting with the tools and libraries so I'm not sure if I'm doing something horribly wrong, misunderstanding how routes should be tested or the library is missing some useful functions for this.

For context, this is my last version of a loadRouter.ts file that I'm trying to use in tests as

import { loadRouter } from 'loadRouter'
beforeEach(loadRouter)
// ...tests
import pages from 'vite-plugin-pages'

export const loadRouter = async () => {
  const pagesPlugin = pages({ replaceSquareBackets: false, extensions: ['vue', 'md'] })
  // This feels wrong already
  const resolveId = (pagesPlugin.resolveId as any)('pages-generated', '', {})
  // The "as any" are because TS was freaking out with the optional resolveId and load functions
  const rawRoutes = await (pagesPlugin.load as any)(resolveId)
  const routes = eval(rawRoutes) // Fails as rawRoutes contains import statements
  // const routes = requreFromString(rawRoutes, '') // Fails with _compile function does not exist
  // ...Instantiate the router and return 
}

// I took this function from https://stackoverflow.com/a/17585470
// but I'm sure some of node's internals have changed. Anyway this feels too much for just loading the generated routes!
function requireFromString(src: string, filename: string) {
  const Module = module.constructor;
  const m = new Module()
  m._compile(src, filename) // Fails
  return m.exports
}

Escape or replace square brackets in file names?

Like with the nuxt routing module, the generation of routes with square brackets makes the plugin unusable in aws API Gateway environments. Original issue for reference: nuxt/nuxt#7625.

The problem is that API Gateway does not consider urls with square brackets valid, which makes dynamic and catch-all route files throw errors when loaded. Is there any way to replace these on build?
For now, I believe a workaround is to remove the brackets manually inside the dist folder, but ideally the plugin could have a way ty prevent this problem.

Is there has any way that I can disable Index Routes

I am use this plugin with vite-plugin-md.

And I want to generate the correct link with markdown syntax.

For example, I have two markdown file:
/src/test.md

[other](./other/index.md) # this will generate a link => <a href="./other/index">other</a>

/src/other/index.md

[test](../test.md) # this will generate a link => <a href="../test">test</a>

And I want the vite-plugin-pages can generate path with index.

Thanks for bring the awesome plugin.

How to test it with Vue Test Utils?

I would like to test my app that uses vite-plugin-pages but once I try to recreate my router outside Vite I (obviously) get an error:

The component that I would like to test - Timeline.vue

<template>
  <nav class="flex space-x-3 bg-gray-400">
    <router-link v-for="({name, slug}, i) in periods" :to="slug" :key="i" class="hover:underline">
      {{ name }}
    </router-link>
  </nav>
</template>

<script lang="ts" setup>
  import type {IPeriod} from '@/types'

  const periods: IPeriod[] = [
    {name: 'Today', slug: '/today'},
    {name: 'This Week', slug: '/week'},
    {name: 'This Month', slug: '/month'}
  ]
</script>

Timeline.spec.ts

// https://next.vue-test-utils.vuejs.org/guide/advanced/vue-router.html
import {shallowMount} from '@vue/test-utils'
import Timeline from './Timeline.vue'

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

const routes = setupLayouts(generatedRoutes)
const router = createRouter({
  history: createWebHistory(),
  routes
})

describe('Timeline', () => {
  it('Renders 3 time periods', () => {
    const wrapper = shallowMount(Timeline, {
      global: {
        plugins: [router]
      }
    })

    console.log('wrapper:', wrapper.html())
  })
})

Error:

 Cannot find module 'virtual:generated-pages' or its corresponding type declarations.

So my question is how can I use the result of virtual:generated-pages inside Vue Test Utils?

Can we expose `generateRoutes` and `generateClientCode`?

I see that the plugin exposes the two functions onRoutesGenerated and onClientGenerated. Can we also expose generateRoutes and generateClientCode? I think it's much easier to customize the code directly than after the operation

Is it possible to define a page with tsx?

created a test.tsx in src/pages like:

export const Test = defineComponent({
    setup() {
        return reactive({
            isEnabled: false
        })
    },
    render() {
        return <div>
            <div>Foo:</div>
            <Foo isEnabled={this.isEnabled}></Foo>
        </div>
    }
})

export default Test

but /test show 404 error

How to add validation for the route

Thanks, for really useful and time saving plugin.

I have tried using it and stumbled upon one issue with validating dynamic routes.

Let's say I have a path /[id] where id is only valid for numbers below 100. For everything else I want it to go to catch all. Obviously I can use beforeRoute check. But I thought maybe there is a builtin solution. Also it needs to work with SSG and to generate all the the pages /1, /2, ..., /100

Thanks in advance

onRoutesGenerated Uncaught SyntaxError: Identifier '_src_pages_index_vue' has already been declared

I'm using the onRoutesGenerated hook to add some localized routes to my application. When adding another route for the page index.vue I get the following error during runtime.

Uncaught SyntaxError: Identifier '_src_pages_index_vue' has already been declared

To be more specific. I have two pages in my pages folder. index.vue and about.vue which works fine on its own until I add the following hook. This is a minimal reproduction of the issue.

  Pages({
    onRoutesGenerated(routes: Route[]) {
      routes.push({
        name: 'index___de',
        path: '/de/',
        component: '/src/pages/index.vue',
        props: true
      })
      console.log(routes)
      return routes
    }
  }),

The console logs the following routes array.

[
  {
    name: 'about',
    path: '/about',
    component: '/src/pages/about.vue',
    props: true
  },
  {
    name: 'index',
    path: '/',
    component: '/src/pages/index.vue',
    props: true
  },
  {
    name: 'index___de',
    path: '/de/',
    component: '/src/pages/index.vue',
    props: true
  }
]

As far as I know the names of the individual routes have to be unique, which is the case here. Do you have any idea what is causing the issue here? I think it is a bug.

PS, the runtime error doesn't occur when adding a localized about route.

Association with vite-plugin-voie

I can see that both this and voie plugins are doing same thing - auto generating routes. So I though they are "competitors" to each other, fine.

But here at the bottom of Readme I see:

See more details: vite-plugin-voie

I though maybe it works on top of voie, but I do not see it in dependencies. So maybe it is fork of voie (if yes, what idea was behind it)? Could be this clarified to help choosing right package? Thanks :)

Ability to store route info in SFC

I have a PR coming shortly for this but wanted to open the issue for discussion.

I really like the auto route generation, but am not crazy about putting route info into vite.config.js

I like the solution provided by https://github.com/ktsn/vue-route-generator so I shamelessly used that as a reference for the changes made in the PR.

Alternatively, I thought of taking a dependency on that and using it to do all of the route generation. Upside would be it would be the same routes generated by vue-cli and vite.

If you would rather go that route (and I think is a lot to be said for doing it that way) let me know and I'll work on it.

weird alphabetical ignore error

So I've been wrangling this problem a lot today, but I think I got it nailed down now.
The steps to reproduce are as follows:

  1. add a index.vue file that has <route> block that sets a custom name that is the same(?!!) as the filename.
  2. add files that come before 'index' (so starting with a etc.)
  3. add files that come after 'index' (like starting with z)
  4. only the files that come before 'index' get generated routes.

Things to note:

  • This also triggers some sort of cache thing, HMR caches older version sometimes
  • once you remove the name attribute from the <route> block everything works again
  • the file gets recognized so it's not an globbing issue

I don't think this issue is particularly devastating but it's sooooo weird and so perplexing that I had to share it! 🤣

Set beforeEnter in extendRoute

Hi,

Thanks for the great component.

I am new to vue and vite, and I am looking to set "route.beforeEnter: Auth0.routeGuard" in the Pages.extendRoute config in vite.config.ts (assuming this is the correct place for this)

Could you perhaps assist with how to get this done? Assume I need to access the RouteRecordRaw?

Many Thanks,
Rob

Cannot find path '/'

I used import routes from 'pages-generated'
and set that in the createRouter(), but cannot find path for '/'
How to set that for /home?
Also getting these in the console. Not sure why.
[Vue Router warn]: No match found for location with path "/"
[Vue Router warn]: No match found for location with path "/"
[Vue Router warn]: No match found for location with path "/about"
[Vue Router warn]: No match found for location with path "/dashboard"
[Vue Router warn]: No match found for location with path "/login"
[Vue Router warn]: No match found for location with path "/dashboardinsuredportal"

BTW: great plugin, it works wonders, but just need to know how to set the path for '/'

dynamic routes are rendered twice after 0.9.6

i have this page [id]

<template>
  <span>{{pageViewColumns}}</span>
</template>

<script setup>

const pageViewColumns=test
console.log("should be printed once")
</script>

after 0.9.6 release i get the console msg printed twice.

How to handle multi entry apps

Hello, love the work you've done with this package.

Does this plugin support multi page apps as documented here in Vite's docs?

If I have 3 entries, could I structure my files similar to the following

/root
   /app1
      /pages
   /app2
      /pages
   /app3
      /pages

When deleting a file, an error will be reported

[vite] Internal server error: /src/pages/admin/index.vue has no corresponding SFC entry in the cache. This is a @vitejs/plugin-vue internal error, please open an issue.
      at getDescriptor (/Users/morelearn/project/vite/vite-vue3/node_modules/@vitejs/plugin-vue/dist/index.js:4068:11)
      at Context.load (/Users/morelearn/project/vite/vite-vue3/node_modules/@vitejs/plugin-vue/dist/index.js:4639:28)
      at Object.load (/Users/morelearn/project/vite/vite-vue3/node_modules/vite/dist/node/chunks/dep-5c642f9e.js:43728:50)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)
      at async transformRequest (/Users/morelearn/project/vite/vite-vue3/node_modules/vite/dist/node/chunks/dep-5c642f9e.js:59344:24)
      at async /Users/morelearn/project/vite/vite-vue3/node_modules/vite/dist/node/chunks/dep-5c642f9e.js:59538:32

Only after the vite.config.ts is resaved can it be reloaded normally

Changing <route> isn't picked up

When modifying the <route> custom block of a page, the new information isn't available in the app even after a full reload.
It looks like the only way to see the changes is to restart Vite.

Do nested routes have to use the same file as the directory name

In my system, there are a large number of pages of different categories that use the same layout component. I can put these different categories in the same directory and perform secondary classification, but this will cause more routing paths. A layout routing level.
Is there a way to point multiple directories to the same layout file?

route.props = function does not work as expected.

Exteding a route using onRoutesGenerated and changing route.props to a function as described here does not work as intended.

How to reproduce:

  1. Create a page that recives a named parameter for example [page].vue
  2. Use extendRoute to modify route.props = (route) => {page:Number.parseInt(route.params.page)}
  3. Load the page, error in console about missing prop for component.

What should happen:
param page should be cast to int and passed to component.

Is it possible to generate a typesafe route file?

add a script in package.json

"scripts": {
  "generate-routes": "vite-plugin-pages generate"
}

everytime run the generate command, it recreates the route file (routes.ts)

export const routes = {
  index: '#/',
  foo: {
    index: '#/foo',
    all: (p: unknown) => `#/foo/${p}`,
    bar: '#/foo/bar'
  }
}

then routing can be

import {routes} from './routes'

const Com = <div onClick={() =>history.push(routes.foo.index)}>go to foo</div>

Full app reload, always

While testing 0.11.4, I noticed that no matter what I change in a page, a full page reload is triggered.
For example, if I change a button label -> full page reload.

I suspect it was introduced by the fix for #52.
Page change -> potential <route> block change -> regenerate routing (always?) -> HMR not possible for routes.js -> full reload (?)

If <route> didn't change, that process should stop early and not induce an HMR failure.

Page parsing error when name contains "components"

I got an error while generating routes when a component has explicitly "component" word in their name

Got this:

  vite-plugin-pages   '      {\n' +
  vite-plugin-pages   `        "nam() => import('": "components-vbutton'),\n` +
  vite-plugin-pages   '        "path": "vbutton",\n' +
  vite-plugin-pages   `        "component": () => import('/src/pages/components/vbutton.vue'),\n` +
  vite-plugin-pages   '        "props": true\n' +
  vite-plugin-pages   '      },\n' +

Instead of this:

  vite-plugin-pages   '      {\n' +
  vite-plugin-pages   '        "name": "components-vbutton",\n' +
  vite-plugin-pages   '        "path": "vbutton",\n' +
  vite-plugin-pages   `        "component": () => import('/src/pages/components/vbutton.vue'),\n` +
  vite-plugin-pages   '        "props": true\n' +
  vite-plugin-pages   '      },\n' +

This expression is not callable. After update to v0.6.0

Hi, I'm having this error when use the plugin in my vite config

This expression is not callable.
  Type 'typeof import("path-to-node_modules/vite-plugin-pages/index")' has no call signatures.

However when run my project everything works correctly.

This is my vite.config.ts

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

import Pages from 'vite-plugin-pages';

import path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),

    // here the error is displayed 
    Pages({
      syncIndex: false,
    }),
  ],
  resolve: {
    alias: {
      '~/': `${path.resolve(__dirname, 'src')}/`,
    },
  },
  server: {
    open: true,
  },
});

[question] Cannot find module 'virtual:generated-pages' or its corresponding type declarations

Hi, thanks for this great plugin!

In main.ts I get

Cannot find module 'virtual:generated-pages' or its corresponding type declarations

on the line import routes from 'virtual:generated-pages' (in vscode)

I see the module is declared at https://github.com/hannoeru/vite-plugin-pages/blob/main/client.d.ts
Is there something else to do in order to recognize that definition and rid of this error?

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'

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [vue(), Pages(), Layouts()]
})

adding module.exports in vite.config.js breaks virtual:generated-pages

virtual:generated-pages works fine until adding this to vite.config.js

const path = require('path')

module.exports = {
    alias: {
        // alias a path to a fs directory
        // the key must start and end with a slash
        '/@/': path.resolve(__dirname, 'src')
    },
}
error when starting dev server:
Error: The following dependencies are imported but could not be resolved:

  virtual:generated-pages (imported by /home/marius/work/wensia/admin/src/main.ts)

Are they installed?
    at optimizeDeps (/home/marius/work/wensia/admin/node_modules/vite/dist/node/chunks/dep-0776dd57.js:65459:15)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async runOptimize (/home/marius/work/wensia/admin/node_modules/vite/dist/node/chunks/dep-0776dd57.js:69211:48)
    at async Server.httpServer.listen (/home/marius/work/wensia/admin/node_modules/vite/dist/node/chunks/dep-0776dd57.js:69225:17)

Would you have any suggestion on how to fix this? Thanks

Dynamic pages and SSG

Let's say i have a dynamic page /[id] which can be from1 to 10. I want to generate all those pages on SSG Build.

I tried includedRoutes in SSGOptions for vite-SSG, but was wodering if there is a better approach.

Thanks

[questions] i18n routes and sitemap.xml

Hello !
First thanks for the work on this project :)

I'm just wondering if this plugin can handle generation of sitemap.xml file related to generated routes.
Also, it may be interesting to be able to localize URI per locale.

I think <route> SFC block is a good place for these settings.

I can start working on it, but I prefer to ask before as this plugin is growing :)

Multiple paths in config

My next step is to allow multiple paths in the config. This will bring Vite-plugin-pages closer to config parity with Vite-plugin-components. Is this a feature you'd be interested in?

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.