Skip to content

Commit b267ce3

Browse files
Internal: Refactor Vue playground (#1864)
* Add dynamic routes to Vue playground * Simplify * Upgrade to Vite 3.0 * Use TypeScript
1 parent dd2feef commit b267ce3

File tree

10 files changed

+322
-300
lines changed

10 files changed

+322
-300
lines changed

packages/playground-vue/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
</head>
1010
<body class="h-full w-full font-sans text-gray-900 antialiased">
1111
<div class="h-full w-full" id="app"></div>
12-
<script type="module" src="/src/main.js"></script>
12+
<script type="module" src="/src/main.ts"></script>
1313
</body>
1414
</html>

packages/playground-vue/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"vue-router": "^4.0.0"
2929
},
3030
"devDependencies": {
31-
"@vitejs/plugin-vue": "^2.0.1",
32-
"vite": "^2.7.13"
31+
"@vitejs/plugin-vue": "^3.0.3",
32+
"vite": "^3.0.0"
3333
}
3434
}
Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,42 @@
1+
<script setup>
2+
import { defineComponent } from 'vue'
3+
import { useRouter } from 'vue-router'
4+
5+
let Examples = defineComponent({
6+
props: ['routes'],
7+
setup:
8+
(props, { slots }) =>
9+
() =>
10+
slots.default({ routes: props.routes, slots }),
11+
})
12+
13+
let router = useRouter()
14+
let routes = router
15+
.getRoutes()
16+
.filter((example) => example.path !== '/')
17+
.filter((route) => route.meta.isRoot)
18+
</script>
19+
120
<template>
221
<div class="container mx-auto my-24">
322
<div class="prose">
423
<h2>Examples</h2>
5-
<Examples :examples="examples" />
24+
<Examples :routes="routes" v-slot="{ routes, slots }">
25+
<ul>
26+
<li v-for="{ children, meta, path } in routes">
27+
<template v-if="children.length > 0">
28+
<h3 class="text-xl">{{ meta.name }}</h3>
29+
<!-- This is a bit cursed but it works -->
30+
<component v-for="vnode in slots.default({ routes: children, slots })" :is="vnode" />
31+
</template>
32+
<template v-else>
33+
<router-link :key="path" :to="path">
34+
{{ meta.name }}
35+
</router-link>
36+
</template>
37+
</li>
38+
</ul>
39+
</Examples>
640
</div>
741
</div>
842
</template>
9-
10-
<script>
11-
import { defineComponent, h } from 'vue'
12-
import { RouterLink } from 'vue-router'
13-
import routes from '../routes.json'
14-
15-
let Examples = defineComponent({
16-
props: ['examples'],
17-
setup(props) {
18-
return () => {
19-
return h(
20-
'ul',
21-
props.examples
22-
.filter((example) => example.path !== '/')
23-
.map((example) =>
24-
h(
25-
'li',
26-
{ key: example.path },
27-
example.children
28-
? h('h3', { class: 'text-xl' }, example.name)
29-
: [h(RouterLink, { to: example.path }, () => example.name)],
30-
example.children && h(Examples, { examples: example.children })
31-
)
32-
)
33-
)
34-
}
35-
},
36-
})
37-
38-
export default {
39-
components: { Examples },
40-
setup() {
41-
return {
42-
examples: routes,
43-
}
44-
},
45-
}
46-
</script>
File renamed without changes.

packages/playground-vue/src/router.js

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { createWebHistory, createRouter, RouterView } from 'vue-router'
2+
3+
type Component = import('vue').Component
4+
5+
function buildRoutes() {
6+
function titleCase(str) {
7+
return str
8+
.toLocaleLowerCase()
9+
.split('-')
10+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
11+
.join(' ')
12+
}
13+
14+
// 1. Get all the components in the src/components directory
15+
let files = Object.entries(
16+
import.meta.glob('./components/**/*.vue', {
17+
eager: true,
18+
import: 'default',
19+
})
20+
) as [string, Component][]
21+
22+
// 2.a. Swap the file names for route urls
23+
// 2.b. Resolve the default import for each component
24+
files = files.map(([file, component]) => [
25+
file
26+
.replace('./components/', '/')
27+
.replace(/\.vue$/, '')
28+
.toLocaleLowerCase()
29+
.replace(/^\/home$/g, '/'),
30+
component,
31+
])
32+
33+
let alreadyAdded = new Set()
34+
35+
// 3. Add a route for each directory (if not already added)
36+
files = files.flatMap((entry) => {
37+
let dirs = entry[0].split('/').slice(1, -1)
38+
39+
let paths: [string, Component][] = []
40+
41+
for (const [idx] of dirs.entries()) {
42+
let path = `/` + dirs.slice(0, idx + 1).join('/')
43+
if (alreadyAdded.has(path)) {
44+
continue
45+
}
46+
47+
paths.push([path, RouterView])
48+
alreadyAdded.add(path)
49+
}
50+
51+
return [...paths, entry]
52+
})
53+
54+
// 4. Sort the routes alphabetically and by length
55+
files.sort((a, b) => a[0].localeCompare(b[0]))
56+
57+
// 5. Create the nested routes
58+
let routes = []
59+
let routesByPath = {}
60+
61+
for (let [path, component] of files) {
62+
let prefix = path.split('/').slice(0, -1).join('/')
63+
let parent = routesByPath[prefix]?.children ?? routes
64+
let route = {
65+
path,
66+
component: component,
67+
children: [],
68+
meta: {
69+
name: titleCase(path.match(/[^/]+$/)?.[0] ?? 'Home'),
70+
isRoot: parent === routes,
71+
},
72+
}
73+
74+
parent.push((routesByPath[path] = route))
75+
}
76+
77+
return routes
78+
}
79+
80+
export default createRouter({
81+
history: createWebHistory(),
82+
routes: buildRoutes(),
83+
})

packages/playground-vue/src/routes.json

Lines changed: 0 additions & 188 deletions
This file was deleted.

0 commit comments

Comments
 (0)