├── tests
├── scenarios
│ ├── single-file
│ │ └── home.vue
│ ├── with-an-index
│ │ ├── about.vue
│ │ └── index.vue
│ ├── with-everything
│ │ ├── about.vue
│ │ ├── contact.vue
│ │ ├── index.vue
│ │ ├── _product.vue
│ │ ├── _product
│ │ │ ├── buy.vue
│ │ │ ├── index.vue
│ │ │ └── sell.vue
│ │ └── contact
│ │ │ ├── help.vue
│ │ │ └── feedback.vue
│ ├── with-some-params
│ │ ├── about.vue
│ │ ├── team
│ │ │ ├── _name.vue
│ │ │ └── join.vue
│ │ └── _product
│ │ │ ├── buy.vue
│ │ │ └── sell.vue
│ ├── with-a-little-nesting
│ │ ├── index.vue
│ │ ├── contact.vue
│ │ └── level1
│ │ │ ├── team.vue
│ │ │ ├── about.vue
│ │ │ └── level2
│ │ │ ├── deep.vue
│ │ │ └── index.vue
│ ├── single-level-multiple-files
│ │ ├── about.vue
│ │ ├── home.vue
│ │ ├── -ignored.vue
│ │ └── ignored.js
│ └── with-some-child-components
│ │ ├── about.vue
│ │ ├── contact.vue
│ │ └── contact
│ │ ├── feedback.vue
│ │ ├── help.vue
│ │ └── index.vue
└── directory-parser.spec.js
├── .gitignore
├── example
├── pages
│ ├── contact.vue
│ ├── services
│ │ ├── index.vue
│ │ ├── cooking.vue
│ │ └── laundry.vue
│ ├── team
│ │ ├── index.vue
│ │ └── _name.vue
│ ├── _product
│ │ ├── buy.vue
│ │ └── sell.vue
│ ├── about.vue
│ └── services.vue
├── main.js
├── router.js
└── App.vue
├── public
└── favicon.ico
├── .prettierrc
├── vite.config.js
├── index.html
├── .eslintrc.js
├── vite-auto-route.code-workspace
├── LICENSE
├── package.json
├── src
├── plugin.js
└── directory-parser.js
└── README.md
/tests/scenarios/single-file/home.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-an-index/about.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-an-index/index.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/about.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/contact.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/index.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-params/about.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-a-little-nesting/index.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/_product.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/_product/buy.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/contact/help.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-params/team/_name.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-params/team/join.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/single-level-multiple-files/about.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/single-level-multiple-files/home.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-a-little-nesting/contact.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-a-little-nesting/level1/team.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/_product/index.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/_product/sell.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-everything/contact/feedback.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-child-components/about.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-params/_product/buy.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-params/_product/sell.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | *.local
--------------------------------------------------------------------------------
/tests/scenarios/single-level-multiple-files/-ignored.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/single-level-multiple-files/ignored.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-a-little-nesting/level1/about.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-child-components/contact.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-a-little-nesting/level1/level2/deep.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-a-little-nesting/level1/level2/index.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-child-components/contact/feedback.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-child-components/contact/help.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/scenarios/with-some-child-components/contact/index.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/pages/contact.vue:
--------------------------------------------------------------------------------
1 |
2 | Contact us
3 |
4 |
--------------------------------------------------------------------------------
/example/pages/services/index.vue:
--------------------------------------------------------------------------------
1 |
2 | Some default stuff
3 |
4 |
--------------------------------------------------------------------------------
/example/pages/team/index.vue:
--------------------------------------------------------------------------------
1 |
2 | Landing page for team
3 |
4 |
--------------------------------------------------------------------------------
/example/pages/services/cooking.vue:
--------------------------------------------------------------------------------
1 |
2 | We'll do your cooking
3 |
4 |
--------------------------------------------------------------------------------
/example/pages/services/laundry.vue:
--------------------------------------------------------------------------------
1 |
2 | We'll do your laundry
3 |
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chs-uk/vite-plugin-auto-routes/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/example/pages/_product/buy.vue:
--------------------------------------------------------------------------------
1 |
2 | You're going to buy this product.
3 |
4 |
--------------------------------------------------------------------------------
/example/pages/_product/sell.vue:
--------------------------------------------------------------------------------
1 |
2 | You're going to sell this product.
3 |
4 |
--------------------------------------------------------------------------------
/example/pages/team/_name.vue:
--------------------------------------------------------------------------------
1 |
2 | Team page for: {{ $route.params.name }}
3 |
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "arrowParens": "always",
4 | "singleQuote": true,
5 | "trailingComma": "all",
6 | "printWidth": 100
7 | }
8 |
--------------------------------------------------------------------------------
/example/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 |
5 | createApp(App).use(router).mount('#app')
6 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | const viteAutoRoute = require('./src/plugin.js')
2 |
3 | module.exports = {
4 | plugins: [viteAutoRoute({ pagesDir: './example/pages' })],
5 | }
6 |
--------------------------------------------------------------------------------
/example/router.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 | import { routes } from 'vue-auto-routes'
3 |
4 | const router = createRouter({
5 | history: createWebHashHistory(),
6 | routes,
7 | })
8 |
9 | export default router
10 |
--------------------------------------------------------------------------------
/example/pages/about.vue:
--------------------------------------------------------------------------------
1 |
2 | About. Will this require login? {{ $route.meta.requiresLogin ? 'Yes' : 'No.' }}
3 |
4 |
5 |
8 |
9 |
10 | {
11 | "meta": {
12 | "requiresLogin": true,
13 | }
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/example/pages/services.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Check out the services we offer
4 | Cooking
5 | Laundry
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | },
7 | parserOptions: {
8 | parser: 'babel-eslint',
9 | },
10 | extends: ['prettier', 'prettier/vue', 'plugin:prettier/recommended'],
11 | plugins: ['prettier'],
12 | rules: {
13 | 'comma-dangle': ['error', 'always-multiline'],
14 |
15 | 'vue/max-attributes-per-line': [
16 | 2,
17 | {
18 | singleline: 20,
19 | multiline: {
20 | max: 1,
21 | allowFirstLine: false,
22 | },
23 | },
24 | ],
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/example/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | About
4 | Contact
5 | Services
6 | Team
7 |
8 | Buy computer
9 |
10 |
11 | Sell computer
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/vite-auto-route.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "."
5 | }
6 | ],
7 | "settings": {
8 | // Newlines/spaces
9 | "files.insertFinalNewline": true,
10 | "files.trimFinalNewlines": true,
11 | "files.trimTrailingWhitespace": true,
12 |
13 | // Files to exclude from file explorer
14 | "files.exclude": {
15 | "**/node_modules/": true
16 | },
17 |
18 | // Files to exclude from git watching
19 | "files.watcherExclude": {
20 | "**/.git/objects/**": true,
21 | "**/.git/subtree-cache/**": true,
22 | "**/node_modules/*/**": true
23 | },
24 |
25 | // Editor appearance
26 | "editor.rulers": [100],
27 |
28 | // General formatting rules
29 | "editor.formatOnSave": true,
30 |
31 | // Frontend formatting
32 | "vetur.format.enable": false,
33 | "vetur.grammar.customBlocks": {
34 | "route": "json"
35 | },
36 | "prettier.disableLanguages": []
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 katashin
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-plugin-auto-routes",
3 | "description": "Vite plugin to automatically generate routes from a file structure",
4 | "version": "0.1.1",
5 | "license": "MIT",
6 | "main": "src/plugin.js",
7 | "files": [
8 | "src"
9 | ],
10 | "keywords": [
11 | "Vue",
12 | "Vue 3",
13 | "vite",
14 | "plugin",
15 | "routing",
16 | "auto routing"
17 | ],
18 | "author": "axwalker",
19 | "bugs": {
20 | "url": "https://github.com/ImpactBox/vite-plugin-auto-routes/issues"
21 | },
22 | "homepage": "https://github.com/ImpactBox/vite-plugin-auto-routes",
23 | "scripts": {
24 | "dev": "vite",
25 | "build": "vite build",
26 | "test": "jest"
27 | },
28 | "dependencies": {
29 | "common-tags": "^1.8.0",
30 | "vue": "^3.0.0-rc.1",
31 | "vue-router": "4.0.0-beta.3"
32 | },
33 | "devDependencies": {
34 | "@rollup/plugin-virtual": "^2.0.3",
35 | "@vue/compiler-sfc": "^3.0.0-rc.1",
36 | "jest": "^26.1.0",
37 | "rollup": "^2.23.0",
38 | "vite": "^1.0.0-rc.1"
39 | },
40 | "peerDependencies": {
41 | "vue": "^3.0.0-rc.1",
42 | "vue-router": "4.0.0-beta.3"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/plugin.js:
--------------------------------------------------------------------------------
1 | const virtual = require('@rollup/plugin-virtual')
2 | const { parsePagesDirectory } = require('./directory-parser')
3 |
4 | function makeModuleContent({ pagesDir }) {
5 | const { routes } = parsePagesDirectory(pagesDir)
6 | return `export const routes = [${routes.join(', \n')}]`
7 | }
8 |
9 | module.exports = function ({ pagesDir } = { pagesDir: 'src/pages/' }) {
10 | const configureServer = [
11 | async ({ app }) => {
12 | app.use(async (ctx, next) => {
13 | if (ctx.path.startsWith('/@modules/vue-auto-routes')) {
14 | ctx.type = 'js'
15 | ctx.body = makeModuleContent({ pagesDir })
16 | } else {
17 | await next()
18 | }
19 | })
20 | },
21 | ]
22 |
23 | const rollupInputOptions = {
24 | plugins: [virtual({ 'vue-auto-routes': makeModuleContent({ pagesDir }) })],
25 | }
26 |
27 | /* Note: these route options are not yet used anywhere */
28 | const vueCustomBlockTransforms = {
29 | route: ({ code }) => {
30 | return `
31 | export default function (Component) {
32 | Component.__routeOptions = ${code}
33 | }
34 | `
35 | },
36 | }
37 |
38 | return { configureServer, rollupInputOptions, vueCustomBlockTransforms }
39 | }
40 |
--------------------------------------------------------------------------------
/src/directory-parser.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | function parsePagesDirectory(
5 | dir,
6 | { prependName, prependPath } = { prependName: '', prependPath: '/' },
7 | ) {
8 | let routes = []
9 |
10 | const siblings = fs.readdirSync(dir, { withFileTypes: true })
11 |
12 | const files = siblings
13 | .filter((f) => f.isFile() && f.name.endsWith('.vue') && !f.name.startsWith('-'))
14 | .map((f) => f.name)
15 |
16 | const directories = siblings.filter((f) => f.isDirectory()).map((d) => d.name)
17 |
18 | for (const name of files) {
19 | const f = { name: name.split('.')[0], importPath: path.join(dir, name) }
20 |
21 | const routeOptions = []
22 | // Route name
23 | if (!directories.includes(f.name) || !fs.existsSync(path.join(dir, f.name, 'index.vue'))) {
24 | const routeName =
25 | f.name === 'index' && prependName
26 | ? prependName.slice(0, -1)
27 | : prependName + f.name.replace(/^_/, '')
28 | routeOptions.push(`name: '${routeName}'`)
29 | }
30 | // Route path
31 | routeOptions.push(
32 | `path: '${prependPath}${f.name === 'index' ? '' : f.name.replace(/^_/, ':')}'`,
33 | )
34 | // Route component
35 | routeOptions.push(`component: () => import('/${f.importPath}')`)
36 | // Route children
37 | if (directories.includes(f.name)) {
38 | children = parsePagesDirectory(path.join(dir, f.name), {
39 | prependName: `${prependName}${f.name.replace(/^_/, '')}-`,
40 | prependPath: '',
41 | }).routes
42 | routeOptions.push(`children: [ ${children.join(', ')} ]`)
43 | }
44 | routes.push(`{ ${routeOptions.join(', ')} }`)
45 | }
46 |
47 | // If a directory exists with the same name as a sibling file, it means the folder acts as
48 | // children routes. Those children are dealt with above, so we filter them out here.
49 | const filesWithoutExtension = files.map((f) => f.slice(0, -4))
50 | const remainingDirectories = directories.filter((d) => !filesWithoutExtension.includes(d))
51 | for (const name of remainingDirectories) {
52 | const parsedDir = parsePagesDirectory(path.join(dir, name), {
53 | prependName: `${prependName}${name.replace(/^_/, '')}-`,
54 | prependPath: `${prependPath}${name.replace(/^_/, ':')}/`,
55 | })
56 | routes = routes.concat(parsedDir.routes)
57 | }
58 |
59 | return { routes }
60 | }
61 |
62 | module.exports = {
63 | parsePagesDirectory,
64 | }
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vite-plugin-auto-routes
2 |
3 | A vite plugin for automatic routing in Vue 3 based on your file structure.
4 |
5 | # Why?
6 |
7 | You want automatic routing from a file structure, as you'd get in [Nuxt](https://nuxtjs.org/guide/routing/). Specifically, you want to turn this file tree:
8 |
9 | ```
10 | pages/
11 | --| user/
12 | -----| index.vue
13 | -----| one.vue
14 | --| index.vue
15 | ```
16 |
17 | into this:
18 |
19 | ```js
20 | router: {
21 | routes: [
22 | {
23 | name: 'index',
24 | path: '/',
25 | component: 'pages/index.vue',
26 | },
27 | {
28 | name: 'user',
29 | path: '/user',
30 | component: 'pages/user/index.vue',
31 | },
32 | {
33 | name: 'user-one',
34 | path: '/user/one',
35 | component: 'pages/user/one.vue',
36 | },
37 | ]
38 | }
39 | ```
40 |
41 | Paramaters and child components are supported in the same way as Nuxt. See the [example](example/) for a more complete example pages directory.
42 |
43 | There already exists a Vue 2 + [vue-cli plugin](https://github.com/ktsn/vue-cli-plugin-auto-routing) for this, but not for Vue 3 + vite.
44 |
45 | # Usage
46 |
47 | ## Installation
48 |
49 | With npm:
50 |
51 | ```
52 | npm i --save-dev vite-plugin-auto-routes
53 | ```
54 |
55 | With yarn:
56 |
57 | ```
58 | yarn add -D vite-plugin-auto-routes
59 | ```
60 |
61 | Then in your `vite.config.js` file add:
62 |
63 | ```js
64 | const viteAutoRoute = require('vite-plugin-auto-routes')
65 |
66 | module.exports = {
67 | plugins: [viteAutoRoute({ pagesDir: 'src/pages' })],
68 | }
69 | ```
70 |
71 | Routes will now be available by importing `vue-auto-routes` in your app. You can then set up your router as you normally would, for example (using vue-router-next for Vue 3):
72 |
73 | ```js
74 | import { createApp } from 'vue'
75 | import { createRouter, createWebHashHistory } from 'vue-router'
76 | import { routes } from 'vue-auto-routes'
77 | import App from './App.vue'
78 |
79 | const router = createRouter({
80 | history: createWebHashHistory(),
81 | routes,
82 | })
83 | createApp(App).use(router).mount('#app')
84 | ```
85 |
86 | # Limitations
87 |
88 | ## Hot module reloading
89 |
90 | If you create new pages that will generate new routes, they currently will not be available until you refresh the page. Editing existing pages will hot reload as normal.
91 |
92 | # To do
93 |
94 | - [x] Support single flat directory
95 | - [x] Support child components through nested directories
96 | - [x] Support route parameters
97 | - [x] Custom pages directory
98 | - [ ] Custom route block
99 |
100 | # Inspirations
101 |
102 | - [Nuxt routing](https://nuxtjs.org/guide/routing/)
103 | - [vue-cli-plugin-auto-routing](https://github.com/ktsn/vue-cli-plugin-auto-routing)
104 |
--------------------------------------------------------------------------------
/tests/directory-parser.spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const { oneLine } = require('common-tags')
3 | const { parsePagesDirectory } = require('../src/directory-parser')
4 |
5 | test('empty directory', () => {
6 | const { routes } = parsePagesDirectory('tests/scenarios/empty')
7 | expect(routes).toEqual([])
8 | })
9 |
10 | test('directory with a single file', () => {
11 | const dir = 'tests/scenarios/single-file'
12 | const { routes } = parsePagesDirectory(dir)
13 | expect(routes).toEqual([
14 | `{ name: 'home', path: '/home', component: () => import('/${dir}/home.vue') }`,
15 | ])
16 | })
17 |
18 | test('directory with multiple files', () => {
19 | const dir = 'tests/scenarios/single-level-multiple-files'
20 | const { routes } = parsePagesDirectory(dir)
21 |
22 | expect(routes).toEqual([
23 | `{ name: 'about', path: '/about', component: () => import('/${dir}/about.vue') }`,
24 | `{ name: 'home', path: '/home', component: () => import('/${dir}/home.vue') }`,
25 | ])
26 | })
27 |
28 | test('directory with an index file', () => {
29 | const dir = 'tests/scenarios/with-an-index'
30 | const { routes } = parsePagesDirectory(dir)
31 |
32 | expect(routes).toEqual([
33 | `{ name: 'about', path: '/about', component: () => import('/${dir}/about.vue') }`,
34 | `{ name: 'index', path: '/', component: () => import('/${dir}/index.vue') }`,
35 | ])
36 | })
37 |
38 | test('directory with a little nesting', () => {
39 | const dir = 'tests/scenarios/with-a-little-nesting'
40 | const { routes } = parsePagesDirectory(dir)
41 |
42 | expect(routes).toEqual([
43 | `{ name: 'contact', path: '/contact', component: () => import('/${dir}/contact.vue') }`,
44 | `{ name: 'index', path: '/', component: () => import('/${dir}/index.vue') }`,
45 | `{ name: 'level1-about', path: '/level1/about', component: () => import('/${dir}/level1/about.vue') }`,
46 | `{ name: 'level1-team', path: '/level1/team', component: () => import('/${dir}/level1/team.vue') }`,
47 | `{ name: 'level1-level2-deep', path: '/level1/level2/deep', component: () => import('/${dir}/level1/level2/deep.vue') }`,
48 | `{ name: 'level1-level2', path: '/level1/level2/', component: () => import('/${dir}/level1/level2/index.vue') }`,
49 | ])
50 | })
51 |
52 | test('directory with child components', () => {
53 | const dir = 'tests/scenarios/with-some-child-components'
54 | const { routes } = parsePagesDirectory(dir)
55 |
56 | expect(routes).toEqual([
57 | `{ name: 'about', path: '/about', component: () => import('/${dir}/about.vue') }`,
58 | oneLine`{
59 | path: '/contact',
60 | component: () => import('/${dir}/contact.vue'),
61 | children: [
62 | { name: 'contact-feedback', path: 'feedback', component: () => import('/${dir}/contact/feedback.vue') },
63 | { name: 'contact-help', path: 'help', component: () => import('/${dir}/contact/help.vue') },
64 | { name: 'contact', path: '', component: () => import('/${dir}/contact/index.vue') }
65 | ]
66 | }`,
67 | ])
68 | })
69 |
70 | test('directory with some params', () => {
71 | const dir = 'tests/scenarios/with-some-params'
72 | const { routes } = parsePagesDirectory(dir)
73 |
74 | expect(routes).toEqual([
75 | `{ name: 'about', path: '/about', component: () => import('/${dir}/about.vue') }`,
76 | `{ name: 'product-buy', path: '/:product/buy', component: () => import('/${dir}/_product/buy.vue') }`,
77 | `{ name: 'product-sell', path: '/:product/sell', component: () => import('/${dir}/_product/sell.vue') }`,
78 | `{ name: 'team-name', path: '/team/:name', component: () => import('/${dir}/team/_name.vue') }`,
79 | `{ name: 'team-join', path: '/team/join', component: () => import('/${dir}/team/join.vue') }`,
80 | ])
81 | })
82 |
83 | test('directory with everything', () => {
84 | const dir = 'tests/scenarios/with-everything'
85 | const { routes } = parsePagesDirectory(dir)
86 |
87 | expect(routes).toEqual([
88 | oneLine`{
89 | path: '/:product',
90 | component: () => import('/${dir}/_product.vue'),
91 | children: [
92 | { name: 'product-buy', path: 'buy', component: () => import('/${dir}/_product/buy.vue') },
93 | { name: 'product', path: '', component: () => import('/${dir}/_product/index.vue') },
94 | { name: 'product-sell', path: 'sell', component: () => import('/${dir}/_product/sell.vue') }
95 | ]
96 | }`,
97 | `{ name: 'about', path: '/about', component: () => import('/${dir}/about.vue') }`,
98 | oneLine`{
99 | name: 'contact',
100 | path: '/contact',
101 | component: () => import('/${dir}/contact.vue'),
102 | children: [
103 | { name: 'contact-feedback', path: 'feedback', component: () => import('/${dir}/contact/feedback.vue') },
104 | { name: 'contact-help', path: 'help', component: () => import('/${dir}/contact/help.vue') }
105 | ]
106 | }`,
107 | `{ name: 'index', path: '/', component: () => import('/${dir}/index.vue') }`,
108 | ])
109 | })
110 |
--------------------------------------------------------------------------------