@tanstack/router-plugin 1.166.7 → 1.166.8
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/core/code-splitter/compilers.cjs +14 -0
- package/dist/cjs/core/code-splitter/compilers.cjs.map +1 -1
- package/dist/cjs/core/code-splitter/compilers.d.cts +2 -0
- package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs +17 -0
- package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs.map +1 -0
- package/dist/cjs/core/code-splitter/plugins/framework-plugins.d.cts +6 -0
- package/dist/cjs/core/code-splitter/plugins/react-refresh-route-components.cjs +69 -0
- package/dist/cjs/core/code-splitter/plugins/react-refresh-route-components.cjs.map +1 -0
- package/dist/cjs/core/code-splitter/plugins/react-refresh-route-components.d.cts +2 -0
- package/dist/cjs/core/code-splitter/plugins.d.cts +28 -0
- package/dist/cjs/core/router-code-splitter-plugin.cjs +11 -5
- package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -1
- package/dist/cjs/core/router-hmr-plugin.cjs +23 -0
- package/dist/cjs/core/router-hmr-plugin.cjs.map +1 -1
- package/dist/cjs/core/utils.cjs +28 -0
- package/dist/cjs/core/utils.cjs.map +1 -1
- package/dist/cjs/core/utils.d.cts +3 -0
- package/dist/esm/core/code-splitter/compilers.d.ts +2 -0
- package/dist/esm/core/code-splitter/compilers.js +14 -0
- package/dist/esm/core/code-splitter/compilers.js.map +1 -1
- package/dist/esm/core/code-splitter/plugins/framework-plugins.d.ts +6 -0
- package/dist/esm/core/code-splitter/plugins/framework-plugins.js +17 -0
- package/dist/esm/core/code-splitter/plugins/framework-plugins.js.map +1 -0
- package/dist/esm/core/code-splitter/plugins/react-refresh-route-components.d.ts +2 -0
- package/dist/esm/core/code-splitter/plugins/react-refresh-route-components.js +52 -0
- package/dist/esm/core/code-splitter/plugins/react-refresh-route-components.js.map +1 -0
- package/dist/esm/core/code-splitter/plugins.d.ts +28 -0
- package/dist/esm/core/router-code-splitter-plugin.js +8 -2
- package/dist/esm/core/router-code-splitter-plugin.js.map +1 -1
- package/dist/esm/core/router-hmr-plugin.js +24 -1
- package/dist/esm/core/router-hmr-plugin.js.map +1 -1
- package/dist/esm/core/utils.d.ts +3 -0
- package/dist/esm/core/utils.js +11 -0
- package/dist/esm/core/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/core/code-splitter/compilers.ts +22 -0
- package/src/core/code-splitter/plugins/framework-plugins.ts +19 -0
- package/src/core/code-splitter/plugins/react-refresh-route-components.ts +63 -0
- package/src/core/code-splitter/plugins.ts +34 -0
- package/src/core/router-code-splitter-plugin.ts +9 -3
- package/src/core/router-hmr-plugin.ts +26 -0
- package/src/core/utils.ts +21 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { default as babel } from '@babel/core';
|
|
2
|
+
import { Config, DeletableNodes } from '../config.js';
|
|
3
|
+
import { CodeSplitGroupings } from '../constants.js';
|
|
4
|
+
import type * as t from '@babel/types';
|
|
5
|
+
export type CompileCodeSplitReferenceRouteOptions = {
|
|
6
|
+
codeSplitGroupings: CodeSplitGroupings;
|
|
7
|
+
deleteNodes?: Set<DeletableNodes>;
|
|
8
|
+
targetFramework: Config['target'];
|
|
9
|
+
filename: string;
|
|
10
|
+
id: string;
|
|
11
|
+
addHmr?: boolean;
|
|
12
|
+
sharedBindings?: Set<string>;
|
|
13
|
+
};
|
|
14
|
+
export type ReferenceRouteCompilerPluginContext = {
|
|
15
|
+
programPath: babel.NodePath<t.Program>;
|
|
16
|
+
callExpressionPath: babel.NodePath<t.CallExpression>;
|
|
17
|
+
insertionPath: babel.NodePath;
|
|
18
|
+
routeOptions: t.ObjectExpression;
|
|
19
|
+
createRouteFn: string;
|
|
20
|
+
opts: CompileCodeSplitReferenceRouteOptions;
|
|
21
|
+
};
|
|
22
|
+
export type ReferenceRouteCompilerPluginResult = {
|
|
23
|
+
modified?: boolean;
|
|
24
|
+
};
|
|
25
|
+
export type ReferenceRouteCompilerPlugin = {
|
|
26
|
+
name: string;
|
|
27
|
+
onUnsplittableRoute?: (ctx: ReferenceRouteCompilerPluginContext) => void | ReferenceRouteCompilerPluginResult;
|
|
28
|
+
};
|
|
@@ -2,6 +2,7 @@ import { pathToFileURL, fileURLToPath } from "node:url";
|
|
|
2
2
|
import { logDiff } from "@tanstack/router-utils";
|
|
3
3
|
import { getConfig, splitGroupingsSchema } from "./config.js";
|
|
4
4
|
import { compileCodeSplitSharedRoute, detectCodeSplitGroupingsFromRoute, computeSharedBindings, compileCodeSplitReferenceRoute, compileCodeSplitVirtualRoute } from "./code-splitter/compilers.js";
|
|
5
|
+
import { getReferenceRouteCompilerPlugins } from "./code-splitter/plugins/framework-plugins.js";
|
|
5
6
|
import { tsrSplit, tsrShared, splitRouteIdentNodes, defaultCodeSplitGroupings } from "./constants.js";
|
|
6
7
|
import { decodeIdentifier } from "./code-splitter/path-ids.js";
|
|
7
8
|
import { normalizePath, debug } from "./utils.js";
|
|
@@ -93,6 +94,7 @@ ${message}`
|
|
|
93
94
|
} else {
|
|
94
95
|
sharedBindingsMap.delete(id);
|
|
95
96
|
}
|
|
97
|
+
const addHmr = (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction;
|
|
96
98
|
const compiledReferenceRoute = compileCodeSplitReferenceRoute({
|
|
97
99
|
code,
|
|
98
100
|
codeSplitGroupings: splitGroupings,
|
|
@@ -100,8 +102,12 @@ ${message}`
|
|
|
100
102
|
filename: id,
|
|
101
103
|
id,
|
|
102
104
|
deleteNodes: userConfig.codeSplittingOptions?.deleteNodes ? new Set(userConfig.codeSplittingOptions.deleteNodes) : void 0,
|
|
103
|
-
addHmr
|
|
104
|
-
sharedBindings: sharedBindings.size > 0 ? sharedBindings : void 0
|
|
105
|
+
addHmr,
|
|
106
|
+
sharedBindings: sharedBindings.size > 0 ? sharedBindings : void 0,
|
|
107
|
+
compilerPlugins: getReferenceRouteCompilerPlugins({
|
|
108
|
+
targetFramework: userConfig.target,
|
|
109
|
+
addHmr
|
|
110
|
+
})
|
|
105
111
|
});
|
|
106
112
|
if (compiledReferenceRoute === null) {
|
|
107
113
|
if (debug) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-code-splitter-plugin.js","sources":["../../../src/core/router-code-splitter-plugin.ts"],"sourcesContent":["/**\n * It is important to familiarize yourself with how the code-splitting works in this plugin.\n * https://github.com/TanStack/router/pull/3355\n */\n\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { logDiff } from '@tanstack/router-utils'\nimport { getConfig, splitGroupingsSchema } from './config'\nimport {\n compileCodeSplitReferenceRoute,\n compileCodeSplitSharedRoute,\n compileCodeSplitVirtualRoute,\n computeSharedBindings,\n detectCodeSplitGroupingsFromRoute,\n} from './code-splitter/compilers'\nimport {\n defaultCodeSplitGroupings,\n splitRouteIdentNodes,\n tsrShared,\n tsrSplit,\n} from './constants'\nimport { decodeIdentifier } from './code-splitter/path-ids'\nimport { debug, normalizePath } from './utils'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst PLUGIN_NAME = 'unplugin:router-code-splitter'\nconst CODE_SPLITTER_PLUGIN_NAME =\n 'tanstack-router:code-splitter:compile-reference-file'\n\ntype TransformationPluginInfo = {\n pluginNames: Array<string>\n pkg: string\n usage: string\n}\n\n/**\n * JSX transformation plugins grouped by framework.\n * These plugins must come AFTER the TanStack Router plugin in the Vite config.\n */\nconst TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record<\n string,\n Array<TransformationPluginInfo>\n> = {\n react: [\n {\n // Babel-based React plugin\n pluginNames: ['vite:react-babel', 'vite:react-refresh'],\n pkg: '@vitejs/plugin-react',\n usage: 'react()',\n },\n {\n // SWC-based React plugin\n pluginNames: ['vite:react-swc', 'vite:react-swc:resolve-runtime'],\n pkg: '@vitejs/plugin-react-swc',\n usage: 'reactSwc()',\n },\n {\n // OXC-based React plugin (deprecated but should still be handled)\n pluginNames: ['vite:react-oxc:config', 'vite:react-oxc:refresh-runtime'],\n pkg: '@vitejs/plugin-react-oxc',\n usage: 'reactOxc()',\n },\n ],\n solid: [\n {\n pluginNames: ['solid'],\n pkg: 'vite-plugin-solid',\n usage: 'solid()',\n },\n ],\n}\n\nexport const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}, { framework: _framework }) => {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n function initUserConfig() {\n if (typeof options === 'function') {\n userConfig = options()\n } else {\n userConfig = getConfig(options, ROOT)\n }\n }\n const isProduction = process.env.NODE_ENV === 'production'\n\n // Map from normalized route file path → set of shared binding names.\n // Populated by the reference compiler, consumed by virtual and shared compilers.\n const sharedBindingsMap = new Map<string, Set<string>>()\n\n const getGlobalCodeSplitGroupings = () => {\n return (\n userConfig.codeSplittingOptions?.defaultBehavior ||\n defaultCodeSplitGroupings\n )\n }\n const getShouldSplitFn = () => {\n return userConfig.codeSplittingOptions?.splitBehavior\n }\n\n const handleCompilingReferenceFile = (\n code: string,\n id: string,\n generatorNodeInfo: GetRoutesByFileMapResultValue,\n ): UnpluginTransformResult => {\n if (debug) console.info('Compiling Route: ', id)\n\n const fromCode = detectCodeSplitGroupingsFromRoute({\n code,\n })\n\n if (fromCode.groupings) {\n const res = splitGroupingsSchema.safeParse(fromCode.groupings)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const userShouldSplitFn = getShouldSplitFn()\n\n const pluginSplitBehavior = userShouldSplitFn?.({\n routeId: generatorNodeInfo.routePath,\n }) as CodeSplitGroupings | undefined\n\n if (pluginSplitBehavior) {\n const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings returned when using \\`splitBehavior\\` for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const splitGroupings: CodeSplitGroupings =\n fromCode.groupings || pluginSplitBehavior || getGlobalCodeSplitGroupings()\n\n // Compute shared bindings before compiling the reference route\n const sharedBindings = computeSharedBindings({\n code,\n codeSplitGroupings: splitGroupings,\n })\n if (sharedBindings.size > 0) {\n sharedBindingsMap.set(id, sharedBindings)\n } else {\n sharedBindingsMap.delete(id)\n }\n\n const compiledReferenceRoute = compileCodeSplitReferenceRoute({\n code,\n codeSplitGroupings: splitGroupings,\n targetFramework: userConfig.target,\n filename: id,\n id,\n deleteNodes: userConfig.codeSplittingOptions?.deleteNodes\n ? new Set(userConfig.codeSplittingOptions.deleteNodes)\n : undefined,\n addHmr:\n (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction,\n sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n })\n\n if (compiledReferenceRoute === null) {\n if (debug) {\n console.info(\n `No changes made to route \"${id}\", skipping code-splitting.`,\n )\n }\n return null\n }\n if (debug) {\n logDiff(code, compiledReferenceRoute.code)\n console.log('Output:\\n', compiledReferenceRoute.code + '\\n\\n')\n }\n\n return compiledReferenceRoute\n }\n\n const handleCompilingVirtualFile = (\n code: string,\n id: string,\n ): UnpluginTransformResult => {\n if (debug) console.info('Splitting Route: ', id)\n\n const [_, ...pathnameParts] = id.split('?')\n\n const searchParams = new URLSearchParams(pathnameParts.join('?'))\n const splitValue = searchParams.get(tsrSplit)\n\n if (!splitValue) {\n throw new Error(\n `The split value for the virtual route \"${id}\" was not found.`,\n )\n }\n\n const rawGrouping = decodeIdentifier(splitValue)\n const grouping = [...new Set(rawGrouping)].filter((p) =>\n splitRouteIdentNodes.includes(p as any),\n ) as Array<SplitRouteIdentNodes>\n\n const baseId = id.split('?')[0]!\n const resolvedSharedBindings = sharedBindingsMap.get(baseId)\n\n const result = compileCodeSplitVirtualRoute({\n code,\n filename: id,\n splitTargets: grouping,\n sharedBindings: resolvedSharedBindings,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n }\n\n const includedCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n ]\n return [\n {\n name: 'tanstack-router:code-splitter:compile-reference-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: {\n exclude: [tsrSplit, tsrShared],\n // this is necessary for webpack / rspack to avoid matching .html files\n include: /\\.(m|c)?(j|t)sx?$/,\n },\n code: {\n include: includedCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const generatorFileInfo =\n globalThis.TSR_ROUTES_BY_ID_MAP?.get(normalizedId)\n if (\n generatorFileInfo &&\n includedCode.some((included) => code.includes(included))\n ) {\n return handleCompilingReferenceFile(\n code,\n normalizedId,\n generatorFileInfo,\n )\n }\n\n return null\n },\n },\n\n vite: {\n configResolved(config) {\n ROOT = config.root\n initUserConfig()\n\n // Validate plugin order - router must come before JSX transformation plugins\n const routerPluginIndex = config.plugins.findIndex(\n (p) => p.name === CODE_SPLITTER_PLUGIN_NAME,\n )\n\n if (routerPluginIndex === -1) return\n\n const frameworkPlugins =\n TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target]\n if (!frameworkPlugins) return\n\n for (const transformPlugin of frameworkPlugins) {\n const transformPluginIndex = config.plugins.findIndex((p) =>\n transformPlugin.pluginNames.includes(p.name),\n )\n\n if (\n transformPluginIndex !== -1 &&\n transformPluginIndex < routerPluginIndex\n ) {\n throw new Error(\n `Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\\n\\n` +\n `The TanStack Router plugin must come BEFORE JSX transformation plugins.\\n\\n` +\n `Please update your Vite config:\\n\\n` +\n ` plugins: [\\n` +\n ` tanstackRouter(),\\n` +\n ` ${transformPlugin.usage},\\n` +\n ` ]\\n`,\n )\n }\n }\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n\n rspack(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\n },\n\n webpack(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-virtual-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-split/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n return handleCompilingVirtualFile(code, normalizedId)\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-shared-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-shared/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n const [baseId] = normalizedId.split('?')\n\n if (!baseId) return null\n\n const sharedBindings = sharedBindingsMap.get(baseId)\n if (!sharedBindings || sharedBindings.size === 0) return null\n\n if (debug) console.info('Compiling Shared Module: ', id)\n\n const result = compileCodeSplitSharedRoute({\n code,\n sharedBindings,\n filename: normalizedId,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n ]\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router-code-splitter-plugin.js","sources":["../../../src/core/router-code-splitter-plugin.ts"],"sourcesContent":["/**\n * It is important to familiarize yourself with how the code-splitting works in this plugin.\n * https://github.com/TanStack/router/pull/3355\n */\n\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { logDiff } from '@tanstack/router-utils'\nimport { getConfig, splitGroupingsSchema } from './config'\nimport {\n compileCodeSplitReferenceRoute,\n compileCodeSplitSharedRoute,\n compileCodeSplitVirtualRoute,\n computeSharedBindings,\n detectCodeSplitGroupingsFromRoute,\n} from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport {\n defaultCodeSplitGroupings,\n splitRouteIdentNodes,\n tsrShared,\n tsrSplit,\n} from './constants'\nimport { decodeIdentifier } from './code-splitter/path-ids'\nimport { debug, normalizePath } from './utils'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst PLUGIN_NAME = 'unplugin:router-code-splitter'\nconst CODE_SPLITTER_PLUGIN_NAME =\n 'tanstack-router:code-splitter:compile-reference-file'\n\ntype TransformationPluginInfo = {\n pluginNames: Array<string>\n pkg: string\n usage: string\n}\n\n/**\n * JSX transformation plugins grouped by framework.\n * These plugins must come AFTER the TanStack Router plugin in the Vite config.\n */\nconst TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record<\n string,\n Array<TransformationPluginInfo>\n> = {\n react: [\n {\n // Babel-based React plugin\n pluginNames: ['vite:react-babel', 'vite:react-refresh'],\n pkg: '@vitejs/plugin-react',\n usage: 'react()',\n },\n {\n // SWC-based React plugin\n pluginNames: ['vite:react-swc', 'vite:react-swc:resolve-runtime'],\n pkg: '@vitejs/plugin-react-swc',\n usage: 'reactSwc()',\n },\n {\n // OXC-based React plugin (deprecated but should still be handled)\n pluginNames: ['vite:react-oxc:config', 'vite:react-oxc:refresh-runtime'],\n pkg: '@vitejs/plugin-react-oxc',\n usage: 'reactOxc()',\n },\n ],\n solid: [\n {\n pluginNames: ['solid'],\n pkg: 'vite-plugin-solid',\n usage: 'solid()',\n },\n ],\n}\n\nexport const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}, { framework: _framework }) => {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n function initUserConfig() {\n if (typeof options === 'function') {\n userConfig = options()\n } else {\n userConfig = getConfig(options, ROOT)\n }\n }\n const isProduction = process.env.NODE_ENV === 'production'\n // Map from normalized route file path → set of shared binding names.\n // Populated by the reference compiler, consumed by virtual and shared compilers.\n const sharedBindingsMap = new Map<string, Set<string>>()\n\n const getGlobalCodeSplitGroupings = () => {\n return (\n userConfig.codeSplittingOptions?.defaultBehavior ||\n defaultCodeSplitGroupings\n )\n }\n const getShouldSplitFn = () => {\n return userConfig.codeSplittingOptions?.splitBehavior\n }\n\n const handleCompilingReferenceFile = (\n code: string,\n id: string,\n generatorNodeInfo: GetRoutesByFileMapResultValue,\n ): UnpluginTransformResult => {\n if (debug) console.info('Compiling Route: ', id)\n\n const fromCode = detectCodeSplitGroupingsFromRoute({\n code,\n })\n\n if (fromCode.groupings) {\n const res = splitGroupingsSchema.safeParse(fromCode.groupings)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const userShouldSplitFn = getShouldSplitFn()\n\n const pluginSplitBehavior = userShouldSplitFn?.({\n routeId: generatorNodeInfo.routePath,\n }) as CodeSplitGroupings | undefined\n\n if (pluginSplitBehavior) {\n const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings returned when using \\`splitBehavior\\` for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const splitGroupings: CodeSplitGroupings =\n fromCode.groupings || pluginSplitBehavior || getGlobalCodeSplitGroupings()\n\n // Compute shared bindings before compiling the reference route\n const sharedBindings = computeSharedBindings({\n code,\n codeSplitGroupings: splitGroupings,\n })\n if (sharedBindings.size > 0) {\n sharedBindingsMap.set(id, sharedBindings)\n } else {\n sharedBindingsMap.delete(id)\n }\n\n const addHmr =\n (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction\n\n const compiledReferenceRoute = compileCodeSplitReferenceRoute({\n code,\n codeSplitGroupings: splitGroupings,\n targetFramework: userConfig.target,\n filename: id,\n id,\n deleteNodes: userConfig.codeSplittingOptions?.deleteNodes\n ? new Set(userConfig.codeSplittingOptions.deleteNodes)\n : undefined,\n addHmr,\n sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\n }),\n })\n\n if (compiledReferenceRoute === null) {\n if (debug) {\n console.info(\n `No changes made to route \"${id}\", skipping code-splitting.`,\n )\n }\n return null\n }\n if (debug) {\n logDiff(code, compiledReferenceRoute.code)\n console.log('Output:\\n', compiledReferenceRoute.code + '\\n\\n')\n }\n\n return compiledReferenceRoute\n }\n\n const handleCompilingVirtualFile = (\n code: string,\n id: string,\n ): UnpluginTransformResult => {\n if (debug) console.info('Splitting Route: ', id)\n\n const [_, ...pathnameParts] = id.split('?')\n\n const searchParams = new URLSearchParams(pathnameParts.join('?'))\n const splitValue = searchParams.get(tsrSplit)\n\n if (!splitValue) {\n throw new Error(\n `The split value for the virtual route \"${id}\" was not found.`,\n )\n }\n\n const rawGrouping = decodeIdentifier(splitValue)\n const grouping = [...new Set(rawGrouping)].filter((p) =>\n splitRouteIdentNodes.includes(p as any),\n ) as Array<SplitRouteIdentNodes>\n\n const baseId = id.split('?')[0]!\n const resolvedSharedBindings = sharedBindingsMap.get(baseId)\n\n const result = compileCodeSplitVirtualRoute({\n code,\n filename: id,\n splitTargets: grouping,\n sharedBindings: resolvedSharedBindings,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n }\n\n const includedCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n ]\n return [\n {\n name: 'tanstack-router:code-splitter:compile-reference-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: {\n exclude: [tsrSplit, tsrShared],\n // this is necessary for webpack / rspack to avoid matching .html files\n include: /\\.(m|c)?(j|t)sx?$/,\n },\n code: {\n include: includedCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const generatorFileInfo =\n globalThis.TSR_ROUTES_BY_ID_MAP?.get(normalizedId)\n if (\n generatorFileInfo &&\n includedCode.some((included) => code.includes(included))\n ) {\n return handleCompilingReferenceFile(\n code,\n normalizedId,\n generatorFileInfo,\n )\n }\n\n return null\n },\n },\n\n vite: {\n configResolved(config) {\n ROOT = config.root\n initUserConfig()\n\n // Validate plugin order - router must come before JSX transformation plugins\n const routerPluginIndex = config.plugins.findIndex(\n (p) => p.name === CODE_SPLITTER_PLUGIN_NAME,\n )\n\n if (routerPluginIndex === -1) return\n\n const frameworkPlugins =\n TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target]\n if (!frameworkPlugins) return\n\n for (const transformPlugin of frameworkPlugins) {\n const transformPluginIndex = config.plugins.findIndex((p) =>\n transformPlugin.pluginNames.includes(p.name),\n )\n\n if (\n transformPluginIndex !== -1 &&\n transformPluginIndex < routerPluginIndex\n ) {\n throw new Error(\n `Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\\n\\n` +\n `The TanStack Router plugin must come BEFORE JSX transformation plugins.\\n\\n` +\n `Please update your Vite config:\\n\\n` +\n ` plugins: [\\n` +\n ` tanstackRouter(),\\n` +\n ` ${transformPlugin.usage},\\n` +\n ` ]\\n`,\n )\n }\n }\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n\n rspack(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\n },\n\n webpack(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-virtual-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-split/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n return handleCompilingVirtualFile(code, normalizedId)\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-shared-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-shared/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n const [baseId] = normalizedId.split('?')\n\n if (!baseId) return null\n\n const sharedBindings = sharedBindingsMap.get(baseId)\n if (!sharedBindings || sharedBindings.size === 0) return null\n\n if (debug) console.info('Compiling Shared Module: ', id)\n\n const result = compileCodeSplitSharedRoute({\n code,\n sharedBindings,\n filename: normalizedId,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n ]\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { parseAst, generateFromAst
|
|
1
|
+
import { logDiff, parseAst, generateFromAst } from "@tanstack/router-utils";
|
|
2
|
+
import { compileCodeSplitReferenceRoute } from "./code-splitter/compilers.js";
|
|
3
|
+
import { getReferenceRouteCompilerPlugins } from "./code-splitter/plugins/framework-plugins.js";
|
|
2
4
|
import { routeHmrStatement } from "./route-hmr-statement.js";
|
|
3
5
|
import { normalizePath, debug } from "./utils.js";
|
|
4
6
|
import { getConfig } from "./config.js";
|
|
@@ -27,6 +29,27 @@ const unpluginRouterHmrFactory = (options = {}) => {
|
|
|
27
29
|
return null;
|
|
28
30
|
}
|
|
29
31
|
if (debug) console.info("Adding HMR handling to route ", normalizedId);
|
|
32
|
+
if (userConfig.target === "react") {
|
|
33
|
+
const compiled = compileCodeSplitReferenceRoute({
|
|
34
|
+
code,
|
|
35
|
+
filename: normalizedId,
|
|
36
|
+
id: normalizedId,
|
|
37
|
+
addHmr: true,
|
|
38
|
+
codeSplitGroupings: [],
|
|
39
|
+
targetFramework: "react",
|
|
40
|
+
compilerPlugins: getReferenceRouteCompilerPlugins({
|
|
41
|
+
targetFramework: "react",
|
|
42
|
+
addHmr: true
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
if (compiled) {
|
|
46
|
+
if (debug) {
|
|
47
|
+
logDiff(code, compiled.code);
|
|
48
|
+
console.log("Output:\n", compiled.code + "\n\n");
|
|
49
|
+
}
|
|
50
|
+
return compiled;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
30
53
|
const ast = parseAst({ code });
|
|
31
54
|
ast.program.body.push(routeHmrStatement);
|
|
32
55
|
const result = generateFromAst(ast, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-hmr-plugin.js","sources":["../../../src/core/router-hmr-plugin.ts"],"sourcesContent":["import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'\nimport { routeHmrStatement } from './route-hmr-statement'\nimport { debug, normalizePath } from './utils'\nimport { getConfig } from './config'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\n\n/**\n * This plugin adds HMR support for file routes.\n * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin\n * handles HMR for code-split routes itself.\n */\n\nconst includeCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n]\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n let ROOT: string = process.cwd()\n let userConfig = options as Config\n\n return {\n name: 'tanstack-router:hmr',\n enforce: 'pre',\n transform: {\n filter: {\n // this is necessary for webpack / rspack to avoid matching .html files\n id: /\\.(m|c)?(j|t)sx?$/,\n code: {\n include: includeCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n if (!globalThis.TSR_ROUTES_BY_ID_MAP?.has(normalizedId)) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n const ast = parseAst({ code })\n ast.program.body.push(routeHmrStatement)\n const result = generateFromAst(ast, {\n sourceMaps: true,\n filename: normalizedId,\n sourceFileName: normalizedId,\n })\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n return result\n },\n },\n vite: {\n configResolved(config) {\n ROOT = config.root\n userConfig = getConfig(options, ROOT)\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router-hmr-plugin.js","sources":["../../../src/core/router-hmr-plugin.ts"],"sourcesContent":["import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'\nimport { compileCodeSplitReferenceRoute } from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport { routeHmrStatement } from './route-hmr-statement'\nimport { debug, normalizePath } from './utils'\nimport { getConfig } from './config'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\n\n/**\n * This plugin adds HMR support for file routes.\n * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin\n * handles HMR for code-split routes itself.\n */\n\nconst includeCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n]\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n let ROOT: string = process.cwd()\n let userConfig = options as Config\n\n return {\n name: 'tanstack-router:hmr',\n enforce: 'pre',\n transform: {\n filter: {\n // this is necessary for webpack / rspack to avoid matching .html files\n id: /\\.(m|c)?(j|t)sx?$/,\n code: {\n include: includeCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n if (!globalThis.TSR_ROUTES_BY_ID_MAP?.has(normalizedId)) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n if (userConfig.target === 'react') {\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\n codeSplitGroupings: [],\n targetFramework: 'react',\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n }),\n })\n\n if (compiled) {\n if (debug) {\n logDiff(code, compiled.code)\n console.log('Output:\\n', compiled.code + '\\n\\n')\n }\n\n return compiled\n }\n }\n\n const ast = parseAst({ code })\n ast.program.body.push(routeHmrStatement)\n const result = generateFromAst(ast, {\n sourceMaps: true,\n filename: normalizedId,\n sourceFileName: normalizedId,\n })\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n return result\n },\n },\n vite: {\n configResolved(config) {\n ROOT = config.root\n userConfig = getConfig(options, ROOT)\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n }\n}\n"],"names":[],"mappings":";;;;;;AAeA,MAAM,cAAc;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF;AACO,MAAM,2BAET,CAAC,UAAU,OAAO;AACpB,MAAI,OAAe,QAAQ,IAAA;AAC3B,MAAI,aAAa;AAEjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,MACT,QAAQ;AAAA;AAAA,QAEN,IAAI;AAAA,QACJ,MAAM;AAAA,UACJ,SAAS;AAAA,QAAA;AAAA,MACX;AAAA,MAEF,QAAQ,MAAM,IAAI;AAChB,cAAM,eAAe,cAAc,EAAE;AACrC,YAAI,CAAC,WAAW,sBAAsB,IAAI,YAAY,GAAG;AACvD,iBAAO;AAAA,QACT;AAEA,YAAI,MAAO,SAAQ,KAAK,iCAAiC,YAAY;AAErE,YAAI,WAAW,WAAW,SAAS;AACjC,gBAAM,WAAW,+BAA+B;AAAA,YAC9C;AAAA,YACA,UAAU;AAAA,YACV,IAAI;AAAA,YACJ,QAAQ;AAAA,YACR,oBAAoB,CAAA;AAAA,YACpB,iBAAiB;AAAA,YACjB,iBAAiB,iCAAiC;AAAA,cAChD,iBAAiB;AAAA,cACjB,QAAQ;AAAA,YAAA,CACT;AAAA,UAAA,CACF;AAED,cAAI,UAAU;AACZ,gBAAI,OAAO;AACT,sBAAQ,MAAM,SAAS,IAAI;AAC3B,sBAAQ,IAAI,aAAa,SAAS,OAAO,MAAM;AAAA,YACjD;AAEA,mBAAO;AAAA,UACT;AAAA,QACF;AAEA,cAAM,MAAM,SAAS,EAAE,MAAM;AAC7B,YAAI,QAAQ,KAAK,KAAK,iBAAiB;AACvC,cAAM,SAAS,gBAAgB,KAAK;AAAA,UAClC,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,gBAAgB;AAAA,QAAA,CACjB;AACD,YAAI,OAAO;AACT,kBAAQ,MAAM,OAAO,IAAI;AACzB,kBAAQ,IAAI,aAAa,OAAO,OAAO,MAAM;AAAA,QAC/C;AACA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,IAEF,MAAM;AAAA,MACJ,eAAe,QAAQ;AACrB,eAAO,OAAO;AACd,qBAAa,UAAU,SAAS,IAAI;AAAA,MACtC;AAAA,MACA,mBAAmB,aAAa;AAC9B,YAAI,WAAW,QAAQ,MAAM,iBAAiB;AAC5C,iBAAO,WAAW,OAAO,KAAK,oBAAoB,YAAY;AAAA,QAChE;AACA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAEJ;"}
|
package/dist/esm/core/utils.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { default as babel } from '@babel/core';
|
|
2
|
+
import * as t from '@babel/types';
|
|
1
3
|
export declare const debug: boolean | "" | undefined;
|
|
2
4
|
/**
|
|
3
5
|
* Normalizes a file path by converting Windows backslashes to forward slashes.
|
|
@@ -7,3 +9,4 @@ export declare const debug: boolean | "" | undefined;
|
|
|
7
9
|
* pass native paths with backslashes to transform handlers.
|
|
8
10
|
*/
|
|
9
11
|
export declare function normalizePath(path: string): string;
|
|
12
|
+
export declare function getUniqueProgramIdentifier(programPath: babel.NodePath<t.Program>, baseName: string): t.Identifier;
|
package/dist/esm/core/utils.js
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
1
2
|
const debug = process.env.TSR_VITE_DEBUG && ["true", "router-plugin"].includes(process.env.TSR_VITE_DEBUG);
|
|
2
3
|
function normalizePath(path) {
|
|
3
4
|
return path.replace(/\\/g, "/");
|
|
4
5
|
}
|
|
6
|
+
function getUniqueProgramIdentifier(programPath, baseName) {
|
|
7
|
+
let name = baseName;
|
|
8
|
+
let suffix = 2;
|
|
9
|
+
while (programPath.scope.hasBinding(name) || programPath.scope.hasGlobal(name)) {
|
|
10
|
+
name = `${baseName}${suffix}`;
|
|
11
|
+
suffix++;
|
|
12
|
+
}
|
|
13
|
+
return t.identifier(name);
|
|
14
|
+
}
|
|
5
15
|
export {
|
|
6
16
|
debug,
|
|
17
|
+
getUniqueProgramIdentifier,
|
|
7
18
|
normalizePath
|
|
8
19
|
};
|
|
9
20
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/core/utils.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/core/utils.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type babel from '@babel/core'\n\nexport const debug =\n process.env.TSR_VITE_DEBUG &&\n ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG)\n\n/**\n * Normalizes a file path by converting Windows backslashes to forward slashes.\n * This ensures consistent path handling across different bundlers and operating systems.\n *\n * The route generator stores paths with forward slashes, but rspack/webpack on Windows\n * pass native paths with backslashes to transform handlers.\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nexport function getUniqueProgramIdentifier(\n programPath: babel.NodePath<t.Program>,\n baseName: string,\n): t.Identifier {\n let name = baseName\n let suffix = 2\n\n while (\n programPath.scope.hasBinding(name) ||\n programPath.scope.hasGlobal(name)\n ) {\n name = `${baseName}${suffix}`\n suffix++\n }\n\n return t.identifier(name)\n}\n"],"names":[],"mappings":";AAGO,MAAM,QACX,QAAQ,IAAI,kBACZ,CAAC,QAAQ,eAAe,EAAE,SAAS,QAAQ,IAAI,cAAc;AASxD,SAAS,cAAc,MAAsB;AAClD,SAAO,KAAK,QAAQ,OAAO,GAAG;AAChC;AAEO,SAAS,2BACd,aACA,UACc;AACd,MAAI,OAAO;AACX,MAAI,SAAS;AAEb,SACE,YAAY,MAAM,WAAW,IAAI,KACjC,YAAY,MAAM,UAAU,IAAI,GAChC;AACA,WAAO,GAAG,QAAQ,GAAG,MAAM;AAC3B;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,IAAI;AAC1B;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-plugin",
|
|
3
|
-
"version": "1.166.
|
|
3
|
+
"version": "1.166.8",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"vite": ">=5.0.0 || >=6.0.0 || >=7.0.0",
|
|
112
112
|
"vite-plugin-solid": "^2.11.10",
|
|
113
113
|
"webpack": ">=5.92.0",
|
|
114
|
-
"@tanstack/react-router": "^1.166.
|
|
114
|
+
"@tanstack/react-router": "^1.166.8"
|
|
115
115
|
},
|
|
116
116
|
"peerDependenciesMeta": {
|
|
117
117
|
"@rsbuild/core": {
|
|
@@ -11,6 +11,10 @@ import { tsrShared, tsrSplit } from '../constants'
|
|
|
11
11
|
import { routeHmrStatement } from '../route-hmr-statement'
|
|
12
12
|
import { createIdentifier } from './path-ids'
|
|
13
13
|
import { getFrameworkOptions } from './framework-options'
|
|
14
|
+
import type {
|
|
15
|
+
CompileCodeSplitReferenceRouteOptions,
|
|
16
|
+
ReferenceRouteCompilerPlugin,
|
|
17
|
+
} from './plugins'
|
|
14
18
|
import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils'
|
|
15
19
|
import type { CodeSplitGroupings, SplitRouteIdentNodes } from '../constants'
|
|
16
20
|
import type { Config, DeletableNodes } from '../config'
|
|
@@ -642,6 +646,7 @@ export function compileCodeSplitReferenceRoute(
|
|
|
642
646
|
id: string
|
|
643
647
|
addHmr?: boolean
|
|
644
648
|
sharedBindings?: Set<string>
|
|
649
|
+
compilerPlugins?: Array<ReferenceRouteCompilerPlugin>
|
|
645
650
|
},
|
|
646
651
|
): GeneratorResult | null {
|
|
647
652
|
const ast = parseAst(opts)
|
|
@@ -714,6 +719,23 @@ export function compileCodeSplitReferenceRoute(
|
|
|
714
719
|
)
|
|
715
720
|
}
|
|
716
721
|
if (!splittableCreateRouteFns.includes(createRouteFn)) {
|
|
722
|
+
const insertionPath = path.getStatementParent() ?? path
|
|
723
|
+
|
|
724
|
+
opts.compilerPlugins?.forEach((plugin) => {
|
|
725
|
+
const pluginResult = plugin.onUnsplittableRoute?.({
|
|
726
|
+
programPath,
|
|
727
|
+
callExpressionPath: path,
|
|
728
|
+
insertionPath,
|
|
729
|
+
routeOptions,
|
|
730
|
+
createRouteFn,
|
|
731
|
+
opts: opts as CompileCodeSplitReferenceRouteOptions,
|
|
732
|
+
})
|
|
733
|
+
|
|
734
|
+
if (pluginResult?.modified) {
|
|
735
|
+
modified = true
|
|
736
|
+
}
|
|
737
|
+
})
|
|
738
|
+
|
|
717
739
|
// we can't split this route but we still add HMR handling if enabled
|
|
718
740
|
if (opts.addHmr && !hmrAdded) {
|
|
719
741
|
programPath.pushContainer('body', routeHmrStatement)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createReactRefreshRouteComponentsPlugin } from './react-refresh-route-components'
|
|
2
|
+
import type { ReferenceRouteCompilerPlugin } from '../plugins'
|
|
3
|
+
import type { Config } from '../../config'
|
|
4
|
+
|
|
5
|
+
export function getReferenceRouteCompilerPlugins(opts: {
|
|
6
|
+
targetFramework: Config['target']
|
|
7
|
+
addHmr?: boolean
|
|
8
|
+
}): Array<ReferenceRouteCompilerPlugin> | undefined {
|
|
9
|
+
switch (opts.targetFramework) {
|
|
10
|
+
case 'react': {
|
|
11
|
+
if (opts.addHmr) {
|
|
12
|
+
return [createReactRefreshRouteComponentsPlugin()]
|
|
13
|
+
}
|
|
14
|
+
return undefined
|
|
15
|
+
}
|
|
16
|
+
default:
|
|
17
|
+
return undefined
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as t from '@babel/types'
|
|
2
|
+
import { getUniqueProgramIdentifier } from '../../utils'
|
|
3
|
+
import type { ReferenceRouteCompilerPlugin } from '../plugins'
|
|
4
|
+
|
|
5
|
+
const REACT_REFRESH_ROUTE_COMPONENT_IDENTS = new Set([
|
|
6
|
+
'component',
|
|
7
|
+
'pendingComponent',
|
|
8
|
+
'errorComponent',
|
|
9
|
+
'notFoundComponent',
|
|
10
|
+
])
|
|
11
|
+
|
|
12
|
+
export function createReactRefreshRouteComponentsPlugin(): ReferenceRouteCompilerPlugin {
|
|
13
|
+
return {
|
|
14
|
+
name: 'react-refresh-route-components',
|
|
15
|
+
onUnsplittableRoute(ctx) {
|
|
16
|
+
if (!ctx.opts.addHmr) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const hoistedDeclarations: Array<t.VariableDeclaration> = []
|
|
21
|
+
|
|
22
|
+
ctx.routeOptions.properties.forEach((prop) => {
|
|
23
|
+
if (!t.isObjectProperty(prop) || !t.isIdentifier(prop.key)) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!REACT_REFRESH_ROUTE_COMPONENT_IDENTS.has(prop.key.name)) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
!t.isArrowFunctionExpression(prop.value) &&
|
|
33
|
+
!t.isFunctionExpression(prop.value)
|
|
34
|
+
) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const hoistedIdentifier = getUniqueProgramIdentifier(
|
|
39
|
+
ctx.programPath,
|
|
40
|
+
`TSR${prop.key.name[0]!.toUpperCase()}${prop.key.name.slice(1)}`,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
hoistedDeclarations.push(
|
|
44
|
+
t.variableDeclaration('const', [
|
|
45
|
+
t.variableDeclarator(
|
|
46
|
+
hoistedIdentifier,
|
|
47
|
+
t.cloneNode(prop.value, true),
|
|
48
|
+
),
|
|
49
|
+
]),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
prop.value = t.cloneNode(hoistedIdentifier)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (hoistedDeclarations.length === 0) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ctx.insertionPath.insertBefore(hoistedDeclarations)
|
|
60
|
+
return { modified: true }
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type babel from '@babel/core'
|
|
2
|
+
import type * as t from '@babel/types'
|
|
3
|
+
import type { Config, DeletableNodes } from '../config'
|
|
4
|
+
import type { CodeSplitGroupings } from '../constants'
|
|
5
|
+
|
|
6
|
+
export type CompileCodeSplitReferenceRouteOptions = {
|
|
7
|
+
codeSplitGroupings: CodeSplitGroupings
|
|
8
|
+
deleteNodes?: Set<DeletableNodes>
|
|
9
|
+
targetFramework: Config['target']
|
|
10
|
+
filename: string
|
|
11
|
+
id: string
|
|
12
|
+
addHmr?: boolean
|
|
13
|
+
sharedBindings?: Set<string>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type ReferenceRouteCompilerPluginContext = {
|
|
17
|
+
programPath: babel.NodePath<t.Program>
|
|
18
|
+
callExpressionPath: babel.NodePath<t.CallExpression>
|
|
19
|
+
insertionPath: babel.NodePath
|
|
20
|
+
routeOptions: t.ObjectExpression
|
|
21
|
+
createRouteFn: string
|
|
22
|
+
opts: CompileCodeSplitReferenceRouteOptions
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ReferenceRouteCompilerPluginResult = {
|
|
26
|
+
modified?: boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type ReferenceRouteCompilerPlugin = {
|
|
30
|
+
name: string
|
|
31
|
+
onUnsplittableRoute?: (
|
|
32
|
+
ctx: ReferenceRouteCompilerPluginContext,
|
|
33
|
+
) => void | ReferenceRouteCompilerPluginResult
|
|
34
|
+
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
computeSharedBindings,
|
|
14
14
|
detectCodeSplitGroupingsFromRoute,
|
|
15
15
|
} from './code-splitter/compilers'
|
|
16
|
+
import { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'
|
|
16
17
|
import {
|
|
17
18
|
defaultCodeSplitGroupings,
|
|
18
19
|
splitRouteIdentNodes,
|
|
@@ -90,7 +91,6 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
const isProduction = process.env.NODE_ENV === 'production'
|
|
93
|
-
|
|
94
94
|
// Map from normalized route file path → set of shared binding names.
|
|
95
95
|
// Populated by the reference compiler, consumed by virtual and shared compilers.
|
|
96
96
|
const sharedBindingsMap = new Map<string, Set<string>>()
|
|
@@ -156,6 +156,9 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
|
|
|
156
156
|
sharedBindingsMap.delete(id)
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
const addHmr =
|
|
160
|
+
(userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction
|
|
161
|
+
|
|
159
162
|
const compiledReferenceRoute = compileCodeSplitReferenceRoute({
|
|
160
163
|
code,
|
|
161
164
|
codeSplitGroupings: splitGroupings,
|
|
@@ -165,9 +168,12 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
|
|
|
165
168
|
deleteNodes: userConfig.codeSplittingOptions?.deleteNodes
|
|
166
169
|
? new Set(userConfig.codeSplittingOptions.deleteNodes)
|
|
167
170
|
: undefined,
|
|
168
|
-
addHmr
|
|
169
|
-
(userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction,
|
|
171
|
+
addHmr,
|
|
170
172
|
sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,
|
|
173
|
+
compilerPlugins: getReferenceRouteCompilerPlugins({
|
|
174
|
+
targetFramework: userConfig.target,
|
|
175
|
+
addHmr,
|
|
176
|
+
}),
|
|
171
177
|
})
|
|
172
178
|
|
|
173
179
|
if (compiledReferenceRoute === null) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'
|
|
2
|
+
import { compileCodeSplitReferenceRoute } from './code-splitter/compilers'
|
|
3
|
+
import { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'
|
|
2
4
|
import { routeHmrStatement } from './route-hmr-statement'
|
|
3
5
|
import { debug, normalizePath } from './utils'
|
|
4
6
|
import { getConfig } from './config'
|
|
@@ -41,6 +43,30 @@ export const unpluginRouterHmrFactory: UnpluginFactory<
|
|
|
41
43
|
|
|
42
44
|
if (debug) console.info('Adding HMR handling to route ', normalizedId)
|
|
43
45
|
|
|
46
|
+
if (userConfig.target === 'react') {
|
|
47
|
+
const compiled = compileCodeSplitReferenceRoute({
|
|
48
|
+
code,
|
|
49
|
+
filename: normalizedId,
|
|
50
|
+
id: normalizedId,
|
|
51
|
+
addHmr: true,
|
|
52
|
+
codeSplitGroupings: [],
|
|
53
|
+
targetFramework: 'react',
|
|
54
|
+
compilerPlugins: getReferenceRouteCompilerPlugins({
|
|
55
|
+
targetFramework: 'react',
|
|
56
|
+
addHmr: true,
|
|
57
|
+
}),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
if (compiled) {
|
|
61
|
+
if (debug) {
|
|
62
|
+
logDiff(code, compiled.code)
|
|
63
|
+
console.log('Output:\n', compiled.code + '\n\n')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return compiled
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
44
70
|
const ast = parseAst({ code })
|
|
45
71
|
ast.program.body.push(routeHmrStatement)
|
|
46
72
|
const result = generateFromAst(ast, {
|
package/src/core/utils.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as t from '@babel/types'
|
|
2
|
+
import type babel from '@babel/core'
|
|
3
|
+
|
|
1
4
|
export const debug =
|
|
2
5
|
process.env.TSR_VITE_DEBUG &&
|
|
3
6
|
['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG)
|
|
@@ -12,3 +15,21 @@ export const debug =
|
|
|
12
15
|
export function normalizePath(path: string): string {
|
|
13
16
|
return path.replace(/\\/g, '/')
|
|
14
17
|
}
|
|
18
|
+
|
|
19
|
+
export function getUniqueProgramIdentifier(
|
|
20
|
+
programPath: babel.NodePath<t.Program>,
|
|
21
|
+
baseName: string,
|
|
22
|
+
): t.Identifier {
|
|
23
|
+
let name = baseName
|
|
24
|
+
let suffix = 2
|
|
25
|
+
|
|
26
|
+
while (
|
|
27
|
+
programPath.scope.hasBinding(name) ||
|
|
28
|
+
programPath.scope.hasGlobal(name)
|
|
29
|
+
) {
|
|
30
|
+
name = `${baseName}${suffix}`
|
|
31
|
+
suffix++
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return t.identifier(name)
|
|
35
|
+
}
|