Условная компиляция

MDX сочетает возможности Markdown и JSX, позволяя создавать динамический контент с компонентами React. Одной из продвинутых возможностей является условная компиляция — способ влиять на итоговый рендеринг контента в зависимости от условий во время сборки или выполнения.

Основы условной компиляции

В MDX условная компиляция достигается использованием JavaScript-выражений внутри JSX-блоков. Поскольку MDX транспилируется в React-компоненты, можно применять стандартные конструкции Jav * aScript: условные операторы, тернарные выражения, логические операции.

Простейший пример использования тернарного оператора в MDX:

import { Feature } from './components/Feature'

{process.env.FEATURE_ENABLED ? <Feature /> : null}

Здесь компонент Feature будет включён только если переменная окружения FEATURE_ENABLED равна true. Важно понимать, что этот код выполняется на этапе рендера React, а не при сборке Markdown.

Логические операторы

Часто используется короткая запись через логический оператор &&:

{user.isAdmin && <AdminPanel />}

AdminPanel рендерится только если user.isAdmin истинно. Это позволяет создавать MDX-документы, которые адаптируются под разные состояния приложения.

Условные блоки с несколькими ветвями

Для более сложных условий применяются стандартные JavaScript-конструкции:

{
  status === 'loading' ? (
    <Spinner />
  ) : status === 'error' ? (
    <ErrorMessage />
  ) : (
    <Content data={data} />
  )
}

Такой подход позволяет полностью контролировать, какой JSX будет вставлен в документ на основе текущего состояния.

Использование функций для условной компиляции

Можно выносить условия в отдельные функции, чтобы улучшить читаемость и повторное использование кода:

import { renderContent } from './utils'

{renderContent(user, data)}

Функция renderContent возвращает JSX в зависимости от переданных параметров. Такой метод особенно полезен для крупных MDX-документов с множеством условий.

Интеграция с переменными окружения

MDX позволяет использовать переменные окружения через process.env, что делает возможным условную компиляцию контента на этапе сборки:

{process.env.NODE_ENV === 'development' && (
  <DebugPanel />
)}

В продакшн-сборке этот блок не рендерится, что уменьшает итоговый размер бандла.

Состояние и контекст

MDX-документы могут использовать React-хуки и контекст для динамической условной компиляции:

import { useTheme } from './ThemeContext'

export const ThemeDependent = () => {
  const theme = useTheme()
  return theme === 'dark' ? <DarkComponent /> : <LightComponent />
}

Такой подход позволяет строить интерактивные MDX-документы, которые меняют содержимое без перезагрузки страницы.

Динамический импорт компонентов

Для оптимизации условной компиляции можно использовать динамический импорт:

import dynamic from 'next/dynamic'

const HeavyComponent = dynamic(() => import('./HeavyComponent'), { ssr: false })

{isVisible && <HeavyComponent />}

Компонент HeavyComponent загружается только если isVisible истинно, что снижает нагрузку на начальный рендер и ускоряет загрузку страницы.

Ограничения и особенности

  • Сборка MDX: Условная компиляция через переменные окружения работает только на этапе сборки, тогда как выражения, основанные на пропсах или состоянии, выполняются на клиенте.
  • Серверный рендеринг: Для SSR необходимо учитывать, что выражения зависят от контекста сервера и клиента. Некоторые условные блоки могут вести себя по-разному.
  • Статический экспорт: Тернарные выражения на основе runtime-переменных не могут влиять на заранее сгенерированный HTML.

Рекомендации по стилю

  1. Выносить сложные условия в функции для улучшения читаемости MDX-документа.
  2. Использовать логический оператор && для простых условий, чтобы код оставался компактным.
  3. Минимизировать использование process.env для runtime условий, чтобы избежать непредсказуемого поведения при клиентской навигации.
  4. Комбинировать с динамическим импортом для тяжелых компонентов, загружаемых по необходимости.

Пример комплексного MDX-документа с условной компиляцией

import { Banner } from './components/Banner'
import { Feature } from './components/Feature'
import dynamic from 'next/dynamic'

const ExperimentalFeature = dynamic(() => import('./ExperimentalFeature'), { ssr: false })

{process.env.SHOW_BANNER && <Banner />}
{user.isLoggedIn ? <Feature /> : <p>Войдите, чтобы увидеть функционал</p>}
{isExperimental && <ExperimentalFeature />}

В этом примере MDX-документ комбинирует условия на основе переменных окружения, состояния пользователя и runtime-флагов. Такой подход позволяет строить гибкие и масштабируемые учебные материалы, документацию и интерактивные страницы.