@tanstack/router-plugin 1.20.3-alpha.1

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.
Files changed (122) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -0
  3. package/dist/cjs/core/code-splitter/compilers.cjs +755 -0
  4. package/dist/cjs/core/code-splitter/compilers.cjs.map +1 -0
  5. package/dist/cjs/core/code-splitter/compilers.d.cts +22 -0
  6. package/dist/cjs/core/code-splitter/framework-options.cjs +34 -0
  7. package/dist/cjs/core/code-splitter/framework-options.cjs.map +1 -0
  8. package/dist/cjs/core/code-splitter/framework-options.d.cts +10 -0
  9. package/dist/cjs/core/code-splitter/path-ids.cjs +37 -0
  10. package/dist/cjs/core/code-splitter/path-ids.cjs.map +1 -0
  11. package/dist/cjs/core/code-splitter/path-ids.d.cts +2 -0
  12. package/dist/cjs/core/config.cjs +46 -0
  13. package/dist/cjs/core/config.cjs.map +1 -0
  14. package/dist/cjs/core/config.d.cts +160 -0
  15. package/dist/cjs/core/constants.cjs +19 -0
  16. package/dist/cjs/core/constants.cjs.map +1 -0
  17. package/dist/cjs/core/constants.d.cts +5 -0
  18. package/dist/cjs/core/route-autoimport-plugin.cjs +98 -0
  19. package/dist/cjs/core/route-autoimport-plugin.cjs.map +1 -0
  20. package/dist/cjs/core/route-autoimport-plugin.d.cts +6 -0
  21. package/dist/cjs/core/route-hmr-statement.cjs +33 -0
  22. package/dist/cjs/core/route-hmr-statement.cjs.map +1 -0
  23. package/dist/cjs/core/route-hmr-statement.d.cts +1 -0
  24. package/dist/cjs/core/router-code-splitter-plugin.cjs +173 -0
  25. package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -0
  26. package/dist/cjs/core/router-code-splitter-plugin.d.cts +3 -0
  27. package/dist/cjs/core/router-composed-plugin.cjs +27 -0
  28. package/dist/cjs/core/router-composed-plugin.cjs.map +1 -0
  29. package/dist/cjs/core/router-composed-plugin.d.cts +3 -0
  30. package/dist/cjs/core/router-generator-plugin.cjs +145 -0
  31. package/dist/cjs/core/router-generator-plugin.cjs.map +1 -0
  32. package/dist/cjs/core/router-generator-plugin.d.cts +3 -0
  33. package/dist/cjs/core/router-hmr-plugin.cjs +51 -0
  34. package/dist/cjs/core/router-hmr-plugin.cjs.map +1 -0
  35. package/dist/cjs/core/router-hmr-plugin.d.cts +8 -0
  36. package/dist/cjs/core/utils.cjs +12 -0
  37. package/dist/cjs/core/utils.cjs.map +1 -0
  38. package/dist/cjs/core/utils.d.cts +2 -0
  39. package/dist/cjs/esbuild.cjs +20 -0
  40. package/dist/cjs/esbuild.cjs.map +1 -0
  41. package/dist/cjs/esbuild.d.cts +127 -0
  42. package/dist/cjs/index.cjs +9 -0
  43. package/dist/cjs/index.cjs.map +1 -0
  44. package/dist/cjs/index.d.cts +4 -0
  45. package/dist/cjs/rspack.cjs +22 -0
  46. package/dist/cjs/rspack.cjs.map +1 -0
  47. package/dist/cjs/rspack.d.cts +139 -0
  48. package/dist/cjs/vite.cjs +22 -0
  49. package/dist/cjs/vite.cjs.map +1 -0
  50. package/dist/cjs/vite.d.cts +159 -0
  51. package/dist/cjs/webpack.cjs +22 -0
  52. package/dist/cjs/webpack.cjs.map +1 -0
  53. package/dist/cjs/webpack.d.cts +127 -0
  54. package/dist/esm/core/code-splitter/compilers.d.ts +22 -0
  55. package/dist/esm/core/code-splitter/compilers.js +737 -0
  56. package/dist/esm/core/code-splitter/compilers.js.map +1 -0
  57. package/dist/esm/core/code-splitter/framework-options.d.ts +10 -0
  58. package/dist/esm/core/code-splitter/framework-options.js +34 -0
  59. package/dist/esm/core/code-splitter/framework-options.js.map +1 -0
  60. package/dist/esm/core/code-splitter/path-ids.d.ts +2 -0
  61. package/dist/esm/core/code-splitter/path-ids.js +37 -0
  62. package/dist/esm/core/code-splitter/path-ids.js.map +1 -0
  63. package/dist/esm/core/config.d.ts +160 -0
  64. package/dist/esm/core/config.js +46 -0
  65. package/dist/esm/core/config.js.map +1 -0
  66. package/dist/esm/core/constants.d.ts +5 -0
  67. package/dist/esm/core/constants.js +19 -0
  68. package/dist/esm/core/constants.js.map +1 -0
  69. package/dist/esm/core/route-autoimport-plugin.d.ts +6 -0
  70. package/dist/esm/core/route-autoimport-plugin.js +81 -0
  71. package/dist/esm/core/route-autoimport-plugin.js.map +1 -0
  72. package/dist/esm/core/route-hmr-statement.d.ts +1 -0
  73. package/dist/esm/core/route-hmr-statement.js +16 -0
  74. package/dist/esm/core/route-hmr-statement.js.map +1 -0
  75. package/dist/esm/core/router-code-splitter-plugin.d.ts +3 -0
  76. package/dist/esm/core/router-code-splitter-plugin.js +173 -0
  77. package/dist/esm/core/router-code-splitter-plugin.js.map +1 -0
  78. package/dist/esm/core/router-composed-plugin.d.ts +3 -0
  79. package/dist/esm/core/router-composed-plugin.js +27 -0
  80. package/dist/esm/core/router-composed-plugin.js.map +1 -0
  81. package/dist/esm/core/router-generator-plugin.d.ts +3 -0
  82. package/dist/esm/core/router-generator-plugin.js +123 -0
  83. package/dist/esm/core/router-generator-plugin.js.map +1 -0
  84. package/dist/esm/core/router-hmr-plugin.d.ts +8 -0
  85. package/dist/esm/core/router-hmr-plugin.js +51 -0
  86. package/dist/esm/core/router-hmr-plugin.js.map +1 -0
  87. package/dist/esm/core/utils.d.ts +2 -0
  88. package/dist/esm/core/utils.js +12 -0
  89. package/dist/esm/core/utils.js.map +1 -0
  90. package/dist/esm/esbuild.d.ts +127 -0
  91. package/dist/esm/esbuild.js +20 -0
  92. package/dist/esm/esbuild.js.map +1 -0
  93. package/dist/esm/index.d.ts +4 -0
  94. package/dist/esm/index.js +9 -0
  95. package/dist/esm/index.js.map +1 -0
  96. package/dist/esm/rspack.d.ts +139 -0
  97. package/dist/esm/rspack.js +22 -0
  98. package/dist/esm/rspack.js.map +1 -0
  99. package/dist/esm/vite.d.ts +159 -0
  100. package/dist/esm/vite.js +22 -0
  101. package/dist/esm/vite.js.map +1 -0
  102. package/dist/esm/webpack.d.ts +127 -0
  103. package/dist/esm/webpack.js +22 -0
  104. package/dist/esm/webpack.js.map +1 -0
  105. package/package.json +133 -0
  106. package/src/core/code-splitter/compilers.ts +1005 -0
  107. package/src/core/code-splitter/framework-options.ts +41 -0
  108. package/src/core/code-splitter/path-ids.ts +39 -0
  109. package/src/core/config.ts +80 -0
  110. package/src/core/constants.ts +17 -0
  111. package/src/core/route-autoimport-plugin.ts +102 -0
  112. package/src/core/route-hmr-statement.ts +13 -0
  113. package/src/core/router-code-splitter-plugin.ts +253 -0
  114. package/src/core/router-composed-plugin.ts +32 -0
  115. package/src/core/router-generator-plugin.ts +172 -0
  116. package/src/core/router-hmr-plugin.ts +65 -0
  117. package/src/core/utils.ts +18 -0
  118. package/src/esbuild.ts +56 -0
  119. package/src/index.ts +4 -0
  120. package/src/rspack.ts +67 -0
  121. package/src/vite.ts +57 -0
  122. package/src/webpack.ts +55 -0
