TanStack Router provides universal bundler plugins for Webpack, ESBuild, and Rspack through a single package. These plugins enable automatic route generation, code splitting, and hot module replacement across different bundlers.
Installation
Install the universal plugin package:
npm install -D @tanstack/router-plugin
# or
pnpm add -D @tanstack/router-plugin
# or
yarn add -D @tanstack/router-plugin
This single package provides plugins for all supported bundlers.
Webpack Plugin
Basic Setup
Add the plugin to your webpack.config.js:
const { TanStackRouterWebpack } = require('@tanstack/router-plugin/webpack')
module.exports = {
plugins: [
TanStackRouterWebpack(),
],
}
With TypeScript:
import { TanStackRouterWebpack } from '@tanstack/router-plugin/webpack'
import type { Configuration } from 'webpack'
const config: Configuration = {
plugins: [
TanStackRouterWebpack(),
],
}
export default config
Configuration
Pass configuration options to the plugin:
import { TanStackRouterWebpack } from '@tanstack/router-plugin/webpack'
const config: Configuration = {
plugins: [
TanStackRouterWebpack({
target: 'react',
routesDirectory: './src/routes',
generatedRouteTree: './src/routeTree.gen.ts',
autoCodeSplitting: true,
}),
],
}
export default config
Specialized Webpack Plugins
Use separate plugins for generation and code splitting:
import {
TanStackRouterGeneratorWebpack,
TanStackRouterCodeSplitterWebpack,
} from '@tanstack/router-plugin/webpack'
const config: Configuration = {
plugins: [
TanStackRouterGeneratorWebpack({
routesDirectory: './src/routes',
}),
TanStackRouterCodeSplitterWebpack({
autoCodeSplitting: true,
}),
],
}
export default config
With React
const { TanStackRouterWebpack } = require('@tanstack/router-plugin/webpack')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
module.exports = {
plugins: [
new ReactRefreshWebpackPlugin(),
TanStackRouterWebpack({ target: 'react' }),
],
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-react', { runtime: 'automatic' }],
'@babel/preset-typescript',
],
},
},
},
],
},
}
ESBuild Plugin
Basic Setup
Add the plugin to your ESBuild configuration:
const { build } = require('esbuild')
const { TanStackRouterEsbuild } = require('@tanstack/router-plugin/esbuild')
build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [TanStackRouterEsbuild()],
})
With TypeScript:
import { build } from 'esbuild'
import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild'
await build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [TanStackRouterEsbuild()],
})
Configuration
import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild'
await build({
plugins: [
TanStackRouterEsbuild({
target: 'react',
routesDirectory: './src/routes',
generatedRouteTree: './src/routeTree.gen.ts',
autoCodeSplitting: true,
}),
],
})
Specialized ESBuild Plugins
import {
TanStackRouterGeneratorEsbuild,
TanStackRouterCodeSplitterEsbuild,
} from '@tanstack/router-plugin/esbuild'
await build({
plugins: [
TanStackRouterGeneratorEsbuild(),
TanStackRouterCodeSplitterEsbuild(),
],
})
With React and JSX
import { build } from 'esbuild'
import { TanStackRouterEsbuild } from '@tanstack/router-plugin/esbuild'
await build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [TanStackRouterEsbuild({ target: 'react' })],
loader: {
'.tsx': 'tsx',
'.ts': 'ts',
},
jsx: 'automatic',
})
Rspack Plugin
Basic Setup
Add the plugin to your Rspack configuration:
const { TanStackRouterRspack } = require('@tanstack/router-plugin/rspack')
module.exports = {
plugins: [
TanStackRouterRspack(),
],
}
With TypeScript and Rsbuild:
import { defineConfig } from '@rsbuild/core'
import { pluginReact } from '@rsbuild/plugin-react'
import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack'
export default defineConfig({
plugins: [pluginReact()],
tools: {
rspack: {
plugins: [TanStackRouterRspack()],
},
},
})
Configuration
import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack'
export default defineConfig({
tools: {
rspack: {
plugins: [
TanStackRouterRspack({
target: 'react',
routesDirectory: './src/routes',
generatedRouteTree: './src/routeTree.gen.ts',
autoCodeSplitting: true,
}),
],
},
},
})
Specialized Rspack Plugins
import {
TanStackRouterGeneratorRspack,
TanStackRouterCodeSplitterRspack,
} from '@tanstack/router-plugin/rspack'
export default defineConfig({
tools: {
rspack: {
plugins: [
TanStackRouterGeneratorRspack(),
TanStackRouterCodeSplitterRspack(),
],
},
},
})
Configuration Options
All bundler plugins support the same configuration options:
target
'react' | 'solid' | 'vue'
default:"react"
The framework you’re using with TanStack Router
routesDirectory
string
default:"./src/routes"
The directory containing your route files
generatedRouteTree
string
default:"./src/routeTree.gen.ts"
Where to output the generated route tree file
Optional prefix for route files
Files starting with this prefix will be ignored
quoteStyle
'single' | 'double'
default:"single"
Quote style for generated code
Whether to include semicolons in generated code
Automatically enable code splitting for routes
Disable TypeScript type generation
Disable plugin logging output
Advanced code splitting configuration:{
defaultBehavior: [
['component'],
['pendingComponent'],
['errorComponent'],
['notFoundComponent']
],
splitBehavior: ({ routeId }) => {
// Custom logic per route
return undefined // use default
},
deleteNodes: ['loader'],
addHmr: true
}
Code Splitting
All plugins support automatic code splitting:
// Any bundler plugin
{
autoCodeSplitting: true,
codeSplittingOptions: {
defaultBehavior: [
['component'],
['pendingComponent'],
['errorComponent', 'notFoundComponent'],
],
splitBehavior: ({ routeId }) => {
// Don't split critical routes
if (routeId === '/' || routeId === '/login') {
return undefined
}
// Custom split for admin
if (routeId.startsWith('/admin')) {
return [['component', 'pendingComponent']]
}
return undefined // use default
},
},
}
TypeScript Support
All plugins generate TypeScript types automatically. Ensure your tsconfig.json includes the generated files:
{
"compilerOptions": {
"strict": true,
"moduleResolution": "bundler"
},
"include": [
"src",
"src/routeTree.gen.ts"
]
}
Validation with Zod
The plugins use Zod for configuration validation:
import { configSchema } from '@tanstack/router-plugin'
// Validate your config
const config = configSchema.parse({
target: 'react',
routesDirectory: './src/routes',
})
Using Unplugin Directly
The plugins are built with unplugin, which provides a unified plugin interface. You can use the raw unplugin factories:
import { createWebpackPlugin } from 'unplugin'
import { unpluginRouterGeneratorFactory } from '@tanstack/router-plugin'
const customPlugin = createWebpackPlugin(unpluginRouterGeneratorFactory)
Comparison with CLI
Bundler plugins vs CLI (tsr watch):
| Feature | Bundler Plugin | CLI |
|---|
| Route generation | ✅ | ✅ |
| Watch mode | ✅ (automatic) | ✅ (manual) |
| HMR | ✅ | ❌ |
| Code splitting | ✅ | ❌ |
| Build integration | ✅ (native) | ❌ (separate process) |
| Setup complexity | Medium | Low |
Recommendation: Use bundler plugins for better integration and features. Use CLI only if your bundler is not supported.
Comparison with Vite Plugin
The Vite plugin is the recommended choice for Vite projects:
// ✅ Recommended for Vite
import { tanstackRouter } from '@tanstack/router-plugin/vite'
// ⚠️ Also works, but use Vite-specific export
import { TanStackRouterWebpack } from '@tanstack/router-plugin/webpack'
See Vite Plugin for Vite-specific documentation.
Troubleshooting
Plugin not working
- Verify the plugin is properly imported for your bundler
- Check that configuration options are valid
- Ensure route files exist in the configured directory
- Check bundler logs for errors
Routes not generating
- Verify
routesDirectory path is correct
- Check file naming conventions match expected patterns
- Ensure bundler is running in watch/dev mode
- Check for configuration validation errors
Type errors
- Include generated route tree in
tsconfig.json
- Restart your TypeScript server
- Verify
disableTypes is not set to true
- Check that route files have valid TypeScript
Code splitting not working
- Set
autoCodeSplitting: true
- Verify
codeSplittingOptions configuration is valid
- Check that route components are properly exported
- Ensure bundler supports dynamic imports
Webpack-specific issues
- Check React Refresh plugin order
- Verify babel configuration includes JSX transform
- Ensure source maps are enabled for debugging
ESBuild-specific issues
- Configure JSX transform:
jsx: 'automatic'
- Set correct loaders for
.tsx and .ts files
- ESBuild plugin support is limited - consider Vite
Rspack-specific issues
- Use within
tools.rspack.plugins array
- Ensure Rsbuild React plugin is configured
- Check Rspack version compatibility (>= 1.0.2)