Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/router/framework/react/guide/automatic-code-splitting.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,38 @@ This means that it creates three separate lazy-loaded chunks for each route. Res
- One for the error component
- And one for the not-found component.

### Rules of Splitting

For automatic code splitting to work, there are some rules in-place to make sure that this process can reliably and predictably happen.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix minor grammar: “in-place” → “in place”

Improves readability in the new rules section.

Apply:

-For automatic code splitting to work, there are some rules in-place to make sure that this process can reliably and predictably happen.
+For automatic code splitting to work, there are some rules in place to make sure that this process can reliably and predictably happen.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
For automatic code splitting to work, there are some rules in-place to make sure that this process can reliably and predictably happen.
For automatic code splitting to work, there are some rules in place to make sure that this process can reliably and predictably happen.
🤖 Prompt for AI Agents
In docs/router/framework/react/guide/automatic-code-splitting.md around line 79,
the phrase "in-place" is grammatically incorrect; change "in-place" to "in
place" so the sentence reads "For automatic code splitting to work, there are
some rules in place to make sure that this process can reliably and predictably
happen." Ensure only that hyphen is removed and spacing is correct.


#### Do not export route properties

Route properties like `component`, `loader`, etc., should not be exported from the route file. Exporting these properties results in them being bundled into the main application bundle, which means that they will not be code-split.

```tsx
import { createRoute } from '@tanstack/react-router'

export const Route = createRoute('/posts')({
// ...
notFoundComponent: PostsNotFoundComponent,
})

// ❌ Do NOT do this!
// Exporting the notFoundComponent will prevent it from being code-split
// and will be included in the main bundle.
export function PostsNotFoundComponent() {
// ❌
// ...
}

function PostsNotFoundComponent() {
// ✅
// ...
}
```

**That's it!** There are no other restrictions. You can use any other JavaScript or TypeScript features in your route files as you normally would. If you run into any issues, please [open an issue](https://github.com/tanstack/router/issues) on GitHub.

## Granular control

For most applications, the default behavior of using `autoCodeSplitting: true` is sufficient. However, TanStack Router provides several options to customize how your routes are split into chunks, allowing you to optimize for specific use cases or performance needs.
Expand Down
68 changes: 45 additions & 23 deletions packages/router-plugin/src/core/code-splitter/compilers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ function addSplitSearchParamToFilename(
const params = new URLSearchParams()
params.append(tsrSplit, createIdentifier(grouping))

return `${bareFilename}?${params.toString()}`
const result = `${bareFilename}?${params.toString()}`
return result
}

