Настройка с Webpack

Установка зависимостей

Для начала работы с TanStack Router в проекте на Webpack необходимо установить саму библиотеку и ее типы (если используется TypeScript):

npm install @tanstack/router
npm install -D @types/react

В случае использования TypeScript важно убедиться, что tsconfig.json корректно настроен для поддержки JSX и модулей ESNext:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "ESNext",
    "moduleResolution": "node",
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Настройка Webpack

Основная задача — убедиться, что Webpack корректно обрабатывает современные ES-модули и JSX. Пример минимальной конфигурации webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    clean: true,
  },
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
  module: {
    rules: [
      {
        test: /\.[jt]sx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react',
              '@babel/preset-typescript'
            ]
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
  devtool: 'source-map',
  devServer: {
    static: path.join(__dirname, 'dist'),
    port: 3000,
    hot: true,
    historyApiFallback: true
  }
};

Ключевые моменты конфигурации:

  • resolve.extensions — позволяет Webpack автоматически определять расширения файлов, что упрощает импорт компонентов.
  • babel-loader с пресетами @babel/preset-react и @babel/preset-typescript обеспечивает корректную транспиляцию JSX и TypeScript.
  • devServer.historyApiFallback: true критично для SPA с TanStack Router, чтобы все маршруты обрабатывались на клиенте, а не приводили к 404 при обновлении страницы.

Интеграция TanStack Router

Создается основной маршрутизатор с определением корневого маршрута:

import { createRouter, createRouteConfig } from '@tanstack/router';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';

const rootRoute = createRouteConfig()
  .route('/', {
    component: App,
    children: [
      {
        path: '/',
        component: HomePage,
      },
      {
        path: '/about',
        component: AboutPage,
      },
    ],
  });

const router = createRouter({
  routeConfig: rootRoute,
});

const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
  <React.StrictMode>
    {router.render()}
  </React.StrictMode>
);

Особенности:

  • createRouteConfig позволяет задавать вложенные маршруты с компонентами.
  • router.render() интегрирует маршрутизатор с React, автоматически обрабатывая переходы между страницами.
  • Структура маршрутов поддерживает вложенность и динамические сегменты, что удобно для сложных приложений.

Настройка для HMR (Hot Module Replacement)

Для ускоренной разработки важно включить HMR, чтобы изменения в компонентах маршрутов автоматически применялись без перезагрузки страницы. В webpack.config.js уже включен параметр hot: true, но для корректной работы с TanStack Router требуется убедиться, что корневой компонент не теряет состояния при обновлении:

if (module.hot) {
  module.hot.accept('./App', () => {
    const NextApp = require('./App').default;
    root.render(
      <React.StrictMode>
        {router.render()}
      </React.StrictMode>
    );
  });
}

Оптимизация сборки

Для production рекомендуется использовать код-сплиттинг для маршрутов:

import React, { lazy, Suspense } from 'react';

const HomePage = lazy(() => import('./pages/HomePage'));
const AboutPage = lazy(() => import('./pages/AboutPage'));

const rootRoute = createRouteConfig()
  .route('/', {
    component: App,
    children: [
      { path: '/', component: () => <Suspense fallback={<div>Loading...</div>}><HomePage /></Suspense> },
      { path: '/about', component: () => <Suspense fallback={<div>Loading...</div>}><AboutPage /></Suspense> },
    ],
  });

Преимущества:

  • Загружаются только нужные страницы, уменьшая размер начального бандла.
  • Поддержка Suspense позволяет отображать индикатор загрузки до подгрузки компонентов.

Настройка alias и пути

Для упрощения импортов компонентов и маршрутов в Webpack можно использовать alias:

resolve: {
  extensions: ['.js', '.jsx', '.ts', '.tsx'],
  alias: {
    '@pages': path.resolve(__dirname, 'src/pages'),
    '@components': path.resolve(__dirname, 'src/components')
  }
}

Это позволяет писать:

import HomePage from '@pages/HomePage';
import Header from '@components/Header';

вместо длинных относительных путей. TanStack Router отлично работает с такими alias, так как маршруты импортируются как обычные модули ES.

Поддержка TypeScript и типов маршрутов

TanStack Router имеет встроенную поддержку типов, что позволяет безопасно работать с параметрами маршрутов:

const userRoute = rootRoute.addRoute({
  path: '/user/:id',
  component: UserPage,
});

type UserParams = typeof userRoute['__types']['params'];

function navigateToUser(id: UserParams['id']) {
  router.navigate(`/user/${id}`);
}

Преимущества типизации:

  • Автодополнение в редакторе.
  • Исключение ошибок при передаче параметров маршрута.
  • Безопасная навигация внутри приложения.