@tanstack/router-vite-plugin 1.24.1 → 1.26.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/compilers.cjs +335 -0
- package/dist/cjs/compilers.cjs.map +1 -0
- package/dist/cjs/compilers.d.cts +38 -0
- package/dist/cjs/constants.cjs +5 -0
- package/dist/cjs/constants.cjs.map +1 -0
- package/dist/cjs/constants.d.cts +1 -0
- package/dist/cjs/eliminateUnreferencedIdentifiers.cjs +144 -0
- package/dist/cjs/eliminateUnreferencedIdentifiers.cjs.map +1 -0
- package/dist/cjs/eliminateUnreferencedIdentifiers.d.cts +8 -0
- package/dist/cjs/index.cjs +103 -8
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +55 -2
- package/dist/esm/compilers.d.ts +38 -0
- package/dist/esm/compilers.js +316 -0
- package/dist/esm/compilers.js.map +1 -0
- package/dist/esm/constants.d.ts +1 -0
- package/dist/esm/constants.js +5 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/eliminateUnreferencedIdentifiers.d.ts +8 -0
- package/dist/esm/eliminateUnreferencedIdentifiers.js +127 -0
- package/dist/esm/eliminateUnreferencedIdentifiers.js.map +1 -0
- package/dist/esm/index.d.ts +55 -2
- package/dist/esm/index.js +103 -8
- package/dist/esm/index.js.map +1 -1
- package/package.json +18 -1
- package/src/compilers.ts +420 -0
- package/src/constants.ts +1 -0
- package/src/eliminateUnreferencedIdentifiers.ts +287 -0
- package/src/index.ts +167 -8
- package/src/tests/index.test.ts +60 -0
- package/src/tests/shared/imported.tsx +11 -0
- package/src/tests/snapshots/function-declaration.tsx +10 -0
- package/src/tests/snapshots/function-declaration?split.tsx +29 -0
- package/src/tests/snapshots/imported.tsx +10 -0
- package/src/tests/snapshots/imported?split.tsx +5 -0
- package/src/tests/snapshots/inline.tsx +8 -0
- package/src/tests/snapshots/inline?split.tsx +18 -0
- package/src/tests/snapshots/random-number.tsx +11 -0
- package/src/tests/snapshots/random-number?split.tsx +27 -0
- package/src/tests/test-files/function-declaration.tsx +39 -0
- package/src/tests/test-files/imported.tsx +8 -0
- package/src/tests/test-files/inline.tsx +25 -0
- package/src/tests/test-files/random-number.tsx +83 -0
package/src/index.ts
CHANGED
|
@@ -1,11 +1,48 @@
|
|
|
1
1
|
import { isAbsolute, join, normalize } from 'path'
|
|
2
|
-
import {
|
|
2
|
+
import { fileURLToPath, pathToFileURL } from 'url'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
import {
|
|
5
|
+
generator,
|
|
6
|
+
configSchema as generatorConfigSchema,
|
|
7
|
+
getConfig as getGeneratorConfig,
|
|
8
|
+
} from '@tanstack/router-generator'
|
|
9
|
+
import { compileFile, makeCompile, splitFile } from './compilers'
|
|
10
|
+
import { splitPrefix } from './constants'
|
|
3
11
|
import type { Plugin } from 'vite'
|
|
4
12
|
|
|
13
|
+
export const configSchema = generatorConfigSchema.extend({
|
|
14
|
+
enableRouteGeneration: z.boolean().optional(),
|
|
15
|
+
experimental: z
|
|
16
|
+
.object({
|
|
17
|
+
enableCodeSplitting: z.boolean().optional(),
|
|
18
|
+
})
|
|
19
|
+
.optional(),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export type Config = z.infer<typeof configSchema>
|
|
23
|
+
|
|
5
24
|
const CONFIG_FILE_NAME = 'tsr.config.json'
|
|
25
|
+
const debug = false as any
|
|
26
|
+
|
|
27
|
+
const getConfig = async (inlineConfig: Partial<Config>, root: string) => {
|
|
28
|
+
const config = await getGeneratorConfig(inlineConfig, root)
|
|
29
|
+
|
|
30
|
+
return configSchema.parse({ ...inlineConfig, ...config })
|
|
31
|
+
}
|
|
6
32
|
|
|
7
|
-
export function TanStackRouterVite(
|
|
8
|
-
|
|
33
|
+
export function TanStackRouterVite(
|
|
34
|
+
inlineConfig: Partial<Config> = {},
|
|
35
|
+
): Array<Plugin> {
|
|
36
|
+
return [
|
|
37
|
+
TanStackRouterViteGenerator(inlineConfig),
|
|
38
|
+
TanStackRouterViteCodeSplitter(inlineConfig),
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function TanStackRouterViteGenerator(
|
|
43
|
+
inlineConfig: Partial<Config> = {},
|
|
44
|
+
): Plugin {
|
|
45
|
+
let ROOT: string = process.cwd()
|
|
9
46
|
let userConfig: Config
|
|
10
47
|
|
|
11
48
|
const generate = async () => {
|
|
@@ -32,15 +69,137 @@ export function TanStackRouterVite(inlineConfig: Partial<Config> = {}): Plugin {
|
|
|
32
69
|
}
|
|
33
70
|
|
|
34
71
|
return {
|
|
35
|
-
name: 'vite-plugin-tanstack-router',
|
|
36
|
-
configResolved: async () => {
|
|
72
|
+
name: 'vite-plugin-tanstack-router-generator',
|
|
73
|
+
configResolved: async (config) => {
|
|
74
|
+
ROOT = config.root
|
|
37
75
|
userConfig = await getConfig(inlineConfig, ROOT)
|
|
38
|
-
|
|
76
|
+
|
|
77
|
+
if (userConfig.enableRouteGeneration ?? true) {
|
|
78
|
+
await generate()
|
|
79
|
+
}
|
|
39
80
|
},
|
|
40
81
|
watchChange: async (file, context) => {
|
|
41
|
-
if (
|
|
42
|
-
|
|
82
|
+
if (userConfig.enableRouteGeneration ?? true) {
|
|
83
|
+
if (['create', 'update', 'delete'].includes(context.event)) {
|
|
84
|
+
await handleFile(file)
|
|
85
|
+
}
|
|
43
86
|
}
|
|
44
87
|
},
|
|
45
88
|
}
|
|
46
89
|
}
|
|
90
|
+
|
|
91
|
+
function fileIsInRoutesDirectory(filePath: string, routesDirectory: string) {
|
|
92
|
+
const routesDirectoryPath = isAbsolute(routesDirectory)
|
|
93
|
+
? routesDirectory
|
|
94
|
+
: join(process.cwd(), routesDirectory)
|
|
95
|
+
|
|
96
|
+
return filePath.startsWith(routesDirectoryPath)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function TanStackRouterViteCodeSplitter(
|
|
100
|
+
inlineConfig: Partial<Config> = {},
|
|
101
|
+
): Plugin {
|
|
102
|
+
let ROOT: string = process.cwd()
|
|
103
|
+
let userConfig: Config
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
name: 'vite-plugin-tanstack-router-code-splitter',
|
|
107
|
+
enforce: 'pre',
|
|
108
|
+
configResolved: async (config) => {
|
|
109
|
+
ROOT = config.root
|
|
110
|
+
userConfig = await getConfig(inlineConfig, ROOT)
|
|
111
|
+
},
|
|
112
|
+
resolveId(source) {
|
|
113
|
+
if (!userConfig.experimental?.enableCodeSplitting) {
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (source.startsWith(splitPrefix + ':')) {
|
|
118
|
+
return source.replace(splitPrefix + ':', '')
|
|
119
|
+
}
|
|
120
|
+
return null
|
|
121
|
+
},
|
|
122
|
+
async transform(code, id, transformOptions) {
|
|
123
|
+
if (!userConfig.experimental?.enableCodeSplitting) {
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const url = pathToFileURL(id)
|
|
128
|
+
url.searchParams.delete('v')
|
|
129
|
+
id = fileURLToPath(url).replace(/\\/g, '/')
|
|
130
|
+
|
|
131
|
+
const compile = makeCompile({
|
|
132
|
+
root: ROOT,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
if (id.includes(splitPrefix)) {
|
|
136
|
+
if (debug) console.info('Splitting route: ', id)
|
|
137
|
+
// const ref = new URLSearchParams(id.split('?')[1]).get('ref') || ''
|
|
138
|
+
|
|
139
|
+
const compiled = await splitFile({
|
|
140
|
+
code,
|
|
141
|
+
compile,
|
|
142
|
+
filename: id,
|
|
143
|
+
// ref,
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
if (debug) console.info('')
|
|
147
|
+
if (debug) console.info('Split Output')
|
|
148
|
+
if (debug) console.info('')
|
|
149
|
+
if (debug) console.info(compiled.code)
|
|
150
|
+
if (debug) console.info('')
|
|
151
|
+
if (debug) console.info('')
|
|
152
|
+
if (debug) console.info('')
|
|
153
|
+
if (debug) console.info('')
|
|
154
|
+
if (debug) console.info('')
|
|
155
|
+
if (debug) console.info('')
|
|
156
|
+
if (debug) console.info('')
|
|
157
|
+
if (debug) console.info('')
|
|
158
|
+
|
|
159
|
+
return compiled
|
|
160
|
+
} else if (
|
|
161
|
+
fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&
|
|
162
|
+
(code.includes('createRoute(') || code.includes('createFileRoute('))
|
|
163
|
+
) {
|
|
164
|
+
if (code.includes('@react-refresh')) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`We detected that the '@vitejs/plugin-react' was passed before '@tanstack/router-vite-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again:
|
|
167
|
+
e.g.
|
|
168
|
+
|
|
169
|
+
plugins: [
|
|
170
|
+
TanStackRouterVite(), // Place this before viteReact()
|
|
171
|
+
viteReact(),
|
|
172
|
+
]
|
|
173
|
+
`,
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (debug) console.info('Handling createRoute: ', id)
|
|
178
|
+
const compiled = await compileFile({
|
|
179
|
+
code,
|
|
180
|
+
compile,
|
|
181
|
+
filename: id,
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
if (debug) console.info('')
|
|
185
|
+
if (debug) console.info('Compiled Output')
|
|
186
|
+
if (debug) console.info('')
|
|
187
|
+
if (debug) console.info(compiled.code)
|
|
188
|
+
if (debug) console.info('')
|
|
189
|
+
if (debug) console.info('')
|
|
190
|
+
if (debug) console.info('')
|
|
191
|
+
if (debug) console.info('')
|
|
192
|
+
if (debug) console.info('')
|
|
193
|
+
if (debug) console.info('')
|
|
194
|
+
if (debug) console.info('')
|
|
195
|
+
if (debug) console.info('')
|
|
196
|
+
if (debug) console.info('')
|
|
197
|
+
if (debug) console.info('')
|
|
198
|
+
|
|
199
|
+
return compiled
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return null
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readFile, readdir } from 'fs/promises'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { expect, test } from 'vitest'
|
|
4
|
+
import { compileFile, makeCompile, splitFile } from '../compilers'
|
|
5
|
+
import { splitPrefix } from '../constants'
|
|
6
|
+
|
|
7
|
+
test('it compiles and splits', async () => {
|
|
8
|
+
// get the list of files from the /test-files directory
|
|
9
|
+
const files = await readdir(path.resolve(__dirname, './test-files'))
|
|
10
|
+
for (const file of files) {
|
|
11
|
+
console.log('Testing:', file)
|
|
12
|
+
await compileTestFile({ file })
|
|
13
|
+
await splitTestFile({ file })
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
async function compileTestFile(opts: { file: string }) {
|
|
18
|
+
const code = (
|
|
19
|
+
await readFile(path.resolve(__dirname, `./test-files/${opts.file}`))
|
|
20
|
+
).toString()
|
|
21
|
+
|
|
22
|
+
// console.log('Compiling...')
|
|
23
|
+
// console.log('⬇️⬇️⬇️⬇️⬇️')
|
|
24
|
+
// console.log()
|
|
25
|
+
const result = await compileFile({
|
|
26
|
+
code,
|
|
27
|
+
compile: makeCompile({
|
|
28
|
+
root: path.resolve(__dirname, './test-files'),
|
|
29
|
+
}),
|
|
30
|
+
filename: `${opts.file}`,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// console.log(result.code)
|
|
34
|
+
// console.log()
|
|
35
|
+
|
|
36
|
+
await expect(result.code).toMatchFileSnapshot(`./snapshots/${opts.file}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function splitTestFile(opts: { file: string }) {
|
|
40
|
+
const code = (
|
|
41
|
+
await readFile(path.resolve(__dirname, `./test-files/${opts.file}`))
|
|
42
|
+
).toString()
|
|
43
|
+
|
|
44
|
+
// console.log('Splitting...')
|
|
45
|
+
// console.log('⬇️⬇️⬇️⬇️⬇️')
|
|
46
|
+
// console.log()
|
|
47
|
+
const result = await splitFile({
|
|
48
|
+
code,
|
|
49
|
+
compile: makeCompile({
|
|
50
|
+
root: path.resolve(__dirname, './test-files'),
|
|
51
|
+
}),
|
|
52
|
+
filename: `${opts.file}?${splitPrefix}`,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// console.log(result.code)
|
|
56
|
+
// console.log()
|
|
57
|
+
await expect(result.code).toMatchFileSnapshot(
|
|
58
|
+
`./snapshots/${opts.file.replace('.tsx', '')}?split.tsx`,
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { lazyRouteComponent } from '@tanstack/react-router';
|
|
2
|
+
const $$splitComponentImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/function-declaration.tsx?tsr-split');
|
|
3
|
+
import { lazyFn } from '@tanstack/react-router';
|
|
4
|
+
const $$splitLoaderImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/function-declaration.tsx?tsr-split');
|
|
5
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
6
|
+
import '../posts';
|
|
7
|
+
export const Route = createFileRoute('/posts')({
|
|
8
|
+
loader: lazyFn($$splitLoaderImporter, 'loader'),
|
|
9
|
+
component: lazyRouteComponent($$splitComponentImporter, 'component')
|
|
10
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Link, Outlet } from '@tanstack/react-router';
|
|
2
|
+
import { fetchPosts } from '../posts';
|
|
3
|
+
import { Route } from "function-declaration.tsx";
|
|
4
|
+
const component = function PostsComponent() {
|
|
5
|
+
const posts = Route.useLoaderData();
|
|
6
|
+
return <div className="p-2 flex gap-2">
|
|
7
|
+
<ul className="list-disc pl-4">
|
|
8
|
+
{[...posts, {
|
|
9
|
+
id: 'i-do-not-exist',
|
|
10
|
+
title: 'Non-existent Post'
|
|
11
|
+
}]?.map(post => {
|
|
12
|
+
return <li key={post.id} className="whitespace-nowrap">
|
|
13
|
+
<Link to="/posts/$postId" params={{
|
|
14
|
+
postId: post.id
|
|
15
|
+
}} className="block py-1 text-blue-800 hover:text-blue-600" activeProps={{
|
|
16
|
+
className: 'text-black font-bold'
|
|
17
|
+
}}>
|
|
18
|
+
<div>{post.title.substring(0, 20)}</div>
|
|
19
|
+
</Link>
|
|
20
|
+
</li>;
|
|
21
|
+
})}
|
|
22
|
+
</ul>
|
|
23
|
+
<hr />
|
|
24
|
+
<Outlet />
|
|
25
|
+
</div>;
|
|
26
|
+
};
|
|
27
|
+
export { component };
|
|
28
|
+
const loader = fetchPosts;
|
|
29
|
+
export { loader };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { lazyFn } from '@tanstack/react-router';
|
|
2
|
+
const $$splitLoaderImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/imported.tsx?tsr-split');
|
|
3
|
+
import { lazyRouteComponent } from '@tanstack/react-router';
|
|
4
|
+
const $$splitComponentImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/imported.tsx?tsr-split');
|
|
5
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
6
|
+
import '../shared/imported';
|
|
7
|
+
export const Route = createFileRoute('/')({
|
|
8
|
+
component: lazyRouteComponent($$splitComponentImporter, 'component'),
|
|
9
|
+
loader: lazyFn($$splitLoaderImporter, 'loader')
|
|
10
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { lazyRouteComponent } from '@tanstack/react-router';
|
|
2
|
+
const $$splitComponentImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/inline.tsx?tsr-split');
|
|
3
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
4
|
+
export const Route = createFileRoute('/')({
|
|
5
|
+
component: lazyRouteComponent($$splitComponentImporter, 'component')
|
|
6
|
+
});
|
|
7
|
+
Route.addChildren([]);
|
|
8
|
+
export const test = 'test';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as styles from '../style.css';
|
|
2
|
+
import { TEST_DATA } from '../test.const';
|
|
3
|
+
const Button = (props: {
|
|
4
|
+
children: any;
|
|
5
|
+
}) => {
|
|
6
|
+
return <button>{props.children}</button>;
|
|
7
|
+
};
|
|
8
|
+
import { Route } from "inline.tsx";
|
|
9
|
+
Route.addChildren([]);
|
|
10
|
+
import { test } from "inline.tsx";
|
|
11
|
+
const component = () => {
|
|
12
|
+
return <div className="p-2">
|
|
13
|
+
{test}
|
|
14
|
+
<h3 className={styles.indexPageTitle}>{TEST_DATA.welcome}</h3>
|
|
15
|
+
<Button>Click me</Button>
|
|
16
|
+
</div>;
|
|
17
|
+
};
|
|
18
|
+
export { component };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { lazyRouteComponent } from '@tanstack/react-router';
|
|
2
|
+
const $$splitComponentImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/random-number.tsx?tsr-split');
|
|
3
|
+
import { lazyFn } from '@tanstack/react-router';
|
|
4
|
+
const $$splitLoaderImporter = () => import('tsr-split:/Users/tannerlinsley/GitHub/router/packages/router-vite-plugin/random-number.tsx?tsr-split');
|
|
5
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
6
|
+
export const textColors = [`text-rose-500`, `text-yellow-500`, `text-teal-500`, `text-blue-500`];
|
|
7
|
+
export const gradients = [`from-rose-500 to-yellow-500`, `from-yellow-500 to-teal-500`, `from-teal-500 to-violet-500`, `from-blue-500 to-pink-500`];
|
|
8
|
+
export const Route = createFileRoute('/')({
|
|
9
|
+
loader: lazyFn($$splitLoaderImporter, 'loader'),
|
|
10
|
+
component: lazyRouteComponent($$splitComponentImporter, 'component')
|
|
11
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defer } from '@tanstack/react-router';
|
|
2
|
+
import { getSponsorsForSponsorPack } from '~/server/sponsors';
|
|
3
|
+
import discordImage from '~/images/discord-logo-white.svg';
|
|
4
|
+
import { sample } from '~/utils/utils';
|
|
5
|
+
import { textColors } from "random-number.tsx";
|
|
6
|
+
import { gradients } from "random-number.tsx";
|
|
7
|
+
import { Route } from "random-number.tsx";
|
|
8
|
+
const component = function Index() {
|
|
9
|
+
const {
|
|
10
|
+
randomNumber
|
|
11
|
+
} = Route.useLoaderData();
|
|
12
|
+
const gradient = sample(gradients, randomNumber);
|
|
13
|
+
const textColor = sample(textColors, randomNumber);
|
|
14
|
+
return <>
|
|
15
|
+
{discordImage}
|
|
16
|
+
{gradient}
|
|
17
|
+
{textColor}
|
|
18
|
+
</>;
|
|
19
|
+
};
|
|
20
|
+
export { component };
|
|
21
|
+
const loader = () => {
|
|
22
|
+
return {
|
|
23
|
+
randomNumber: Math.random(),
|
|
24
|
+
sponsorsPromise: defer(getSponsorsForSponsorPack())
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export { loader };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { createFileRoute, Link, Outlet } from '@tanstack/react-router'
|
|
3
|
+
import { fetchPosts } from '../posts'
|
|
4
|
+
|
|
5
|
+
export const Route = createFileRoute('/posts')({
|
|
6
|
+
loader: fetchPosts,
|
|
7
|
+
component: PostsComponent,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
function PostsComponent() {
|
|
11
|
+
const posts = Route.useLoaderData()
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div className="p-2 flex gap-2">
|
|
15
|
+
<ul className="list-disc pl-4">
|
|
16
|
+
{[...posts, { id: 'i-do-not-exist', title: 'Non-existent Post' }]?.map(
|
|
17
|
+
(post) => {
|
|
18
|
+
return (
|
|
19
|
+
<li key={post.id} className="whitespace-nowrap">
|
|
20
|
+
<Link
|
|
21
|
+
to="/posts/$postId"
|
|
22
|
+
params={{
|
|
23
|
+
postId: post.id,
|
|
24
|
+
}}
|
|
25
|
+
className="block py-1 text-blue-800 hover:text-blue-600"
|
|
26
|
+
activeProps={{ className: 'text-black font-bold' }}
|
|
27
|
+
>
|
|
28
|
+
<div>{post.title.substring(0, 20)}</div>
|
|
29
|
+
</Link>
|
|
30
|
+
</li>
|
|
31
|
+
)
|
|
32
|
+
},
|
|
33
|
+
)}
|
|
34
|
+
</ul>
|
|
35
|
+
<hr />
|
|
36
|
+
<Outlet />
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
3
|
+
|
|
4
|
+
import * as styles from '../style.css'
|
|
5
|
+
import { TEST_DATA } from '../test.const'
|
|
6
|
+
|
|
7
|
+
const Button = (props: { children: any }) => {
|
|
8
|
+
return <button>{props.children}</button>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Route = createFileRoute('/')({
|
|
12
|
+
component: () => {
|
|
13
|
+
return (
|
|
14
|
+
<div className="p-2">
|
|
15
|
+
{test}
|
|
16
|
+
<h3 className={styles.indexPageTitle}>{TEST_DATA.welcome}</h3>
|
|
17
|
+
<Button>Click me</Button>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
Route.addChildren([])
|
|
24
|
+
|
|
25
|
+
export const test = 'test'
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Await, Link, createFileRoute, defer } from '@tanstack/react-router'
|
|
2
|
+
import { Carbon } from '~/components/Carbon'
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
4
|
+
import { FaDiscord, FaGithub, FaTshirt } from 'react-icons/fa'
|
|
5
|
+
import { CgMusicSpeaker, CgSpinner } from 'react-icons/cg'
|
|
6
|
+
import { Footer } from '~/components/Footer'
|
|
7
|
+
import SponsorPack from '~/components/SponsorPack'
|
|
8
|
+
import { LogoColor } from '~/components/LogoColor'
|
|
9
|
+
import { getSponsorsForSponsorPack } from '~/server/sponsors'
|
|
10
|
+
import discordImage from '~/images/discord-logo-white.svg'
|
|
11
|
+
import agGridImage from '~/images/ag-grid.png'
|
|
12
|
+
import nozzleImage from '~/images/nozzle.png'
|
|
13
|
+
import bytesImage from '~/images/bytes.svg'
|
|
14
|
+
import bytesUidotdevImage from '~/images/bytes-uidotdev.png'
|
|
15
|
+
import { useMutation } from '~/hooks/useMutation'
|
|
16
|
+
import { sample } from '~/utils/utils'
|
|
17
|
+
|
|
18
|
+
export const textColors = [
|
|
19
|
+
`text-rose-500`,
|
|
20
|
+
`text-yellow-500`,
|
|
21
|
+
`text-teal-500`,
|
|
22
|
+
`text-blue-500`,
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
export const gradients = [
|
|
26
|
+
`from-rose-500 to-yellow-500`,
|
|
27
|
+
`from-yellow-500 to-teal-500`,
|
|
28
|
+
`from-teal-500 to-violet-500`,
|
|
29
|
+
`from-blue-500 to-pink-500`,
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const courses = [
|
|
33
|
+
{
|
|
34
|
+
name: 'The Official TanStack React Query Course',
|
|
35
|
+
cardStyles: `border-t-4 border-red-500 hover:(border-green-500)`,
|
|
36
|
+
href: 'https://query.gg/?s=tanstack',
|
|
37
|
+
description: `Learn how to build enterprise quality apps with TanStack's React Query the easy way with our brand new course.`,
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
export const Route = createFileRoute('/')({
|
|
42
|
+
loader: () => {
|
|
43
|
+
return {
|
|
44
|
+
randomNumber: Math.random(),
|
|
45
|
+
sponsorsPromise: defer(getSponsorsForSponsorPack()),
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
component: Index,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
async function bytesSignupServerFn({ email }: { email: string }) {
|
|
52
|
+
'use server'
|
|
53
|
+
|
|
54
|
+
return fetch(`https://bytes.dev/api/bytes-optin-cors`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
email,
|
|
58
|
+
influencer: 'tanstack',
|
|
59
|
+
}),
|
|
60
|
+
headers: {
|
|
61
|
+
Accept: 'application/json',
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function Index() {
|
|
68
|
+
const bytesSignupMutation = useMutation({
|
|
69
|
+
fn: bytesSignupServerFn,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const { sponsorsPromise, randomNumber, testing2 } = Route.useLoaderData()
|
|
73
|
+
const gradient = sample(gradients, randomNumber)
|
|
74
|
+
const textColor = sample(textColors, randomNumber)
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<>
|
|
78
|
+
{discordImage}
|
|
79
|
+
{gradient}
|
|
80
|
+
{textColor}
|
|
81
|
+
</>
|
|
82
|
+
)
|
|
83
|
+
}
|