@@ -0,0 +1,41 @@
1
+ type FrameworkOptions = {
2
+ package: string
3
+ idents: {
4
+ createFileRoute: string
5
+ lazyFn: string
6
+ lazyRouteComponent: string
7
+ }
8
+ }
9
+
10
+ export function getFrameworkOptions(framework: string): FrameworkOptions {
11
+ let frameworkOptions: FrameworkOptions
12
+
13
+ switch (framework) {
14
+ case 'react':
15
+ frameworkOptions = {
16
+ package: '@tanstack/react-router',
17
+ idents: {
18
+ createFileRoute: 'createFileRoute',
19
+ lazyFn: 'lazyFn',
20
+ lazyRouteComponent: 'lazyRouteComponent',
21
+ },
22
+ }
23
+ break
24
+ case 'solid':
25
+ frameworkOptions = {
26
+ package: '@tanstack/solid-router',
27
+ idents: {
28
+ createFileRoute: 'createFileRoute',
29
+ lazyFn: 'lazyFn',
30
+ lazyRouteComponent: 'lazyRouteComponent',
31
+ },
32
+ }
33
+ break
34
+ default:
35
+ throw new Error(
36
+ `[getFrameworkOptions] - Unsupported framework: ${framework}`,
37
+ )
38
+ }
39
+
40
+ return frameworkOptions
41
+ }
@@ -0,0 +1,39 @@
1
+ export function createIdentifier(strings: Array<string>): string {
2
+ if (strings.length === 0) {
3
+ throw new Error('Cannot create an identifier from an empty array')
4
+ }
5
+
6
+ const sortedStrings = [...strings].sort()
7
+ const combinedString = sortedStrings.join('---') // Delimiter
8
+
9
+ // Replace unsafe characters
10
+ let safeString = combinedString.replace(/\//g, '--slash--')
11
+ safeString = safeString.replace(/\\/g, '--backslash--')
12
+ safeString = safeString.replace(/\?/g, '--question--')
13
+ safeString = safeString.replace(/%/g, '--percent--')
14
+ safeString = safeString.replace(/#/g, '--hash--')
15
+ safeString = safeString.replace(/\+/g, '--plus--')
16
+ safeString = safeString.replace(/=/g, '--equals--')
17
+ safeString = safeString.replace(/&/g, '--ampersand--')
18
+ safeString = safeString.replace(/\s/g, '_') // Replace spaces with underscores
19
+
20
+ return safeString
21
+ }
22
+
23
+ export function decodeIdentifier(identifier: string): Array<string> {
24
+ if (!identifier) {
25
+ return []
26
+ }
27
+
28
+ let combinedString = identifier.replace(/--slash--/g, '/')
29
+ combinedString = combinedString.replace(/--backslash--/g, '\\')
30
+ combinedString = combinedString.replace(/--question--/g, '?')
31
+ combinedString = combinedString.replace(/--percent--/g, '%')
32
+ combinedString = combinedString.replace(/--hash--/g, '#')
33
+ combinedString = combinedString.replace(/--plus--/g, '+')
34
+ combinedString = combinedString.replace(/--equals--/g, '=')
35
+ combinedString = combinedString.replace(/--ampersand--/g, '&')
36
+ combinedString = combinedString.replace(/_/g, ' ') // Restore spaces
37
+
38
+ return combinedString.split('---')
39
+ }
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod'
2
+ import {
3
+ configSchema as generatorConfigSchema,
4
+ getConfig as getGeneratorConfig,
5
+ } from '@tanstack/router-generator'
6
+ import type { RegisteredRouter, RouteIds } from '@tanstack/router-core'
7
+ import type { CodeSplitGroupings } from './constants'
8
+
9
+ export const splitGroupingsSchema = z
10
+ .array(
11
+ z.array(
12
+ z.union([
13
+ z.literal('loader'),
14
+ z.literal('component'),
15
+ z.literal('pendingComponent'),
16
+ z.literal('errorComponent'),
17
+ z.literal('notFoundComponent'),
18
+ ]),
19
+ ),
20
+ {
21
+ message:
22
+ " Must be an Array of Arrays containing the split groupings. i.e. [['component'], ['pendingComponent'], ['errorComponent', 'notFoundComponent']]",
23
+ },
24
+ )
25
+ .superRefine((val, ctx) => {
26
+ const flattened = val.flat()
27
+ const unique = [...new Set(flattened)]
28
+
29
+ // Elements must be unique,
30
+ // ie. this shouldn't be allows [['component'], ['component', 'loader']]
31
+ if (unique.length !== flattened.length) {
32
+ ctx.addIssue({
33
+ code: 'custom',
34
+ message:
35
+ " Split groupings must be unique and not repeated. i.e. i.e. [['component'], ['pendingComponent'], ['errorComponent', 'notFoundComponent']]." +
36
+ `\n You input was: ${JSON.stringify(val)}.`,
37
+ })
38
+ }
39
+ })
40
+
41
+ export type CodeSplittingOptions = {
42
+ /**
43
+ * Use this function to programmatically control the code splitting behavior
44
+ * based on the `routeId` for each route.
45
+ *
46
+ * If you just need to change the default behavior, you can use the `defaultBehavior` option.
47
+ * @param params
48
+ */
49
+ splitBehavior?: (params: {
50
+ routeId: RouteIds<RegisteredRouter['routeTree']>
51
+ }) => CodeSplitGroupings | undefined | void
52
+
53
+ /**
54
+ * The default/global configuration to control your code splitting behavior per route.
55
+ * @default [['component'],['pendingComponent'],['errorComponent'],['notFoundComponent']]
56
+ */
57
+ defaultBehavior?: CodeSplitGroupings
58
+ }
59
+
60
+ const codeSplittingOptionsSchema = z.object({
61
+ splitBehavior: z.function().optional(),
62
+ defaultBehavior: splitGroupingsSchema.optional(),
63
+ })
64
+
65
+ export const configSchema = generatorConfigSchema.extend({
66
+ enableRouteGeneration: z.boolean().optional(),
67
+ codeSplittingOptions: z
68
+ .custom<CodeSplittingOptions>((v) => {
69
+ return codeSplittingOptionsSchema.parse(v)
70
+ })
71
+ .optional(),
72
+ })
73
+
74
+ export const getConfig = (inlineConfig: Partial<Config>, root: string) => {
75
+ const config = getGeneratorConfig(inlineConfig, root)
76
+
77
+ return configSchema.parse({ ...config, ...inlineConfig })
78
+ }
79
+
80
+ export type Config = z.infer<typeof configSchema>
@@ -0,0 +1,17 @@
1
+ export const tsrSplit = 'tsr-split'
2
+
3
+ export const splitRouteIdentNodes = [
4
+ 'loader',
5
+ 'component',
6
+ 'pendingComponent',
7
+ 'errorComponent',
8
+ 'notFoundComponent',
9
+ ] as const
10
+ export type SplitRouteIdentNodes = (typeof splitRouteIdentNodes)[number]
11
+ export type CodeSplitGroupings = Array<Array<SplitRouteIdentNodes>>
12
+
13
+ export const defaultCodeSplitGroupings: CodeSplitGroupings = [
14
+ ['component'],
15
+ ['errorComponent'],
16
+ ['notFoundComponent'],
17
+ ]
@@ -0,0 +1,102 @@
1
+ import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'
2
+ import babel from '@babel/core'
3
+ import * as template from '@babel/template'
4
+ import { getConfig } from './config'
5
+ import { debug, fileIsInRoutesDirectory } from './utils'
6
+ import type { Config } from './config'
7
+ import type { UnpluginFactory } from 'unplugin'
8
+
9
+ /**
10
+ * This plugin adds imports for createFileRoute and createLazyFileRoute to the file route.
11
+ */
12
+ export const unpluginRouteAutoimportFactory: UnpluginFactory<
13
+ Partial<Config> | undefined
14
+ > = (options = {}) => {
15
+ let ROOT: string = process.cwd()
16
+ let userConfig = options as Config
17
+
18
+ return {
19
+ name: 'router-autoimport-plugin',
20
+ enforce: 'pre',
21
+
22
+ transform(code, id) {
23
+ let routeType: 'createFileRoute' | 'createLazyFileRoute'
24
+ if (code.includes('export const Route = createFileRoute(')) {
25
+ routeType = 'createFileRoute'
26
+ } else if (code.includes('export const Route = createLazyFileRoute(')) {
27
+ routeType = 'createLazyFileRoute'
28
+ } else {
29
+ return null
30
+ }
31
+
32
+ const routerImportPath = `@tanstack/${userConfig.target}-router`
33
+
34
+ const ast = parseAst({ code })
35
+
36
+ let isCreateRouteFunctionImported = false as boolean
37
+
38
+ babel.traverse(ast, {
39
+ Program: {
40
+ enter(programPath) {
41
+ programPath.traverse({
42
+ ImportDeclaration(path) {
43
+ const importedSpecifiers = path.node.specifiers.map(
44
+ (specifier) => specifier.local.name,
45
+ )
46
+ if (
47
+ importedSpecifiers.includes(routeType) &&
48
+ path.node.source.value === routerImportPath
49
+ ) {
50
+ isCreateRouteFunctionImported = true
51
+ }
52
+ },
53
+ })
54
+ },
55
+ },
56
+ })
57
+
58
+ if (!isCreateRouteFunctionImported) {
59
+ if (debug) console.info('Adding autoimports to route ', id)
60
+
61
+ const autoImportStatement = template.statement(
62
+ `import { ${routeType} } from '${routerImportPath}'`,
63
+ )()
64
+ ast.program.body.unshift(autoImportStatement)
65
+
66
+ const result = generateFromAst(ast, {
67
+ sourceMaps: true,
68
+ filename: id,
69
+ sourceFileName: id,
70
+ })
71
+ if (debug) {
72
+ logDiff(code, result.code)
73
+ console.log('Output:\n', result.code + '\n\n')
74
+ }
75
+ return result
76
+ }
77
+
78
+ return null
79
+ },
80
+
81
+ transformInclude(id) {
82
+ return fileIsInRoutesDirectory(id, userConfig.routesDirectory)
83
+ },
84
+
85
+ vite: {
86
+ configResolved(config) {
87
+ ROOT = config.root
88
+ userConfig = getConfig(options, ROOT)
89
+ },
90
+ },
91
+
92
+ rspack() {
93
+ ROOT = process.cwd()
94
+ userConfig = getConfig(options, ROOT)
95
+ },
96
+
97
+ webpack() {
98
+ ROOT = process.cwd()
99
+ userConfig = getConfig(options, ROOT)
100
+ },
101
+ }
102
+ }
@@ -0,0 +1,13 @@
1
+ import * as template from '@babel/template'
2
+
3
+ export const routeHmrStatement = template.statement(
4
+ `
5
+ if (import.meta.hot) {
6
+ import.meta.hot.accept((newModule) => {
7
+ if (newModule.Route && typeof newModule.Route.clone === 'function') {
8
+ newModule.Route.clone(Route)
9
+ }
10
+ })
11
+ }
12
+ `,
13
+ )()
@@ -0,0 +1,253 @@
1
+ /**
2
+ * It is important to familiarize yourself with how the code-splitting works in this plugin.
3
+ * https://github.com/TanStack/router/pull/3355
4
+ */
5
+
6
+ import { fileURLToPath, pathToFileURL } from 'node:url'
7
+ import { logDiff } from '@tanstack/router-utils'
8
+ import { getConfig, splitGroupingsSchema } from './config'
9
+ import {
10
+ compileCodeSplitReferenceRoute,
11
+ compileCodeSplitVirtualRoute,
12
+ detectCodeSplitGroupingsFromRoute,
13
+ } from './code-splitter/compilers'
14
+ import {
15
+ defaultCodeSplitGroupings,
16
+ splitRouteIdentNodes,
17
+ tsrSplit,
18
+ } from './constants'
19
+ import { decodeIdentifier } from './code-splitter/path-ids'
20
+ import { debug, fileIsInRoutesDirectory } from './utils'
21
+ import type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'
22
+
23
+ import type { Config } from './config'
24
+ import type {
25
+ UnpluginContextMeta,
26
+ UnpluginFactory,
27
+ TransformResult as UnpluginTransformResult,
28
+ } from 'unplugin'
29
+
30
+ function capitalizeFirst(str: string): string {
31
+ return str.charAt(0).toUpperCase() + str.slice(1)
32
+ }
33
+
34
+ type BannedBeforeExternalPlugin = {
35
+ identifier: string
36
+ pkg: string
37
+ usage: string
38
+ frameworks: Array<UnpluginContextMeta['framework']>
39
+ }
40
+
41
+ const bannedBeforeExternalPlugins: Array<BannedBeforeExternalPlugin> = [
42
+ {
43
+ identifier: '@react-refresh',
44
+ pkg: '@vitejs/plugin-react',
45
+ usage: 'viteReact()',
46
+ frameworks: ['vite'],
47
+ },
48
+ ]
49
+
50
+ class FoundPluginInBeforeCode extends Error {
51
+ constructor(externalPlugin: BannedBeforeExternalPlugin, framework: string) {
52
+ super(`We detected that the '${externalPlugin.pkg}' was passed before '@tanstack/router-plugin'. Please make sure that '@tanstack/router-plugin' is passed before '${externalPlugin.pkg}' and try again:
53
+ e.g.
54
+ plugins: [
55
+ TanStackRouter${capitalizeFirst(framework)}(), // Place this before ${externalPlugin.usage}
56
+ ${externalPlugin.usage},
57
+ ]
58
+ `)
59
+ }
60
+ }
61
+
62
+ const PLUGIN_NAME = 'unplugin:router-code-splitter'
63
+
64
+ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
65
+ Partial<Config> | undefined
66
+ > = (options = {}, { framework }) => {
67
+ let ROOT: string = process.cwd()
68
+ let userConfig = options as Config
69
+
70
+ const isProduction = process.env.NODE_ENV === 'production'
71
+
72
+ const getGlobalCodeSplitGroupings = () => {
73
+ return (
74
+ userConfig.codeSplittingOptions?.defaultBehavior ||
75
+ defaultCodeSplitGroupings
76
+ )
77
+ }
78
+ const getShouldSplitFn = () => {
79
+ return userConfig.codeSplittingOptions?.splitBehavior
80
+ }
81
+
82
+ const handleCompilingReferenceFile = (
83
+ code: string,
84
+ id: string,
85
+ ): UnpluginTransformResult => {
86
+ if (debug) console.info('Compiling Route: ', id)
87
+
88
+ const fromCode = detectCodeSplitGroupingsFromRoute({
89
+ code,
90
+ })
91
+
92
+ if (fromCode.groupings) {
93
+ const res = splitGroupingsSchema.safeParse(fromCode.groupings)
94
+ if (!res.success) {
95
+ const message = res.error.errors.map((e) => e.message).join('. ')
96
+ throw new Error(
97
+ `The groupings for the route "${id}" are invalid.\n${message}`,
98
+ )
99
+ }
100
+ }
101
+
102
+ const userShouldSplitFn = getShouldSplitFn()
103
+
104
+ const pluginSplitBehavior = userShouldSplitFn?.({
105
+ routeId: fromCode.routeId,
106
+ }) as CodeSplitGroupings | undefined
107
+
108
+ if (pluginSplitBehavior) {
109
+ const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)
110
+ if (!res.success) {
111
+ const message = res.error.errors.map((e) => e.message).join('. ')
112
+ throw new Error(
113
+ `The groupings returned when using \`splitBehavior\` for the route "${id}" are invalid.\n${message}`,
114
+ )
115
+ }
116
+ }
117
+
118
+ const splitGroupings: CodeSplitGroupings =
119
+ fromCode.groupings || pluginSplitBehavior || getGlobalCodeSplitGroupings()
120
+
121
+ const compiledReferenceRoute = compileCodeSplitReferenceRoute({
122
+ code,
123
+ runtimeEnv: isProduction ? 'prod' : 'dev',
124
+ codeSplitGroupings: splitGroupings,
125
+ targetFramework: userConfig.target,
126
+ filename: id,
127
+ id,
128
+ })
129
+
130
+ if (debug) {
131
+ logDiff(code, compiledReferenceRoute.code)
132
+ console.log('Output:\n', compiledReferenceRoute.code + '\n\n')
133
+ }
134
+
135
+ return compiledReferenceRoute
136
+ }
137
+
138
+ const handleCompilingVirtualFile = (
139
+ code: string,
140
+ id: string,
141
+ ): UnpluginTransformResult => {
142
+ if (debug) console.info('Splitting Route: ', id)
143
+
144
+ const [_, ...pathnameParts] = id.split('?')
145
+
146
+ const searchParams = new URLSearchParams(pathnameParts.join('?'))
147
+ const splitValue = searchParams.get(tsrSplit)
148
+
149
+ if (!splitValue) {
150
+ throw new Error(
151
+ `The split value for the virtual route "${id}" was not found.`,
152
+ )
153
+ }
154
+
155
+ const rawGrouping = decodeIdentifier(splitValue)
156
+ const grouping = [...new Set(rawGrouping)].filter((p) =>
157
+ splitRouteIdentNodes.includes(p as any),
158
+ ) as Array<SplitRouteIdentNodes>
159
+
160
+ const result = compileCodeSplitVirtualRoute({
161
+ code,
162
+ filename: id,
163
+ splitTargets: grouping,
164
+ })
165
+
166
+ if (debug) {
167
+ logDiff(code, result.code)
168
+ console.log('Output:\n', result.code + '\n\n')
169
+ }
170
+
171
+ return result
172
+ }
173
+
174
+ return {
175
+ name: 'router-code-splitter-plugin',
176
+ enforce: 'pre',
177
+
178
+ transform(code, id) {
179
+ if (!userConfig.autoCodeSplitting) {
180
+ return null
181
+ }
182
+
183
+ const url = pathToFileURL(id)
184
+ url.searchParams.delete('v')
185
+ id = fileURLToPath(url).replace(/\\/g, '/')
186
+
187
+ if (id.includes(tsrSplit)) {
188
+ return handleCompilingVirtualFile(code, id)
189
+ } else if (
190
+ fileIsInRoutesDirectory(id, userConfig.routesDirectory) &&
191
+ (code.includes('createRoute(') || code.includes('createFileRoute('))
192
+ ) {
193
+ for (const externalPlugin of bannedBeforeExternalPlugins) {
194
+ if (!externalPlugin.frameworks.includes(framework)) {
195
+ continue
196
+ }
197
+
198
+ if (code.includes(externalPlugin.identifier)) {
199
+ throw new FoundPluginInBeforeCode(externalPlugin, framework)
200
+ }
201
+ }
202
+
203
+ return handleCompilingReferenceFile(code, id)
204
+ }
205
+
206
+ return null
207
+ },
208
+
209
+ transformInclude(id) {
210
+ if (!userConfig.autoCodeSplitting) {
211
+ return undefined
212
+ }
213
+
214
+ if (
215
+ fileIsInRoutesDirectory(id, userConfig.routesDirectory) ||
216
+ id.includes(tsrSplit)
217
+ ) {
218
+ return true
219
+ }
220
+ return false
221
+ },
222
+
223
+ vite: {
224
+ configResolved(config) {
225
+ ROOT = config.root
226
+
227
+ userConfig = getConfig(options, ROOT)
228
+ },
229
+ },
230
+
231
+ rspack(_compiler) {
232
+ ROOT = process.cwd()
233
+ userConfig = getConfig(options, ROOT)
234
+ },
235
+
236
+ webpack(compiler) {
237
+ ROOT = process.cwd()
238
+ userConfig = getConfig(options, ROOT)
239
+
240
+ if (
241
+ userConfig.autoCodeSplitting &&
242
+ compiler.options.mode === 'production'
243
+ ) {
244
+ compiler.hooks.done.tap(PLUGIN_NAME, () => {
245
+ console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')
246
+ setTimeout(() => {
247
+ process.exit(0)
248
+ })
249
+ })
250
+ }
251
+ },
252
+ }
253
+ }
@@ -0,0 +1,32 @@
1
+ import { unpluginRouterGeneratorFactory } from './router-generator-plugin'
2
+ import { unpluginRouterCodeSplitterFactory } from './router-code-splitter-plugin'
3
+ import { unpluginRouterHmrFactory } from './router-hmr-plugin'
4
+ import { unpluginRouteAutoimportFactory } from './route-autoimport-plugin'
5
+ import type { Config } from './config'
6
+ import type { UnpluginFactory } from 'unplugin'
7
+
8
+ export const unpluginRouterComposedFactory: UnpluginFactory<
9
+ Partial<Config> | undefined
10
+ > = (options = {}, meta) => {
11
+ const getPlugin = (pluginFactory: UnpluginFactory<Partial<Config>>) => {
12
+ const plugin = pluginFactory(options, meta)
13
+ if (!Array.isArray(plugin)) {
14
+ return [plugin]
15
+ }
16
+ return plugin
17
+ }
18
+
19
+ const routerGenerator = getPlugin(unpluginRouterGeneratorFactory)
20
+ const routerCodeSplitter = getPlugin(unpluginRouterCodeSplitterFactory)
21
+ const routeAutoImport = getPlugin(unpluginRouteAutoimportFactory)
22
+
23
+ const result = [...routerGenerator, ...routerCodeSplitter, ...routeAutoImport]
24
+
25
+ const isProduction = process.env.NODE_ENV === 'production'
26
+
27
+ if (!isProduction && !options.autoCodeSplitting) {
28
+ const routerHmr = getPlugin(unpluginRouterHmrFactory)
29
+ result.push(...routerHmr)
30
+ }
31
+ return result
32
+ }