function removeSplitSearchParamFromFilename(filename: string) {
Expand Down Expand Up @@ -116,6 +117,8 @@ export function compileCodeSplitReferenceRoute(

const refIdents = findReferencedIdentifiers(ast)

const knownExportedIdents = new Set<string>()

function findIndexForSplitNode(str: string) {
return opts.codeSplitGroupings.findIndex((group) =>
group.includes(str as any),
Expand Down Expand Up @@ -251,6 +254,9 @@ export function compileCodeSplitReferenceRoute(
// since they are already being imported
// and need to be retained in the compiled file
const isExported = hasExport(ast, value)
if (isExported) {
knownExportedIdents.add(value.name)
}
shouldSplit = !isExported

if (shouldSplit) {
Expand Down Expand Up @@ -320,6 +326,9 @@ export function compileCodeSplitReferenceRoute(
// since they are already being imported
// and need to be retained in the compiled file
const isExported = hasExport(ast, value)
if (isExported) {
knownExportedIdents.add(value.name)
}
shouldSplit = !isExported

if (shouldSplit) {
Expand Down Expand Up @@ -410,6 +419,26 @@ export function compileCodeSplitReferenceRoute(

deadCodeElimination(ast, refIdents)

// if there are exported identifiers, then we need to add a warning
// to the file to let the user know that the exported identifiers
// will not in the split file but in the original file, therefore
// increasing the bundle size
if (knownExportedIdents.size > 0) {
const warningMessage = createNotExportableMessage(
opts.filename,
knownExportedIdents,
)
console.warn(warningMessage)

// append this warning to the file using a template
if (process.env.NODE_ENV !== 'production') {
const warningTemplate = template.statement(
`console.warn(${JSON.stringify(warningMessage)})`,
)()
ast.program.body.unshift(warningTemplate)
}
}

return generateFromAst(ast, {
sourceMaps: true,
sourceFileName: opts.filename,
Expand Down Expand Up @@ -712,28 +741,6 @@ export function compileCodeSplitVirtualRoute(

deadCodeElimination(ast, refIdents)

// if there are exported identifiers, then we need to add a warning
// to the file to let the user know that the exported identifiers
// will not in the split file but in the original file, therefore
// increasing the bundle size
if (knownExportedIdents.size > 0) {
const list = Array.from(knownExportedIdents).reduce((str, ident) => {
str += `\n- ${ident}`
return str
}, '')

const warningMessage = `These exports from "${opts.filename}" are not being code-split and will increase your bundle size: ${list}\nThese should either have their export statements removed or be imported from another file that is not a route.`
console.warn(warningMessage)

// append this warning to the file using a template
if (process.env.NODE_ENV !== 'production') {
const warningTemplate = template.statement(
`console.warn(${JSON.stringify(warningMessage)})`,
)()
ast.program.body.unshift(warningTemplate)
}
}

return generateFromAst(ast, {
sourceMaps: true,
sourceFileName: opts.filename,
Expand Down Expand Up @@ -837,6 +844,21 @@ export function detectCodeSplitGroupingsFromRoute(opts: ParseAstOptions): {
return { groupings: codeSplitGroupings }
}

function createNotExportableMessage(
filename: string,
idents: Set<string>,
): string {
const list = Array.from(idents).map((d) => `- ${d}`)

const message = [
`[tanstack-router] These exports from "${filename}" will not be code-split and will increase your bundle size:`,
...list,
'For the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.',
].join('\n')

return message
}

function getImportSpecifierAndPathFromLocalName(
programPath: babel.NodePath<t.Program>,
name: string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"export-default-component-and-normal-notFound.tsx\" will not be code-split and will increase your bundle size:\n- Home\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
const $$splitNotFoundComponentImporter = () => import('export-default-component-and-normal-notFound.tsx?tsr-split=notFoundComponent');
import { lazyRouteComponent } from '@tanstack/react-router';
import React, { useState } from 'react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
console.warn("These exports from \"export-default-component-and-normal-notFound.tsx?component\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component-and-normal-notFound.tsx";
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
console.warn("These exports from \"export-default-component-and-normal-notFound.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component-and-normal-notFound.tsx";
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"export-default-component-and-normal-notFound.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component-and-normal-notFound.tsx";
function NotFoundComponent() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"export-default-component.tsx\" will not be code-split and will increase your bundle size:\n- Home\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
import React, { useState } from 'react';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/home')({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
console.warn("These exports from \"export-default-component.tsx?component\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component.tsx";
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
console.warn("These exports from \"export-default-component.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component.tsx";
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
console.warn("These exports from \"export-default-component.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component.tsx";
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"retain-export-component.tsx\" will not be code-split and will increase your bundle size:\n- Layout\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
import * as React from 'react';
import { createFileRoute, Outlet } from '@tanstack/react-router';
import { importedComponent as ImportedComponent, importedLoader } from '../../shared/imported';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-export-component.tsx?component\" are not being code-split and will increase your bundle size: \n- Layout\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-export-component.tsx";
import { SIDEBAR_WIDTH } from "retain-export-component.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-export-component.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- Layout\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-export-component.tsx";
import { SIDEBAR_WIDTH } from "retain-export-component.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-export-component.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- Layout\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-export-component.tsx";
import { SIDEBAR_WIDTH } from "retain-export-component.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"retain-exports-const.tsx\" will not be code-split and will increase your bundle size:\n- Layout\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
import * as React from 'react';
import { createFileRoute, Outlet } from '@tanstack/react-router';
import { importedComponent as ImportedComponent, importedLoader } from '../../shared/imported';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-const.tsx?component\" are not being code-split and will increase your bundle size: \n- Layout\n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-const.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-const.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-const.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- Layout\n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-const.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-const.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-const.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- Layout\n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-const.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-const.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"retain-exports-function.tsx\" will not be code-split and will increase your bundle size:\n- Layout\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
import * as React from 'react';
import { createFileRoute, Outlet } from '@tanstack/react-router';
import { importedComponent as ImportedComponent, importedLoader } from '../../shared/imported';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-function.tsx?component\" are not being code-split and will increase your bundle size: \n- Layout\n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-function.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-function.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-function.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- Layout\n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-function.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-function.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-function.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- Layout\n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-function.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-function.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-loader.tsx?component\" are not being code-split and will increase your bundle size: \n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Outlet } from '@tanstack/react-router';
import { importedComponent as ImportedComponent } from '../../shared/imported';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-loader.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-loader.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-loader.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"retain-exports-loader.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- loaderFn\nThese should either have their export statements removed or be imported from another file that is not a route.");
import * as React from 'react';
import { Route } from "retain-exports-loader.tsx";
import { SIDEBAR_WIDTH } from "retain-exports-loader.tsx";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"useStateDestructure.tsx\" will not be code-split and will increase your bundle size:\n- VersionIndex\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
import * as React from 'react';
import { CgCornerUpLeft, CgSpinner } from 'react-icons/cg';
import { FaBolt, FaBook, FaCheckCircle, FaCogs, FaDiscord, FaGithub, FaTshirt, FaTwitter } from 'react-icons/fa';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"useStateDestructure.tsx?component\" are not being code-split and will increase your bundle size: \n- VersionIndex\nThese should either have their export statements removed or be imported from another file that is not a route.");
import { FaBolt, FaBook, FaCheckCircle, FaCogs } from 'react-icons/fa';
import { VscPreview, VscWand } from 'react-icons/vsc';
import { Route } from "useStateDestructure.tsx";
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"useStateDestructure.tsx?errorComponent\" are not being code-split and will increase your bundle size: \n- VersionIndex\nThese should either have their export statements removed or be imported from another file that is not a route.");
import { FaBolt, FaBook, FaCheckCircle, FaCogs } from 'react-icons/fa';
import { VscPreview, VscWand } from 'react-icons/vsc';
import { Route } from "useStateDestructure.tsx";
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"useStateDestructure.tsx?notFoundComponent\" are not being code-split and will increase your bundle size: \n- VersionIndex\nThese should either have their export statements removed or be imported from another file that is not a route.");
import { FaBolt, FaBook, FaCheckCircle, FaCogs } from 'react-icons/fa';
import { VscPreview, VscWand } from 'react-icons/vsc';
import { Route } from "useStateDestructure.tsx";
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.warn("[tanstack-router] These exports from \"export-default-component-and-normal-notFound.tsx\" will not be code-split and will increase your bundle size:\n- Home\nFor the best optimization, these items should either have their export statements removed, or be imported from another location that is not a route file.");
const $$splitNotFoundComponentImporter = () => import('export-default-component-and-normal-notFound.tsx?tsr-split=component---errorComponent---notFoundComponent---pendingComponent');
import { lazyRouteComponent } from '@tanstack/react-router';
import React, { useState } from 'react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
console.warn("These exports from \"export-default-component-and-normal-notFound.tsx?component---errorComponent---notFoundComponent---pendingComponent\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component-and-normal-notFound.tsx";
function NotFoundComponent() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
console.warn("These exports from \"export-default-component-and-normal-notFound.tsx?loader\" are not being code-split and will increase your bundle size: \n- Home\nThese should either have their export statements removed or be imported from another file that is not a route.");
import React from 'react';
import { Route } from "export-default-component-and-normal-notFound.tsx";
Loading
Loading