Source maps

Source Maps — это механизм, который позволяет сопоставить скомпилированный код с исходным исходным кодом, что значительно облегчает отладку и анализ. В случае с MDX, где используется комбинация Markdown и JSX, source maps играют критически важную роль, так как напрямую работают с результатом трансформации MDX в чистый JavaScript.

Назначение source maps

Source maps нужны для того, чтобы инструменты разработчика (например, браузерные DevTools) могли показывать оригинальные строки и файлы, из которых был сгенерирован код. Это позволяет:

  • Отслеживать ошибки в исходных MDX-файлах, а не в итоговом JS.
  • Делать корректные breakpoint’ы и навигацию по коду в редакторах и IDE.
  • Поддерживать совместимость с инструментами сборки и линтерами.

Формат source maps

Source maps представляют собой JSON-объект, содержащий следующие ключевые поля:

  • version — версия спецификации source map, обычно 3.
  • file — имя результирующего JS-файла.
  • sources — массив файлов исходного кода.
  • sourcesContent — опционально, содержимое исходных файлов для встроенного просмотра.
  • mappings — строка, кодирующая позиции исходного кода и соответствующих мест в скомпилированном коде.
  • names — массив идентификаторов переменных и функций для улучшения читаемости.

Генерация source maps при трансформации MDX

MDX-компиляция происходит через пакет @mdx-js/mdx, который трансформирует MDX в JSX, а затем Babel или другой транспайлер превращает JSX в чистый JavaScript. В процессе генерации source maps можно включать следующие опции:

import { compile } from '@mdx-js/mdx';

const mdxCode = `
# Заголовок

<MyComponent />
`;

const result = await compile(mdxCode, {
  sourceMap: true,
  jsx: true
});

Ключевые моменты:

  • sourceMap: true активирует генерацию сопоставления.
  • jsx: true указывает, что результат должен содержать JSX, что влияет на корректность source map.
  • Полученный объект result содержит поле map, которое можно передать транспайлеру или сборщику.

Использование source maps в сборщиках

MDX часто интегрируется с Webpack, Vite или Rollup. Для корректной работы source maps необходимо:

  • Включить devtool (Webpack) или соответствующий параметр Vite (build.sourcemap).
  • Передавать sourceMap из MDX-трансформации в loader/плагин сборщика.
  • Обеспечить поддержку inline или external source maps в зависимости от целей: inline для локальной разработки, external для production.

Пример настройки Webpack с @mdx-js/loader:

module.exports = {
  module: {
    rules: [
      {
        test: /\.mdx$/,
        use: [
          {
            loader: 'babel-loader',
            options: { sourceMaps: true }
          },
          {
            loader: '@mdx-js/loader',
            options: { sourceMap: true }
          }
        ]
      }
    ]
  },
  devtool: 'source-map'
};

Проблемы и особенности

  1. Сложные цепочки транспиляции: Если MDX-компоненты проходят через несколько плагинов Babel, source maps могут терять точность. Важно проверять корректность маппинга после каждого шага.
  2. Inline-компоненты: При использовании MDXProvider и встроенных JSX-компонентов source map корректно отображает только исходные MDX-файлы, а не JSX-компоненты, импортированные из других модулей.
  3. Большие MDX-файлы: Встроенные source maps увеличивают размер bundle. В production рекомендуется использовать external source maps.

Отладка с source maps

DevTools Chrome или Firefox позволяют включать отображение оригинального кода при подключенных source maps. Основные практики:

  • Использовать панель Sources для просмотра MDX-файлов.
  • Ставить breakpoint в исходном MDX, а не в скомпилированном JS.
  • Проверять консольные ошибки — они будут ссылаться на исходный MDX.

Интеграция с TypeScript

При работе с .mdx в TypeScript важно использовать @types/mdx или типовые декларации для корректного сопоставления типов, что позволяет source maps показывать корректные TS-позиции при использовании TSX.

import { FC } from 'react';
import { MDXContent } from './example.mdx';

const Page: FC = () => <MDXContent />;

В этом случае, ошибки в JSX внутри MDX будут ссылаться на строку в example.mdx, благодаря корректным source maps.

Рекомендации по оптимизации

  • Использовать inline source maps только в development, для ускорения сборки в production лучше external maps.
  • Следить за совместимостью версий Babel и @mdx-js/mdx, чтобы mappings не терялись.
  • Проверять, что sourcesContent не пуст, иначе отладка будет показывать пустые файлы.

Source maps являются связующим звеном между MDX и конечным JS, позволяя безопасно и эффективно отлаживать сложные MDX-проекты, включая работу с компонентами React и сборщиками модулей.