Skip to content

Commit 3d6aa41

Browse files
authored
Vue router (#5997)
1 parent aac4621 commit 3d6aa41

File tree

360 files changed

+48753
-132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

360 files changed

+48753
-132
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import js from '@eslint/js'
2+
import typescript from '@typescript-eslint/eslint-plugin'
3+
import typescriptParser from '@typescript-eslint/parser'
4+
import vue from 'eslint-plugin-vue'
5+
import vueParser from 'vue-eslint-parser'
6+
7+
export default [
8+
js.configs.recommended,
9+
...vue.configs['flat/recommended'],
10+
{
11+
files: ['**/*.{js,jsx,ts,tsx,vue}'],
12+
languageOptions: {
13+
parser: vueParser,
14+
parserOptions: {
15+
parser: typescriptParser,
16+
ecmaVersion: 'latest',
17+
sourceType: 'module',
18+
ecmaFeatures: {
19+
jsx: true,
20+
},
21+
},
22+
},
23+
plugins: {
24+
'@typescript-eslint': typescript,
25+
vue,
26+
},
27+
rules: {
28+
// Vue specific rules
29+
'vue/multi-word-component-names': 'off',
30+
'vue/no-unused-vars': 'error',
31+
32+
// TypeScript rules
33+
'@typescript-eslint/no-unused-vars': 'error',
34+
'@typescript-eslint/no-explicit-any': 'warn',
35+
36+
// General rules
37+
'no-unused-vars': 'off', // Let TypeScript handle this
38+
},
39+
},
40+
{
41+
files: ['**/*.vue'],
42+
languageOptions: {
43+
parser: vueParser,
44+
parserOptions: {
45+
parser: typescriptParser,
46+
},
47+
},
48+
},
49+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
</head>
7+
<body>
8+
<div id="app"></div>
9+
<script type="module" src="/src/main.tsx"></script>
10+
</body>
11+
</html>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "tanstack-router-e2e-vue-basic-file-based-jsx",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite --port 3000",
7+
"dev:e2e": "vite",
8+
"build": "vite build && vue-tsc --noEmit",
9+
"preview": "vite preview",
10+
"start": "vite",
11+
"test:e2e": "rm -rf port*.txt; playwright test --project=chromium"
12+
},
13+
"dependencies": {
14+
"@tailwindcss/postcss": "^4.1.15",
15+
"@tanstack/router-plugin": "workspace:^",
16+
"@tanstack/vue-router": "workspace:^",
17+
"@tanstack/vue-router-devtools": "workspace:^",
18+
"@tanstack/zod-adapter": "workspace:^",
19+
"postcss": "^8.5.1",
20+
"redaxios": "^0.5.1",
21+
"tailwindcss": "^4.1.15",
22+
"vue": "^3.5.16",
23+
"zod": "^3.24.2"
24+
},
25+
"devDependencies": {
26+
"@eslint/js": "^9.36.0",
27+
"@playwright/test": "^1.50.1",
28+
"@tanstack/router-e2e-utils": "workspace:^",
29+
"@typescript-eslint/eslint-plugin": "^8.44.1",
30+
"@typescript-eslint/parser": "^8.44.1",
31+
"@vitejs/plugin-vue": "^5.2.3",
32+
"@vitejs/plugin-vue-jsx": "^4.1.2",
33+
"eslint-plugin-vue": "^9.33.0",
34+
"typescript": "~5.8.3",
35+
"vite": "^7.1.7",
36+
"vue-eslint-parser": "^9.4.3",
37+
"vue-tsc": "^3.1.5"
38+
}
39+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
import {
3+
getDummyServerPort,
4+
getTestServerPort,
5+
} from '@tanstack/router-e2e-utils'
6+
import packageJson from './package.json' with { type: 'json' }
7+
8+
const PORT = await getTestServerPort(packageJson.name)
9+
const EXTERNAL_PORT = await getDummyServerPort(packageJson.name)
10+
const baseURL = `http://localhost:${PORT}`
11+
/**
12+
* See https://playwright.dev/docs/test-configuration.
13+
*/
14+
export default defineConfig({
15+
testDir: './tests',
16+
workers: 1,
17+
18+
reporter: [['line']],
19+
20+
globalSetup: './tests/setup/global.setup.ts',
21+
globalTeardown: './tests/setup/global.teardown.ts',
22+
23+
use: {
24+
/* Base URL to use in actions like `await page.goto('/')`. */
25+
baseURL,
26+
},
27+
28+
webServer: {
29+
command: `VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm build && VITE_NODE_ENV="test" VITE_EXTERNAL_PORT=${EXTERNAL_PORT} VITE_SERVER_PORT=${PORT} pnpm preview --port ${PORT}`,
30+
url: baseURL,
31+
reuseExistingServer: !process.env.CI,
32+
stdout: 'pipe',
33+
},
34+
35+
projects: [
36+
{
37+
name: 'chromium',
38+
use: { ...devices['Desktop Chrome'] },
39+
},
40+
],
41+
})
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
plugins: {
3+
'@tailwindcss/postcss': {},
4+
},
5+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { ref, defineComponent } from 'vue'
2+
import { useBlocker, useNavigate } from '@tanstack/vue-router'
3+
4+
export const EditingAComponent = defineComponent({
5+
setup() {
6+
const navigate = useNavigate()
7+
const input = ref('')
8+
9+
const blocker = useBlocker({
10+
shouldBlockFn: ({ next }) => {
11+
if (next.fullPath === '/editing-b' && input.value.length > 0) {
12+
return true
13+
}
14+
return false
15+
},
16+
withResolver: true,
17+
})
18+
19+
return () => (
20+
<div>
21+
<h1>Editing A</h1>
22+
<label>
23+
Enter your name:
24+
<input
25+
name="input"
26+
value={input.value}
27+
onInput={(e) =>
28+
(input.value = (e.target as HTMLInputElement).value)
29+
}
30+
/>
31+
</label>
32+
<button onClick={() => navigate({ to: '/editing-b' })}>
33+
Go to next step
34+
</button>
35+
{blocker.value.status === 'blocked' && (
36+
<button onClick={() => blocker.value.proceed?.()}>Proceed</button>
37+
)}
38+
</div>
39+
)
40+
},
41+
})
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ref, toValue, defineComponent } from 'vue'
2+
import { useBlocker, useNavigate } from '@tanstack/vue-router'
3+
4+
export const EditingBComponent = defineComponent({
5+
setup() {
6+
const navigate = useNavigate()
7+
const input = ref('')
8+
9+
const blocker = useBlocker({
10+
shouldBlockFn: () => !!toValue(input),
11+
withResolver: true,
12+
})
13+
14+
return () => (
15+
<div>
16+
<h1>Editing B</h1>
17+
<label>
18+
Enter your name:
19+
<input
20+
name="input"
21+
value={input.value}
22+
onInput={(e) =>
23+
(input.value = (e.target as HTMLInputElement).value)
24+
}
25+
/>
26+
</label>
27+
<button onClick={() => navigate({ to: '/editing-a' })}>Go back</button>
28+
{blocker.value.status === 'blocked' && (
29+
<button onClick={() => blocker.value.proceed?.()}>Proceed</button>
30+
)}
31+
</div>
32+
)
33+
},
34+
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script setup lang="ts">
2+
import { Link } from '@tanstack/vue-router'
3+
</script>
4+
5+
<template>
6+
<div>
7+
<p>This is the notFoundComponent configured on root route</p>
8+
<Link to="/">Start Over</Link>
9+
</div>
10+
</template>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { ref, onMounted, defineComponent } from 'vue'
2+
import { useSearch, useNavigate } from '@tanstack/vue-router'
3+
4+
export const NotRemountDepsComponent = defineComponent({
5+
setup() {
6+
// Component-scoped ref - will be recreated on component remount
7+
const mounts = ref(0)
8+
const search = useSearch({ from: '/notRemountDeps' })
9+
const navigate = useNavigate()
10+
11+
onMounted(() => {
12+
mounts.value++
13+
})
14+
15+
return () => (
16+
<div class="p-2">
17+
<button
18+
onClick={() =>
19+
navigate({
20+
to: '/notRemountDeps',
21+
search: {
22+
searchParam: Math.random().toString(36).substring(2, 8),
23+
},
24+
})
25+
}
26+
>
27+
Regenerate search param
28+
</button>
29+
30+
<div>Search: {search.value.searchParam}</div>
31+
<div data-testid="component-mounts">
32+
Page component mounts: {mounts.value}
33+
</div>
34+
</div>
35+
)
36+
},
37+
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script setup lang="ts">
2+
import { ErrorComponent } from '@tanstack/vue-router'
3+
import type { ErrorComponentProps } from '@tanstack/vue-router'
4+
5+
defineProps<ErrorComponentProps>()
6+
</script>
7+
8+
<template>
9+
<ErrorComponent :error="error" />
10+
</template>

0 commit comments

Comments
 (0)